diff --git a/xtrn/tw2/filename.js b/xtrn/tw2/filename.js
new file mode 100644
index 0000000000000000000000000000000000000000..21686153bcceb3f57cb860fb043cbb34e8e9ed14
--- /dev/null
+++ b/xtrn/tw2/filename.js
@@ -0,0 +1,6 @@
+function fname(name)
+{
+	if(name.search(/^(?:[A-Z]:)?[\/\\]/)!=-1)
+		return(name);
+	return("../xtrn/tw2/"+name);
+}
diff --git a/xtrn/tw2/gamesettings.js b/xtrn/tw2/gamesettings.js
new file mode 100644
index 0000000000000000000000000000000000000000..8329afbfb0258c6a8acc170222fe78f04c5f49dd
--- /dev/null
+++ b/xtrn/tw2/gamesettings.js
@@ -0,0 +1,130 @@
+load("sbbsdefs.js");				// K_*
+load("uifcdefs.js");				// WIN_*
+load("../xtrn/tw2/filename.js");
+
+var GameSettingProperties=[
+			 {
+				 prop:"EditorPassword"
+				,name:"Editor Password"
+				,type:"String"
+				,def:""
+			}
+			,{
+				 prop:"Start"
+				,name:"Starting Date"
+				,type:"Date"
+				,def:system.datestr()
+			}
+			,{
+				 prop:"StartingFighters"
+				,name:"Starting Fighters"
+				,type:"Integer"
+				,def:20
+			}
+			,{
+				 prop:"StartingCredits"
+				,name:"Starting Credits"
+				,type:"Integer"
+				,def:200
+			}
+			,{
+				 prop:"StartingHolds"
+				,name:"Starting Holds"
+				,type:"Integer"
+				,def:20
+			}
+			,{
+				 prop:"DaysInactivity"
+				,name:"Days of inactivity before deletion"
+				,type:"Integer"
+				,def:21
+			}
+			,{
+				 prop:"MaintLastRan"
+				,name:"Maintenance Last Ran"
+				,type:"Date"
+				,def:system.datestr(time()-86400)
+			}
+			,{
+				 prop:"TurnsPerDay"
+				,name:"Turns Per Day"
+				,type:"Integer"
+				,def:30
+			}
+			,{
+				 prop:"CabalRegeneration"
+				,name:"Cabal Regeneration (ftrs/day)"
+				,type:"Integer"
+				,def:200
+			}
+			,{
+				 prop:"MessagesToSysop"
+				,name:"Messages to SysOp"
+				,type:"Boolean"
+				,def:true
+			}
+			,{
+				 prop:"MaxPlayers"
+				,name:"Maximum Players"
+				,type:"Integer"
+				,def:70
+			}
+			,{
+				 prop:"MaxPlanets"
+				,name:"Maximum Planets"
+				,type:"Integer"
+				,def:50
+			}
+			,{
+				 prop:"TopTenFile"
+				,name:"Top Ten File Name"
+				,type:"String"
+				,def:"twtopten.txt"
+			}
+			,{
+				 prop:"AllowAliases"
+				,name:"Allow Aliases"
+				,type:"Boolean"
+				,def:true
+			}
+			,{
+				 prop:"MaxTime"
+				,name:"Minutes Allowed Per Session"
+				,type:"Integer"
+				,def:30
+			}
+		];
+
+function GameSettings()
+{
+	var f=new File(fname("game.ini"));
+	var i;
+
+	if(file_exists(f.name)) {
+		f.open("r+");
+		for(i=0; i<GameSettingProperties.length; i++) {
+			this[GameSettingProperties[i].prop]=f.iniGetValue(null, GameSettingProperties[i].prop, GameSettingProperties[i].def);
+		}
+		f.close();
+	}
+	else {
+		for(i=0; i<GameSettingProperties.length; i++) {
+			this[GameSettingProperties[i].prop]=GameSettingProperties[i].def;
+		}
+	}
+	this.save=GameSettings_Save;
+}
+
+function GameSettings_Save()
+{
+	var f=new File(fname("game.ini"));
+
+	f.open(file_exists(f.name) ? 'r+':'w+');
+	for(i=0; i<GameSettingProperties.length; i++) {
+		if(GameSettingProperties[i].type=="Date" || this[GameSettingProperties[i].prop]!=GameSettingProperties[i].def)
+			f.iniSetValue(null, GameSettingProperties[i].prop, this[GameSettingProperties[i].prop]);
+		else
+			f.iniRemoveKey(null, GameSettingProperties[i].prop);
+	}
+	f.close();
+}
diff --git a/xtrn/tw2/ports_map.js b/xtrn/tw2/ports_map.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2d7b2ddaf4fa183f1f973f254b873983405dd6d
--- /dev/null
+++ b/xtrn/tw2/ports_map.js
@@ -0,0 +1,1686 @@
+var ports_init=[
+	{
+		 Name:"Sol"
+		,Position:1
+		,Class:1
+		,OreProduction:0
+		,OrgProduction:0
+		,EquProduction:0
+		,OreDeduction:0
+		,OrgDeduction:0
+		,EquDeduction:0
+	}
+	,{
+		 Name:"Alpha Centauri"
+		,Position:3
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:150
+		,EquProduction:25
+		,OreDeduction:-25
+		,OrgDeduction:22
+		,EquDeduction:-21
+	}
+	,{
+		 Name:"Wolf 359"
+		,Position:5
+		,Class:3
+		,OreProduction:200
+		,OrgProduction:75
+		,EquProduction:75
+		,OreDeduction:20
+		,OrgDeduction:-23
+		,EquDeduction:-21
+	}
+	,{
+		 Name:"Sirius"
+		,Position:7
+		,Class:1
+		,OreProduction:150
+		,OrgProduction:75
+		,EquProduction:100
+		,OreDeduction:-15
+		,OrgDeduction:-23
+		,EquDeduction:26
+	}
+	,{
+		 Name:"Centaurus"
+		,Position:10
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:40
+		,EquProduction:5
+		,OreDeduction:-50
+		,OrgDeduction:50
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Arcturus"
+		,Position:18
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:15
+		,EquProduction:5
+		,OreDeduction:-48
+		,OrgDeduction:50
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Rigel"
+		,Position:19
+		,Class:1
+		,OreProduction:60
+		,OrgProduction:10
+		,EquProduction:80
+		,OreDeduction:-72
+		,OrgDeduction:-75
+		,EquDeduction:80
+	}
+	,{
+		 Name:"T'xe"
+		,Position:21
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:6
+		,OreDeduction:-60
+		,OrgDeduction:60
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"New Paris"
+		,Position:22
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:7
+		,OreDeduction:-63
+		,OrgDeduction:80
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"Palmer's World"
+		,Position:23
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:20
+		,EquProduction:5
+		,OreDeduction:-45
+		,OrgDeduction:40
+		,EquDeduction:-43
+	}
+	,{
+		 Name:"NGC-33"
+		,Position:35
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:20
+		,EquProduction:10
+		,OreDeduction:40
+		,OrgDeduction:-30
+		,EquDeduction:-29
+	}
+	,{
+		 Name:"Bourne's Star"
+		,Position:37
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:30
+		,EquProduction:10
+		,OreDeduction:-55
+		,OrgDeduction:60
+		,EquDeduction:-57
+	}
+	,{
+		 Name:"Aldebaran"
+		,Position:38
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:35
+		,EquProduction:8
+		,OreDeduction:-80
+		,OrgDeduction:52
+		,EquDeduction:-69
+	}
+	,{
+		 Name:"LNC Nebulae"
+		,Position:39
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:50
+		,EquProduction:40
+		,OreDeduction:-40
+		,OrgDeduction:40
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Second Home"
+		,Position:41
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:30
+		,EquProduction:10
+		,OreDeduction:-51
+		,OrgDeduction:49
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Daleth"
+		,Position:43
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:20
+		,EquProduction:10
+		,OreDeduction:75
+		,OrgDeduction:-50
+		,EquDeduction:-54
+	}
+	,{
+		 Name:"Bettelgeuse"
+		,Position:45
+		,Class:3
+		,OreProduction:60
+		,OrgProduction:20
+		,EquProduction:15
+		,OreDeduction:48
+		,OrgDeduction:-50
+		,EquDeduction:-51
+	}
+	,{
+		 Name:"Koph System"
+		,Position:46
+		,Class:1
+		,OreProduction:70
+		,OrgProduction:10
+		,EquProduction:100
+		,OreDeduction:-70
+		,OrgDeduction:-85
+		,EquDeduction:66
+	}
+	,{
+		 Name:"Lonely Hole"
+		,Position:48
+		,Class:3
+		,OreProduction:20
+		,OrgProduction:15
+		,EquProduction:12
+		,OreDeduction:48
+		,OrgDeduction:-30
+		,EquDeduction:-34
+	}
+	,{
+		 Name:"NGC-78"
+		,Position:51
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:15
+		,EquProduction:10
+		,OreDeduction:30
+		,OrgDeduction:-38
+		,EquDeduction:-34
+	}
+	,{
+		 Name:"NGC-4151"
+		,Position:53
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:20
+		,EquProduction:15
+		,OreDeduction:52
+		,OrgDeduction:-60
+		,EquDeduction:-47
+	}
+	,{
+		 Name:"Outpost 7"
+		,Position:57
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:25
+		,EquProduction:12
+		,OreDeduction:60
+		,OrgDeduction:-25
+		,EquDeduction:-48
+	}
+	,{
+		 Name:"Youlose"
+		,Position:58
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:35
+		,EquProduction:15
+		,OreDeduction:50
+		,OrgDeduction:-70
+		,EquDeduction:-86
+	}
+	,{
+		 Name:"Last Hope"
+		,Position:60
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:10
+		,OreDeduction:36
+		,OrgDeduction:-60
+		,EquDeduction:-54
+	}
+	,{
+		 Name:"Epsilon Erandi"
+		,Position:62
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:50
+		,EquProduction:50
+		,OreDeduction:-50
+		,OrgDeduction:70
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Fort Dallas"
+		,Position:66
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:60
+		,EquProduction:50
+		,OreDeduction:-70
+		,OrgDeduction:80
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"Antares"
+		,Position:69
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:-70
+		,OrgDeduction:40
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"Gateway"
+		,Position:71
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:20
+		,EquProduction:40
+		,OreDeduction:-75
+		,OrgDeduction:84
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Sirus II"
+		,Position:73
+		,Class:1
+		,OreProduction:70
+		,OrgProduction:40
+		,EquProduction:50
+		,OreDeduction:-70
+		,OrgDeduction:-70
+		,EquDeduction:60
+	}
+	,{
+		 Name:"Czar'ak"
+		,Position:77
+		,Class:1
+		,OreProduction:80
+		,OrgProduction:60
+		,EquProduction:70
+		,OreDeduction:-69
+		,OrgDeduction:-75
+		,EquDeduction:50
+	}
+	,{
+		 Name:"Vega"
+		,Position:88
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:30
+		,EquProduction:40
+		,OreDeduction:-50
+		,OrgDeduction:30
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Canopus"
+		,Position:89
+		,Class:3
+		,OreProduction:20
+		,OrgProduction:30
+		,EquProduction:50
+		,OreDeduction:35
+		,OrgDeduction:-40
+		,EquDeduction:-80
+	}
+	,{
+		 Name:"Ross 154"
+		,Position:93
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:70
+		,OrgDeduction:-60
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Luyten 789-6"
+		,Position:94
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:45
+		,EquProduction:50
+		,OreDeduction:40
+		,OrgDeduction:-30
+		,EquDeduction:-30
+	}
+	,{
+		 Name:"Bozone"
+		,Position:97
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:30
+		,EquProduction:20
+		,OreDeduction:20
+		,OrgDeduction:-40
+		,EquDeduction:-25
+	}
+	,{
+		 Name:"Insearch"
+		,Position:101
+		,Class:1
+		,OreProduction:50
+		,OrgProduction:20
+		,EquProduction:75
+		,OreDeduction:-20
+		,OrgDeduction:-15
+		,EquDeduction:40
+	}
+	,{
+		 Name:"Ptolemy"
+		,Position:105
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:30
+		,EquProduction:30
+		,OreDeduction:-40
+		,OrgDeduction:35
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Frontier 3"
+		,Position:107
+		,Class:3
+		,OreProduction:35
+		,OrgProduction:35
+		,EquProduction:20
+		,OreDeduction:51
+		,OrgDeduction:-30
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Pleione"
+		,Position:111
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:10
+		,EquProduction:35
+		,OreDeduction:30
+		,OrgDeduction:-20
+		,EquDeduction:-20
+	}
+	,{
+		 Name:"Orion"
+		,Position:113
+		,Class:1
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:50
+		,OreDeduction:-10
+		,OrgDeduction:-30
+		,EquDeduction:45
+	}
+	,{
+		 Name:"Triffid 4"
+		,Position:116
+		,Class:1
+		,OreProduction:130
+		,OrgProduction:70
+		,EquProduction:85
+		,OreDeduction:-15
+		,OrgDeduction:-36
+		,EquDeduction:50
+	}
+	,{
+		 Name:"Diamond"
+		,Position:118
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:30
+		,EquProduction:15
+		,OreDeduction:40
+		,OrgDeduction:-52
+		,EquDeduction:-30
+	}
+	,{
+		 Name:"Last Chance"
+		,Position:120
+		,Class:1
+		,OreProduction:110
+		,OrgProduction:15
+		,EquProduction:60
+		,OreDeduction:-10
+		,OrgDeduction:-75
+		,EquDeduction:32
+	}
+	,{
+		 Name:"Polaris"
+		,Position:122
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:16
+		,EquProduction:26
+		,OreDeduction:80
+		,OrgDeduction:-30
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Yaxa"
+		,Position:124
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:30
+		,EquProduction:20
+		,OreDeduction:-75
+		,OrgDeduction:10
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Jorgasnovara"
+		,Position:125
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:75
+		,OreDeduction:-40
+		,OrgDeduction:40
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Quilst"
+		,Position:130
+		,Class:1
+		,OreProduction:15
+		,OrgProduction:75
+		,EquProduction:100
+		,OreDeduction:-12
+		,OrgDeduction:-26
+		,EquDeduction:55
+	}
+	,{
+		 Name:"Qeegiz"
+		,Position:133
+		,Class:3
+		,OreProduction:86
+		,OrgProduction:45
+		,EquProduction:37
+		,OreDeduction:70
+		,OrgDeduction:-23
+		,EquDeduction:-12
+	}
+	,{
+		 Name:"Zumerbalt"
+		,Position:138
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:30
+		,EquProduction:50
+		,OreDeduction:-85
+		,OrgDeduction:30
+		,EquDeduction:-10
+	}
+	,{
+		 Name:"Felgercarb"
+		,Position:139
+		,Class:1
+		,OreProduction:20
+		,OrgProduction:20
+		,EquProduction:20
+		,OreDeduction:-28
+		,OrgDeduction:-25
+		,EquDeduction:50
+	}
+	,{
+		 Name:"Nodi"
+		,Position:141
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:25
+		,EquProduction:12
+		,OreDeduction:-23
+		,OrgDeduction:42
+		,EquDeduction:-36
+	}
+	,{
+		 Name:"Dazzel"
+		,Position:144
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:25
+		,EquProduction:5
+		,OreDeduction:41
+		,OrgDeduction:-50
+		,EquDeduction:-43
+	}
+	,{
+		 Name:"Yimx"
+		,Position:145
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:30
+		,EquProduction:10
+		,OreDeduction:12
+		,OrgDeduction:-36
+		,EquDeduction:-71
+	}
+	,{
+		 Name:"Gedemondas"
+		,Position:149
+		,Class:2
+		,OreProduction:17
+		,OrgProduction:27
+		,EquProduction:37
+		,OreDeduction:-85
+		,OrgDeduction:50
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Crill"
+		,Position:153
+		,Class:2
+		,OreProduction:10
+		,OrgProduction:15
+		,EquProduction:50
+		,OreDeduction:-41
+		,OrgDeduction:37
+		,EquDeduction:-18
+	}
+	,{
+		 Name:"Samaara"
+		,Position:155
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:50
+		,EquProduction:90
+		,OreDeduction:-30
+		,OrgDeduction:30
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Lofz"
+		,Position:157
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:30
+		,EquProduction:85
+		,OreDeduction:-20
+		,OrgDeduction:24
+		,EquDeduction:-73
+	}
+	,{
+		 Name:"Tsunamis"
+		,Position:161
+		,Class:3
+		,OreProduction:18
+		,OrgProduction:29
+		,EquProduction:46
+		,OreDeduction:36
+		,OrgDeduction:-50
+		,EquDeduction:-64
+	}
+	,{
+		 Name:"Furiaz"
+		,Position:165
+		,Class:1
+		,OreProduction:19
+		,OrgProduction:39
+		,EquProduction:44
+		,OreDeduction:-70
+		,OrgDeduction:-65
+		,EquDeduction:66
+	}
+	,{
+		 Name:"ZTX 4"
+		,Position:166
+		,Class:1
+		,OreProduction:70
+		,OrgProduction:40
+		,EquProduction:50
+		,OreDeduction:-84
+		,OrgDeduction:-40
+		,EquDeduction:35
+	}
+	,{
+		 Name:"Ilik-69"
+		,Position:169
+		,Class:3
+		,OreProduction:80
+		,OrgProduction:20
+		,EquProduction:60
+		,OreDeduction:45
+		,OrgDeduction:-40
+		,EquDeduction:-55
+	}
+	,{
+		 Name:"Marsh System"
+		,Position:171
+		,Class:1
+		,OreProduction:40
+		,OrgProduction:110
+		,EquProduction:70
+		,OreDeduction:-40
+		,OrgDeduction:-55
+		,EquDeduction:75
+	}
+	,{
+		 Name:"Stargate"
+		,Position:173
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:30
+		,EquProduction:10
+		,OreDeduction:60
+		,OrgDeduction:-42
+		,EquDeduction:-43
+	}
+	,{
+		 Name:"Ridiculous 1"
+		,Position:176
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:-70
+		,OrgDeduction:50
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Ceti-Alpha VI"
+		,Position:182
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:15
+		,EquProduction:30
+		,OreDeduction:-40
+		,OrgDeduction:40
+		,EquDeduction:-65
+	}
+	,{
+		 Name:"Frontier 8"
+		,Position:183
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:30
+		,EquProduction:25
+		,OreDeduction:-63
+		,OrgDeduction:80
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"New America"
+		,Position:186
+		,Class:3
+		,OreProduction:60
+		,OrgProduction:20
+		,EquProduction:15
+		,OreDeduction:40
+		,OrgDeduction:-40
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Criton"
+		,Position:190
+		,Class:1
+		,OreProduction:30
+		,OrgProduction:25
+		,EquProduction:20
+		,OreDeduction:-70
+		,OrgDeduction:-60
+		,EquDeduction:40
+	}
+	,{
+		 Name:"Moskva"
+		,Position:191
+		,Class:2
+		,OreProduction:200
+		,OrgProduction:10
+		,EquProduction:15
+		,OreDeduction:-75
+		,OrgDeduction:75
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Ahzdar"
+		,Position:192
+		,Class:1
+		,OreProduction:90
+		,OrgProduction:90
+		,EquProduction:90
+		,OreDeduction:-80
+		,OrgDeduction:-80
+		,EquDeduction:70
+	}
+	,{
+		 Name:"Sukered-ya"
+		,Position:194
+		,Class:3
+		,OreProduction:10
+		,OrgProduction:200
+		,EquProduction:99
+		,OreDeduction:49
+		,OrgDeduction:-50
+		,EquDeduction:-53
+	}
+	,{
+		 Name:"Gamma 12"
+		,Position:196
+		,Class:1
+		,OreProduction:42
+		,OrgProduction:16
+		,EquProduction:50
+		,OreDeduction:-70
+		,OrgDeduction:-70
+		,EquDeduction:60
+	}
+	,{
+		 Name:"Sqeel"
+		,Position:199
+		,Class:2
+		,OreProduction:70
+		,OrgProduction:69
+		,EquProduction:70
+		,OreDeduction:-75
+		,OrgDeduction:95
+		,EquDeduction:-65
+	}
+	,{
+		 Name:"Darion"
+		,Position:214
+		,Class:3
+		,OreProduction:75
+		,OrgProduction:45
+		,EquProduction:45
+		,OreDeduction:80
+		,OrgDeduction:-51
+		,EquDeduction:-53
+	}
+	,{
+		 Name:"Caspan"
+		,Position:218
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:150
+		,EquProduction:25
+		,OreDeduction:-25
+		,OrgDeduction:22
+		,EquDeduction:-21
+	}
+	,{
+		 Name:"Paegan"
+		,Position:225
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:100
+		,EquProduction:68
+		,OreDeduction:-50
+		,OrgDeduction:61
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Mongo"
+		,Position:236
+		,Class:3
+		,OreProduction:80
+		,OrgProduction:40
+		,EquProduction:45
+		,OreDeduction:85
+		,OrgDeduction:-50
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Tori"
+		,Position:242
+		,Class:1
+		,OreProduction:190
+		,OrgProduction:120
+		,EquProduction:190
+		,OreDeduction:-20
+		,OrgDeduction:-25
+		,EquDeduction:45
+	}
+	,{
+		 Name:"Fomalhaut"
+		,Position:247
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:30
+		,EquProduction:20
+		,OreDeduction:-50
+		,OrgDeduction:50
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Xanthii"
+		,Position:248
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:55
+		,EquProduction:50
+		,OreDeduction:-60
+		,OrgDeduction:75
+		,EquDeduction:-61
+	}
+	,{
+		 Name:"Sinuiji"
+		,Position:250
+		,Class:3
+		,OreProduction:70
+		,OrgProduction:30
+		,EquProduction:30
+		,OreDeduction:30
+		,OrgDeduction:-40
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Sardar"
+		,Position:254
+		,Class:3
+		,OreProduction:90
+		,OrgProduction:50
+		,EquProduction:40
+		,OreDeduction:50
+		,OrgDeduction:-52
+		,EquDeduction:-49
+	}
+	,{
+		 Name:"Behr'ak"
+		,Position:256
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:60
+		,EquProduction:55
+		,OreDeduction:-50
+		,OrgDeduction:70
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Bellatrix"
+		,Position:259
+		,Class:3
+		,OreProduction:30
+		,OrgProduction:40
+		,EquProduction:15
+		,OreDeduction:35
+		,OrgDeduction:-70
+		,EquDeduction:-55
+	}
+	,{
+		 Name:"Acrux"
+		,Position:262
+		,Class:3
+		,OreProduction:100
+		,OrgProduction:60
+		,EquProduction:28
+		,OreDeduction:70
+		,OrgDeduction:-45
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Horok"
+		,Position:263
+		,Class:3
+		,OreProduction:80
+		,OrgProduction:30
+		,EquProduction:50
+		,OreDeduction:50
+		,OrgDeduction:-40
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"K'ushui"
+		,Position:273
+		,Class:1
+		,OreProduction:80
+		,OrgProduction:120
+		,EquProduction:200
+		,OreDeduction:-72
+		,OrgDeduction:-80
+		,EquDeduction:90
+	}
+	,{
+		 Name:"Mialplacidas"
+		,Position:276
+		,Class:3
+		,OreProduction:110
+		,OrgProduction:80
+		,EquProduction:105
+		,OreDeduction:50
+		,OrgDeduction:-30
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Rigil Kentaurus"
+		,Position:280
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:70
+		,EquProduction:50
+		,OreDeduction:-75
+		,OrgDeduction:85
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Jassan"
+		,Position:285
+		,Class:2
+		,OreProduction:155
+		,OrgProduction:200
+		,EquProduction:110
+		,OreDeduction:-45
+		,OrgDeduction:50
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Oomaru"
+		,Position:290
+		,Class:2
+		,OreProduction:45
+		,OrgProduction:70
+		,EquProduction:40
+		,OreDeduction:-40
+		,OrgDeduction:42
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Eskiis"
+		,Position:293
+		,Class:3
+		,OreProduction:90
+		,OrgProduction:50
+		,EquProduction:60
+		,OreDeduction:84
+		,OrgDeduction:-65
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Taan"
+		,Position:295
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:90
+		,EquProduction:60
+		,OreDeduction:-60
+		,OrgDeduction:65
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Saaula"
+		,Position:298
+		,Class:3
+		,OreProduction:75
+		,OrgProduction:40
+		,EquProduction:45
+		,OreDeduction:75
+		,OrgDeduction:-40
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Kep Salu"
+		,Position:301
+		,Class:1
+		,OreProduction:80
+		,OrgProduction:100
+		,EquProduction:130
+		,OreDeduction:-40
+		,OrgDeduction:-40
+		,EquDeduction:50
+	}
+	,{
+		 Name:"Alam'ak"
+		,Position:304
+		,Class:2
+		,OreProduction:95
+		,OrgProduction:150
+		,EquProduction:100
+		,OreDeduction:-40
+		,OrgDeduction:50
+		,EquDeduction:-33
+	}
+	,{
+		 Name:"Wezen"
+		,Position:305
+		,Class:3
+		,OreProduction:70
+		,OrgProduction:25
+		,EquProduction:25
+		,OreDeduction:30
+		,OrgDeduction:-40
+		,EquDeduction:-25
+	}
+	,{
+		 Name:"Ghondr"
+		,Position:307
+		,Class:3
+		,OreProduction:110
+		,OrgProduction:50
+		,EquProduction:50
+		,OreDeduction:60
+		,OrgDeduction:-40
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"K'hotan"
+		,Position:311
+		,Class:3
+		,OreProduction:70
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:51
+		,OrgDeduction:-30
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Androcus"
+		,Position:316
+		,Class:1
+		,OreProduction:110
+		,OrgProduction:120
+		,EquProduction:180
+		,OreDeduction:-71
+		,OrgDeduction:-65
+		,EquDeduction:85
+	}
+	,{
+		 Name:"Regulus"
+		,Position:319
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:35
+		,EquProduction:20
+		,OreDeduction:80
+		,OrgDeduction:-50
+		,EquDeduction:-30
+	}
+	,{
+		 Name:"Proxima"
+		,Position:329
+		,Class:2
+		,OreProduction:125
+		,OrgProduction:115
+		,EquProduction:100
+		,OreDeduction:-45
+		,OrgDeduction:70
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Achernar B"
+		,Position:334
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:90
+		,EquProduction:45
+		,OreDeduction:-50
+		,OrgDeduction:70
+		,EquDeduction:-55
+	}
+	,{
+		 Name:"Ndele"
+		,Position:337
+		,Class:3
+		,OreProduction:190
+		,OrgProduction:90
+		,EquProduction:100
+		,OreDeduction:25
+		,OrgDeduction:-25
+		,EquDeduction:-20
+	}
+	,{
+		 Name:"Tali"
+		,Position:341
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:80
+		,EquProduction:40
+		,OreDeduction:-50
+		,OrgDeduction:30
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Tutakai"
+		,Position:342
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:35
+		,EquProduction:20
+		,OreDeduction:60
+		,OrgDeduction:-80
+		,EquDeduction:-85
+	}
+	,{
+		 Name:"Dubhe"
+		,Position:344
+		,Class:1
+		,OreProduction:200
+		,OrgProduction:110
+		,EquProduction:195
+		,OreDeduction:-25
+		,OrgDeduction:-20
+		,EquDeduction:38
+	}
+	,{
+		 Name:"Annobon"
+		,Position:348
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:70
+		,EquProduction:65
+		,OreDeduction:-60
+		,OrgDeduction:80
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Lux"
+		,Position:350
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:30
+		,EquProduction:20
+		,OreDeduction:53
+		,OrgDeduction:-62
+		,EquDeduction:-46
+	}
+	,{
+		 Name:"Mirfak"
+		,Position:356
+		,Class:2
+		,OreProduction:95
+		,OrgProduction:115
+		,EquProduction:90
+		,OreDeduction:-63
+		,OrgDeduction:85
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"Zindar"
+		,Position:360
+		,Class:2
+		,OreProduction:100
+		,OrgProduction:160
+		,EquProduction:45
+		,OreDeduction:-26
+		,OrgDeduction:27
+		,EquDeduction:-21
+	}
+	,{
+		 Name:"Adao"
+		,Position:362
+		,Class:3
+		,OreProduction:60
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:30
+		,OrgDeduction:-40
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Theseus 2"
+		,Position:366
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:60
+		,EquProduction:45
+		,OreDeduction:-55
+		,OrgDeduction:60
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Azrael"
+		,Position:369
+		,Class:3
+		,OreProduction:80
+		,OrgProduction:40
+		,EquProduction:40
+		,OreDeduction:50
+		,OrgDeduction:-40
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Etzel"
+		,Position:373
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:155
+		,EquProduction:85
+		,OreDeduction:-36
+		,OrgDeduction:50
+		,EquDeduction:-28
+	}
+	,{
+		 Name:"Xerxes"
+		,Position:379
+		,Class:2
+		,OreProduction:90
+		,OrgProduction:75
+		,EquProduction:50
+		,OreDeduction:-80
+		,OrgDeduction:52
+		,EquDeduction:-70
+	}
+	,{
+		 Name:"Loki"
+		,Position:383
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:160
+		,EquProduction:30
+		,OreDeduction:-28
+		,OrgDeduction:30
+		,EquDeduction:-20
+	}
+	,{
+		 Name:"Hashishyun"
+		,Position:384
+		,Class:3
+		,OreProduction:60
+		,OrgProduction:20
+		,EquProduction:25
+		,OreDeduction:70
+		,OrgDeduction:-30
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Akbar"
+		,Position:386
+		,Class:3
+		,OreProduction:120
+		,OrgProduction:100
+		,EquProduction:110
+		,OreDeduction:50
+		,OrgDeduction:-30
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Abu Bekr"
+		,Position:387
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:30
+		,EquProduction:20
+		,OreDeduction:40
+		,OrgDeduction:-27
+		,EquDeduction:-23
+	}
+	,{
+		 Name:"Appollyon"
+		,Position:389
+		,Class:1
+		,OreProduction:110
+		,OrgProduction:60
+		,EquProduction:150
+		,OreDeduction:-71
+		,OrgDeduction:-83
+		,EquDeduction:65
+	}
+	,{
+		 Name:"Iblis"
+		,Position:390
+		,Class:2
+		,OreProduction:105
+		,OrgProduction:115
+		,EquProduction:70
+		,OreDeduction:-61
+		,OrgDeduction:85
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Siva"
+		,Position:393
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:60
+		,EquProduction:30
+		,OreDeduction:-40
+		,OrgDeduction:40
+		,EquDeduction:-45
+	}
+	,{
+		 Name:"Tyr"
+		,Position:394
+		,Class:1
+		,OreProduction:110
+		,OrgProduction:120
+		,EquProduction:180
+		,OreDeduction:-78
+		,OrgDeduction:-69
+		,EquDeduction:81
+	}
+	,{
+		 Name:"Alaric"
+		,Position:395
+		,Class:2
+		,OreProduction:90
+		,OrgProduction:50
+		,EquProduction:45
+		,OreDeduction:-50
+		,OrgDeduction:65
+		,EquDeduction:-57
+	}
+	,{
+		 Name:"Aeolus"
+		,Position:397
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:20
+		,EquProduction:40
+		,OreDeduction:-75
+		,OrgDeduction:85
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Tonti"
+		,Position:408
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:30
+		,EquProduction:25
+		,OreDeduction:85
+		,OrgDeduction:-45
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Canus Minor"
+		,Position:418
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:40
+		,EquProduction:35
+		,OreDeduction:-75
+		,OrgDeduction:75
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Equulus"
+		,Position:421
+		,Class:3
+		,OreProduction:60
+		,OrgProduction:40
+		,EquProduction:20
+		,OreDeduction:80
+		,OrgDeduction:-40
+		,EquDeduction:-50
+	}
+	,{
+		 Name:"Monoceros"
+		,Position:423
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:50
+		,EquProduction:15
+		,OreDeduction:-40
+		,OrgDeduction:45
+		,EquDeduction:-80
+	}
+	,{
+		 Name:"Corvus"
+		,Position:426
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:110
+		,EquProduction:75
+		,OreDeduction:-60
+		,OrgDeduction:65
+		,EquDeduction:-75
+	}
+	,{
+		 Name:"Phoenix"
+		,Position:429
+		,Class:3
+		,OreProduction:86
+		,OrgProduction:60
+		,EquProduction:45
+		,OreDeduction:90
+		,OrgDeduction:-80
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"Tucana"
+		,Position:435
+		,Class:1
+		,OreProduction:70
+		,OrgProduction:40
+		,EquProduction:85
+		,OreDeduction:-80
+		,OrgDeduction:-85
+		,EquDeduction:65
+	}
+	,{
+		 Name:"Apian"
+		,Position:438
+		,Class:3
+		,OreProduction:80
+		,OrgProduction:70
+		,EquProduction:65
+		,OreDeduction:65
+		,OrgDeduction:-65
+		,EquDeduction:-65
+	}
+	,{
+		 Name:"Doppler"
+		,Position:440
+		,Class:3
+		,OreProduction:86
+		,OrgProduction:45
+		,EquProduction:37
+		,OreDeduction:85
+		,OrgDeduction:-40
+		,EquDeduction:-78
+	}
+	,{
+		 Name:"Palitzsch"
+		,Position:443
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:60
+		,EquProduction:40
+		,OreDeduction:-40
+		,OrgDeduction:65
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Seagate"
+		,Position:445
+		,Class:3
+		,OreProduction:45
+		,OrgProduction:15
+		,EquProduction:25
+		,OreDeduction:85
+		,OrgDeduction:-60
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Chandrasekher"
+		,Position:446
+		,Class:2
+		,OreProduction:80
+		,OrgProduction:140
+		,EquProduction:90
+		,OreDeduction:-70
+		,OrgDeduction:55
+		,EquDeduction:-62
+	}
+	,{
+		 Name:"Cratuer"
+		,Position:452
+		,Class:1
+		,OreProduction:130
+		,OrgProduction:40
+		,EquProduction:180
+		,OreDeduction:-65
+		,OrgDeduction:-80
+		,EquDeduction:70
+	}
+	,{
+		 Name:"Ibn Duad"
+		,Position:459
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:60
+		,EquProduction:50
+		,OreDeduction:-85
+		,OrgDeduction:85
+		,EquDeduction:-85
+	}
+	,{
+		 Name:"Pilar"
+		,Position:463
+		,Class:2
+		,OreProduction:40
+		,OrgProduction:80
+		,EquProduction:25
+		,OreDeduction:-75
+		,OrgDeduction:80
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Ketoi"
+		,Position:466
+		,Class:2
+		,OreProduction:30
+		,OrgProduction:60
+		,EquProduction:30
+		,OreDeduction:-40
+		,OrgDeduction:65
+		,EquDeduction:-65
+	}
+	,{
+		 Name:"Tulan"
+		,Position:468
+		,Class:3
+		,OreProduction:40
+		,OrgProduction:16
+		,EquProduction:30
+		,OreDeduction:75
+		,OrgDeduction:-25
+		,EquDeduction:-40
+	}
+	,{
+		 Name:"Alvarado"
+		,Position:469
+		,Class:2
+		,OreProduction:90
+		,OrgProduction:120
+		,EquProduction:80
+		,OreDeduction:-60
+		,OrgDeduction:70
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Hrok 1"
+		,Position:471
+		,Class:1
+		,OreProduction:90
+		,OrgProduction:50
+		,EquProduction:150
+		,OreDeduction:-45
+		,OrgDeduction:-75
+		,EquDeduction:75
+	}
+	,{
+		 Name:"Ramusik"
+		,Position:472
+		,Class:3
+		,OreProduction:50
+		,OrgProduction:30
+		,EquProduction:10
+		,OreDeduction:65
+		,OrgDeduction:-35
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Canus Major"
+		,Position:482
+		,Class:3
+		,OreProduction:70
+		,OrgProduction:35
+		,EquProduction:35
+		,OreDeduction:70
+		,OrgDeduction:-70
+		,EquDeduction:-65
+	}
+	,{
+		 Name:"H12"
+		,Position:483
+		,Class:2
+		,OreProduction:90
+		,OrgProduction:180
+		,EquProduction:100
+		,OreDeduction:-40
+		,OrgDeduction:50
+		,EquDeduction:-25
+	}
+	,{
+		 Name:"Spica"
+		,Position:489
+		,Class:2
+		,OreProduction:50
+		,OrgProduction:60
+		,EquProduction:40
+		,OreDeduction:-70
+		,OrgDeduction:59
+		,EquDeduction:-36
+	}
+	,{
+		 Name:"Yugonislom"
+		,Position:490
+		,Class:3
+		,OreProduction:46
+		,OrgProduction:29
+		,EquProduction:20
+		,OreDeduction:50
+		,OrgDeduction:-50
+		,EquDeduction:-45
+	}
+/* Not in the real game...
+	,{
+		 Name:"Alfr"
+		,Position:492
+		,Class:2
+		,OreProduction:20
+		,OrgProduction:85
+		,EquProduction:30
+		,OreDeduction:-20
+		,OrgDeduction:50
+		,EquDeduction:-35
+	}
+	,{
+		 Name:"Tall Grass"
+		,Position:494
+		,Class:3
+		,OreProduction:65
+		,OrgProduction:40
+		,EquProduction:30
+		,OreDeduction:60
+		,OrgDeduction:-60
+		,EquDeduction:-60
+	}
+	,{
+		 Name:"H9"
+		,Position:496
+		,Class:3
+		,OreProduction:110
+		,OrgProduction:60
+		,EquProduction:50
+		,OreDeduction:80
+		,OrgDeduction:-40
+		,EquDeduction:-65
+	} */
+];
diff --git a/xtrn/tw2/rectest.js b/xtrn/tw2/rectest.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c0acb34f98b413299fece07c6a80438d192e1c1
--- /dev/null
+++ b/xtrn/tw2/rectest.js
@@ -0,0 +1,19 @@
+load("recordfile.js");
+var Struct = [
+				{
+				 prop:"Check"
+				,type:"Boolean"
+				,def:false
+				}
+	];
+var rf=new RecordFile("../xtrn/tw2/rectest.dat",Struct);
+
+if(rf.length==0)
+	r=rf.New();
+else
+	r=rf.Get(0);
+writeln("At start, Check=="+r.Check);
+r.Put();
+writeln("After Put, Check=="+r.Check);
+r.ReLoad(0);
+writeln("Ad end, Check=="+r.Check);
diff --git a/xtrn/tw2/sector_map.js b/xtrn/tw2/sector_map.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb109587e77953863a51344a8c922741a91a2c41
--- /dev/null
+++ b/xtrn/tw2/sector_map.js
@@ -0,0 +1,1502 @@
+var sector_map=[
+	{
+		Warps:[2,3,4,5,6,7]
+	}
+	,{
+		Warps:[9,10,3,1,7,8]
+	}
+	,{
+		Warps:[20,4,1,2]
+	}
+	,{
+		Warps:[3,11,12,13,5,1]
+	}
+	,{
+		Warps:[1,4,6]
+	}
+	,{
+		Warps:[7,1,5,14,15,16]
+	}
+	,{
+		Warps:[8,2,1,6,75,17]
+	}
+	,{
+		Warps:[19,2,7]
+	}
+	,{
+		Warps:[38,10,2,140,19]
+	}
+	,{
+		Warps:[140,2,9]
+	}
+	,{
+		Warps:[20,21,4,151]
+	}
+	,{
+		Warps:[22,4]
+	}
+	,{
+		Warps:[4,32,46]
+	}
+	,{
+		Warps:[6,46,47,201,15]
+	}
+	,{
+		Warps:[23,16,6,14,142]
+	}
+	,{
+		Warps:[17,6,15,23]
+	}
+	,{
+		Warps:[7,16,18]
+	}
+	,{
+		Warps:[25,17,238,24]
+	}
+	,{
+		Warps:[26,9,8,25]
+	}
+	,{
+		Warps:[27,28,11,3]
+	}
+	,{
+		Warps:[29,11]
+	}
+	,{
+		Warps:[12,30,31,32]
+	}
+	,{
+		Warps:[16,15,238,34]
+	}
+	,{
+		Warps:[54,18,35,36]
+	}
+	,{
+		Warps:[19,18,37]
+	}
+	,{
+		Warps:[252,38,19,92]
+	}
+	,{
+		Warps:[56,20]
+	}
+	,{
+		Warps:[39,40,110,20]
+	}
+	,{
+		Warps:[41,42,151,21]
+	}
+	,{
+		Warps:[43,44,22]
+	}
+	,{
+		Warps:[22,45,141]
+	}
+	,{
+		Warps:[13,22,33,46]
+	}
+	,{
+		Warps:[46,32,45,88,87,47]
+	}
+	,{
+		Warps:[49,23,48]
+	}
+	,{
+		Warps:[36,24,49,50]
+	}
+	,{
+		Warps:[53,24,35,51,52]
+	}
+	,{
+		Warps:[91,252,25]
+	}
+	,{
+		Warps:[55,9,140,26]
+	}
+	,{
+		Warps:[109,110,28,500,56]
+	}
+	,{
+		Warps:[57,41,28]
+	}
+	,{
+		Warps:[40,29]
+	}
+	,{
+		Warps:[159,58,59,43,29]
+	}
+	,{
+		Warps:[42,30]
+	}
+	,{
+		Warps:[59,60,30]
+	}
+	,{
+		Warps:[31,95,33]
+	}
+	,{
+		Warps:[13,32,33,14]
+	}
+	,{
+		Warps:[14,33,61]
+	}
+	,{
+		Warps:[34,63,64]
+	}
+	,{
+		Warps:[491,238,34,35]
+	}
+	,{
+		Warps:[51,35,65,71]
+	}
+	,{
+		Warps:[52,36,50,498]
+	}
+	,{
+		Warps:[75,53,36,51,152,66]
+	}
+	,{
+		Warps:[67,68,54,36,52]
+	}
+	,{
+		Warps:[24,53]
+	}
+	,{
+		Warps:[1,56,38,157]
+	}
+	,{
+		Warps:[39,27,55]
+	}
+	,{
+		Warps:[40]
+	}
+	,{
+		Warps:[159,59,42]
+	}
+	,{
+		Warps:[42,58,69,44]
+	}
+	,{
+		Warps:[44,70,198,224]
+	}
+	,{
+		Warps:[47,89,62]
+	}
+	,{
+		Warps:[121,61,90,63]
+	}
+	,{
+		Warps:[62,461,48]
+	}
+	,{
+		Warps:[65,48,100,222]
+	}
+	,{
+		Warps:[50,64]
+	}
+	,{
+		Warps:[76,52,74,152]
+	}
+	,{
+		Warps:[78,53,77]
+	}
+	,{
+		Warps:[91,53]
+	}
+	,{
+		Warps:[59,116,118,70,224]
+	}
+	,{
+		Warps:[69,116,99,60]
+	}
+	,{
+		Warps:[50,102,72]
+	}
+	,{
+		Warps:[73,71,262]
+	}
+	,{
+		Warps:[74,183,72,1]
+	}
+	,{
+		Warps:[66,179,73,152,178]
+	}
+	,{
+		Warps:[7,52]
+	}
+	,{
+		Warps:[79,77,66]
+	}
+	,{
+		Warps:[67,76]
+	}
+	,{
+		Warps:[81,67,80]
+	}
+	,{
+		Warps:[82,80,76]
+	}
+	,{
+		Warps:[83,81,78,79,82]
+	}
+	,{
+		Warps:[84,78,80,83]
+	}
+	,{
+		Warps:[86,83,80,79]
+	}
+	,{
+		Warps:[85,84,81,80,82,86]
+	}
+	,{
+		Warps:[81,83]
+	}
+	,{
+		Warps:[83]
+	}
+	,{
+		Warps:[83,82]
+	}
+	,{
+		Warps:[33,88,89]
+	}
+	,{
+		Warps:[33,95,96,87]
+	}
+	,{
+		Warps:[61,87,351,98,90]
+	}
+	,{
+		Warps:[62,89,120]
+	}
+	,{
+		Warps:[94,92,37,68]
+	}
+	,{
+		Warps:[93,26,91]
+	}
+	,{
+		Warps:[131,204,92,497]
+	}
+	,{
+		Warps:[332,91,130]
+	}
+	,{
+		Warps:[45,105,97,88]
+	}
+	,{
+		Warps:[88,97,98]
+	}
+	,{
+		Warps:[95,115,96]
+	}
+	,{
+		Warps:[89,96,111,1]
+	}
+	,{
+		Warps:[70,117,1,198,116]
+	}
+	,{
+		Warps:[64,101,103,104]
+	}
+	,{
+		Warps:[100,102,128]
+	}
+	,{
+		Warps:[71,101]
+	}
+	,{
+		Warps:[100,104]
+	}
+	,{
+		Warps:[100,103,190,129]
+	}
+	,{
+		Warps:[95,115,202,106]
+	}
+	,{
+		Warps:[105,107,125,108]
+	}
+	,{
+		Warps:[106]
+	}
+	,{
+		Warps:[106,126,149]
+	}
+	,{
+		Warps:[39,139]
+	}
+	,{
+		Warps:[39,28]
+	}
+	,{
+		Warps:[98,113,112,114]
+	}
+	,{
+		Warps:[145,114,111]
+	}
+	,{
+		Warps:[111,132,114]
+	}
+	,{
+		Warps:[113,112,127,111,230]
+	}
+	,{
+		Warps:[97,442,105]
+	}
+	,{
+		Warps:[69,99,117,70,118,119]
+	}
+	,{
+		Warps:[99,188,136,119,116]
+	}
+	,{
+		Warps:[69,116,224]
+	}
+	,{
+		Warps:[136,116,117,185]
+	}
+	,{
+		Warps:[90,121,122]
+	}
+	,{
+		Warps:[62,120]
+	}
+	,{
+		Warps:[120,125,123,200]
+	}
+	,{
+		Warps:[122,125,200,124]
+	}
+	,{
+		Warps:[144,143,123]
+	}
+	,{
+		Warps:[188,106,126]
+	}
+	,{
+		Warps:[125,150,108,166]
+	}
+	,{
+		Warps:[114,133,176,231]
+	}
+	,{
+		Warps:[101,129]
+	}
+	,{
+		Warps:[128,104]
+	}
+	,{
+		Warps:[195,94,205,331]
+	}
+	,{
+		Warps:[153,93]
+	}
+	,{
+		Warps:[113,189,135]
+	}
+	,{
+		Warps:[189,127,176,170,134,135]
+	}
+	,{
+		Warps:[133,172,171]
+	}
+	,{
+		Warps:[133,132]
+	}
+	,{
+		Warps:[119,117,188,137,161]
+	}
+	,{
+		Warps:[138,161,136]
+	}
+	,{
+		Warps:[137,164]
+	}
+	,{
+		Warps:[109,274]
+	}
+	,{
+		Warps:[38,9,10]
+	}
+	,{
+		Warps:[31]
+	}
+	,{
+		Warps:[15]
+	}
+	,{
+		Warps:[124,440,144]
+	}
+	,{
+		Warps:[143,124,221]
+	}
+	,{
+		Warps:[199,112,146]
+	}
+	,{
+		Warps:[145,148,230,147]
+	}
+	,{
+		Warps:[148,173,146,231]
+	}
+	,{
+		Warps:[146,129,173,147]
+	}
+	,{
+		Warps:[108,150,202]
+	}
+	,{
+		Warps:[126,149,177,400]
+	}
+	,{
+		Warps:[11,29]
+	}
+	,{
+		Warps:[66,74,52]
+	}
+	,{
+		Warps:[131,154,158,156]
+	}
+	,{
+		Warps:[153,155]
+	}
+	,{
+		Warps:[156,154,207]
+	}
+	,{
+		Warps:[153,154,155,259]
+	}
+	,{
+		Warps:[55,158,497]
+	}
+	,{
+		Warps:[157,153,261]
+	}
+	,{
+		Warps:[42,58,160]
+	}
+	,{
+		Warps:[159]
+	}
+	,{
+		Warps:[136,137,162]
+	}
+	,{
+		Warps:[161,247,163]
+	}
+	,{
+		Warps:[162,164,197,196]
+	}
+	,{
+		Warps:[138,163,165]
+	}
+	,{
+		Warps:[164]
+	}
+	,{
+		Warps:[126,177,167,168]
+	}
+	,{
+		Warps:[166,225,168,169,177]
+	}
+	,{
+		Warps:[166,167]
+	}
+	,{
+		Warps:[167,286]
+	}
+	,{
+		Warps:[176,133,232,172,192]
+	}
+	,{
+		Warps:[134,226,229,172]
+	}
+	,{
+		Warps:[171,194,193,134,170,192]
+	}
+	,{
+		Warps:[148,147,174,175]
+	}
+	,{
+		Warps:[173,172,215]
+	}
+	,{
+		Warps:[216,173,174]
+	}
+	,{
+		Warps:[127,170,133]
+	}
+	,{
+		Warps:[150,226,166,167]
+	}
+	,{
+		Warps:[74,179,180,184,183]
+	}
+	,{
+		Warps:[74,178,181]
+	}
+	,{
+		Warps:[178,244,239,241]
+	}
+	,{
+		Warps:[179,182,244]
+	}
+	,{
+		Warps:[181,210,211,239]
+	}
+	,{
+		Warps:[178,184,264,73]
+	}
+	,{
+		Warps:[178,183,263]
+	}
+	,{
+		Warps:[119,186,444]
+	}
+	,{
+		Warps:[275,187,185]
+	}
+	,{
+		Warps:[247,186]
+	}
+	,{
+		Warps:[125,117,136]
+	}
+	,{
+		Warps:[133,132]
+	}
+	,{
+		Warps:[104,191]
+	}
+	,{
+		Warps:[190,221,220]
+	}
+	,{
+		Warps:[170,172]
+	}
+	,{
+		Warps:[219,304,172]
+	}
+	,{
+		Warps:[172,229,228]
+	}
+	,{
+		Warps:[296,333,130]
+	}
+	,{
+		Warps:[163,245]
+	}
+	,{
+		Warps:[163,250]
+	}
+	,{
+		Warps:[60,99]
+	}
+	,{
+		Warps:[145]
+	}
+	,{
+		Warps:[122,406,123]
+	}
+	,{
+		Warps:[14]
+	}
+	,{
+		Warps:[105,203,149]
+	}
+	,{
+		Warps:[202]
+	}
+	,{
+		Warps:[93,205]
+	}
+	,{
+		Warps:[130,204,206]
+	}
+	,{
+		Warps:[205,207]
+	}
+	,{
+		Warps:[206,155,209,208]
+	}
+	,{
+		Warps:[235,236,207,209,297]
+	}
+	,{
+		Warps:[207,208,233]
+	}
+	,{
+		Warps:[182,214]
+	}
+	,{
+		Warps:[182,212,243]
+	}
+	,{
+		Warps:[211,213,345,492]
+	}
+	,{
+		Warps:[212,214,253,258]
+	}
+	,{
+		Warps:[213,210]
+	}
+	,{
+		Warps:[174,218,232]
+	}
+	,{
+		Warps:[175,217]
+	}
+	,{
+		Warps:[216,218]
+	}
+	,{
+		Warps:[215,219,217]
+	}
+	,{
+		Warps:[193,218,370,377]
+	}
+	,{
+		Warps:[121,191,222]
+	}
+	,{
+		Warps:[144,191]
+	}
+	,{
+		Warps:[64,220,270]
+	}
+	,{
+		Warps:[118,224]
+	}
+	,{
+		Warps:[59,113,223]
+	}
+	,{
+		Warps:[226,229,227,167]
+	}
+	,{
+		Warps:[171,177,225]
+	}
+	,{
+		Warps:[225,229,228]
+	}
+	,{
+		Warps:[194,374,282,227]
+	}
+	,{
+		Warps:[171,194,227,225]
+	}
+	,{
+		Warps:[114,146]
+	}
+	,{
+		Warps:[127,147]
+	}
+	,{
+		Warps:[170,215]
+	}
+	,{
+		Warps:[234,209]
+	}
+	,{
+		Warps:[233,237,236]
+	}
+	,{
+		Warps:[1,208,269,237]
+	}
+	,{
+		Warps:[234,208]
+	}
+	,{
+		Warps:[235,234,266]
+	}
+	,{
+		Warps:[23,49,18]
+	}
+	,{
+		Warps:[182,180,243]
+	}
+	,{
+		Warps:[242,288,243]
+	}
+	,{
+		Warps:[242,180]
+	}
+	,{
+		Warps:[241,240]
+	}
+	,{
+		Warps:[239,211,293,240]
+	}
+	,{
+		Warps:[180,181]
+	}
+	,{
+		Warps:[196,401,248,415,246]
+	}
+	,{
+		Warps:[245,415,276,249]
+	}
+	,{
+		Warps:[187,162,249]
+	}
+	,{
+		Warps:[245,251,277,415]
+	}
+	,{
+		Warps:[247,246]
+	}
+	,{
+		Warps:[197,251]
+	}
+	,{
+		Warps:[250,367,281,248]
+	}
+	,{
+		Warps:[26,37]
+	}
+	,{
+		Warps:[291,492,213,254]
+	}
+	,{
+		Warps:[314,253,257,255]
+	}
+	,{
+		Warps:[315,254,256]
+	}
+	,{
+		Warps:[272,255,257]
+	}
+	,{
+		Warps:[254,258,256]
+	}
+	,{
+		Warps:[213,257]
+	}
+	,{
+		Warps:[156,261]
+	}
+	,{
+		Warps:[261,274]
+	}
+	,{
+		Warps:[158,260,259]
+	}
+	,{
+		Warps:[72,265]
+	}
+	,{
+		Warps:[184,264]
+	}
+	,{
+		Warps:[183,263,265]
+	}
+	,{
+		Warps:[264,262]
+	}
+	,{
+		Warps:[237,273,270]
+	}
+	,{
+		Warps:[269,268]
+	}
+	,{
+		Warps:[267,297]
+	}
+	,{
+		Warps:[235,273,271,267]
+	}
+	,{
+		Warps:[266,352,494,271]
+	}
+	,{
+		Warps:[270,494,299,348,269]
+	}
+	,{
+		Warps:[268,256,297]
+	}
+	,{
+		Warps:[266,269]
+	}
+	,{
+		Warps:[260,139]
+	}
+	,{
+		Warps:[444,186]
+	}
+	,{
+		Warps:[246,415,278]
+	}
+	,{
+		Warps:[415,248,306,278]
+	}
+	,{
+		Warps:[277,276,415,280]
+	}
+	,{
+		Warps:[490,484,474,1]
+	}
+	,{
+		Warps:[278,398,308]
+	}
+	,{
+		Warps:[389,251,366,309]
+	}
+	,{
+		Warps:[375,302,284,285,228]
+	}
+	,{
+		Warps:[227,285,287,329,286]
+	}
+	,{
+		Warps:[282,303,301,287]
+	}
+	,{
+		Warps:[283,282]
+	}
+	,{
+		Warps:[169,283,366]
+	}
+	,{
+		Warps:[283,301,328]
+	}
+	,{
+		Warps:[290,240]
+	}
+	,{
+		Warps:[1,471]
+	}
+	,{
+		Warps:[288,292,347]
+	}
+	,{
+		Warps:[253,311,321,344]
+	}
+	,{
+		Warps:[293,290]
+	}
+	,{
+		Warps:[292,424,243]
+	}
+	,{
+		Warps:[485]
+	}
+	,{
+		Warps:[272,296,297]
+	}
+	,{
+		Warps:[295,195]
+	}
+	,{
+		Warps:[208,268,295]
+	}
+	,{
+		Warps:[296]
+	}
+	,{
+		Warps:[271,354,300]
+	}
+	,{
+		Warps:[337,348,299]
+	}
+	,{
+		Warps:[287,284,303,324,313]
+	}
+	,{
+		Warps:[282,376,305]
+	}
+	,{
+		Warps:[284,305,327,301]
+	}
+	,{
+		Warps:[193,374,326]
+	}
+	,{
+		Warps:[302,303,372]
+	}
+	,{
+		Warps:[277,309,310,307,398]
+	}
+	,{
+		Warps:[306,382,416,308]
+	}
+	,{
+		Warps:[307,416,378,280]
+	}
+	,{
+		Warps:[368,281,306]
+	}
+	,{
+		Warps:[1,306,382]
+	}
+	,{
+		Warps:[291,312,317]
+	}
+	,{
+		Warps:[317,311,314]
+	}
+	,{
+		Warps:[330,301,386]
+	}
+	,{
+		Warps:[312,351,254,316]
+	}
+	,{
+		Warps:[255,334]
+	}
+	,{
+		Warps:[314,318]
+	}
+	,{
+		Warps:[311,312,320,322,426]
+	}
+	,{
+		Warps:[425,316,319]
+	}
+	,{
+		Warps:[318,427,361]
+	}
+	,{
+		Warps:[317,394]
+	}
+	,{
+		Warps:[291,323]
+	}
+	,{
+		Warps:[317,391,362]
+	}
+	,{
+		Warps:[321,426,338,342,341]
+	}
+	,{
+		Warps:[301,327,395]
+	}
+	,{
+		Warps:[327,397,1,372]
+	}
+	,{
+		Warps:[304,369,364]
+	}
+	,{
+		Warps:[303,325,396,324]
+	}
+	,{
+		Warps:[287,363,330]
+	}
+	,{
+		Warps:[363,283]
+	}
+	,{
+		Warps:[328,385,313]
+	}
+	,{
+		Warps:[130]
+	}
+	,{
+		Warps:[94]
+	}
+	,{
+		Warps:[195]
+	}
+	,{
+		Warps:[315,349,335]
+	}
+	,{
+		Warps:[337,334]
+	}
+	,{
+		Warps:[356,1,337]
+	}
+	,{
+		Warps:[336,335,300]
+	}
+	,{
+		Warps:[391,323,339]
+	}
+	,{
+		Warps:[338,1,393,340]
+	}
+	,{
+		Warps:[339,342,343]
+	}
+	,{
+		Warps:[323,346,343]
+	}
+	,{
+		Warps:[323,340]
+	}
+	,{
+		Warps:[341,340,496,347]
+	}
+	,{
+		Warps:[346,345,492,291]
+	}
+	,{
+		Warps:[212,344]
+	}
+	,{
+		Warps:[344,341,347]
+	}
+	,{
+		Warps:[346,343,290]
+	}
+	,{
+		Warps:[271,349,300]
+	}
+	,{
+		Warps:[348,334,350]
+	}
+	,{
+		Warps:[349]
+	}
+	,{
+		Warps:[314]
+	}
+	,{
+		Warps:[270,494,353]
+	}
+	,{
+		Warps:[354,494,352]
+	}
+	,{
+		Warps:[353,355,299]
+	}
+	,{
+		Warps:[354,360,357,430]
+	}
+	,{
+		Warps:[357,336]
+	}
+	,{
+		Warps:[429,356,355]
+	}
+	,{
+		Warps:[490,359]
+	}
+	,{
+		Warps:[358,272]
+	}
+	,{
+		Warps:[355]
+	}
+	,{
+		Warps:[319,428]
+	}
+	,{
+		Warps:[322,392]
+	}
+	,{
+		Warps:[366,329,328,365]
+	}
+	,{
+		Warps:[326,371,372]
+	}
+	,{
+		Warps:[363,384]
+	}
+	,{
+		Warps:[281,367,286,363]
+	}
+	,{
+		Warps:[251,366]
+	}
+	,{
+		Warps:[309,383]
+	}
+	,{
+		Warps:[326,370,371]
+	}
+	,{
+		Warps:[219,414,369]
+	}
+	,{
+		Warps:[364,369,373]
+	}
+	,{
+		Warps:[325,305,364,373]
+	}
+	,{
+		Warps:[371,372,412]
+	}
+	,{
+		Warps:[228,304]
+	}
+	,{
+		Warps:[282]
+	}
+	,{
+		Warps:[302]
+	}
+	,{
+		Warps:[219]
+	}
+	,{
+		Warps:[308,380]
+	}
+	,{
+		Warps:[380,416,382,409,406]
+	}
+	,{
+		Warps:[378,416,379,402]
+	}
+	,{
+		Warps:[486,482]
+	}
+	,{
+		Warps:[307,310,379,409]
+	}
+	,{
+		Warps:[382,368,387]
+	}
+	,{
+		Warps:[365,385,387]
+	}
+	,{
+		Warps:[330,390,384]
+	}
+	,{
+		Warps:[399,388,417]
+	}
+	,{
+		Warps:[383,384,409,410]
+	}
+	,{
+		Warps:[386,417,418,408,390]
+	}
+	,{
+		Warps:[281]
+	}
+	,{
+		Warps:[385,388,407]
+	}
+	,{
+		Warps:[338,426,322,392]
+	}
+	,{
+		Warps:[362,393,391]
+	}
+	,{
+		Warps:[392,495,339]
+	}
+	,{
+		Warps:[428,320,493]
+	}
+	,{
+		Warps:[324,404]
+	}
+	,{
+		Warps:[327,397,405]
+	}
+	,{
+		Warps:[396,325,411,413]
+	}
+	,{
+		Warps:[280,306]
+	}
+	,{
+		Warps:[386]
+	}
+	,{
+		Warps:[150]
+	}
+	,{
+		Warps:[245]
+	}
+	,{
+		Warps:[380,431,403]
+	}
+	,{
+		Warps:[402,406]
+	}
+	,{
+		Warps:[395,405,422,421]
+	}
+	,{
+		Warps:[396,404,423]
+	}
+	,{
+		Warps:[379,409,410,435,403]
+	}
+	,{
+		Warps:[390,408,440]
+	}
+	,{
+		Warps:[388,407,441]
+	}
+	,{
+		Warps:[379,382,406,387]
+	}
+	,{
+		Warps:[406,436,387]
+	}
+	,{
+		Warps:[397,438,439]
+	}
+	,{
+		Warps:[373,413]
+	}
+	,{
+		Warps:[397,412,438]
+	}
+	,{
+		Warps:[370]
+	}
+	,{
+		Warps:[246,245,248,277,278,276]
+	}
+	,{
+		Warps:[308,307,380,379]
+	}
+	,{
+		Warps:[388,386,420,419]
+	}
+	,{
+		Warps:[388,419,432]
+	}
+	,{
+		Warps:[418,417,433]
+	}
+	,{
+		Warps:[417,421]
+	}
+	,{
+		Warps:[420,404,434]
+	}
+	,{
+		Warps:[404,423,437]
+	}
+	,{
+		Warps:[405,422,439]
+	}
+	,{
+		Warps:[293]
+	}
+	,{
+		Warps:[318]
+	}
+	,{
+		Warps:[317,391,323]
+	}
+	,{
+		Warps:[319,428]
+	}
+	,{
+		Warps:[427,394,361]
+	}
+	,{
+		Warps:[357]
+	}
+	,{
+		Warps:[355]
+	}
+	,{
+		Warps:[402,445,435]
+	}
+	,{
+		Warps:[418,453,433]
+	}
+	,{
+		Warps:[432,419,434,452]
+	}
+	,{
+		Warps:[421,433]
+	}
+	,{
+		Warps:[406,447,431]
+	}
+	,{
+		Warps:[410,440]
+	}
+	,{
+		Warps:[422,451,443]
+	}
+	,{
+		Warps:[413,411]
+	}
+	,{
+		Warps:[423,411,443]
+	}
+	,{
+		Warps:[407,441,448,436]
+	}
+	,{
+		Warps:[408,446,449,440]
+	}
+	,{
+		Warps:[115]
+	}
+	,{
+		Warps:[461,437,439]
+	}
+	,{
+		Warps:[275,185]
+	}
+	,{
+		Warps:[431,457]
+	}
+	,{
+		Warps:[441,450]
+	}
+	,{
+		Warps:[435,459,458]
+	}
+	,{
+		Warps:[440,469,487,459]
+	}
+	,{
+		Warps:[441,450]
+	}
+	,{
+		Warps:[446,449,468]
+	}
+	,{
+		Warps:[437,455,467,461]
+	}
+	,{
+		Warps:[433,453,455,460]
+	}
+	,{
+		Warps:[432,452,454]
+	}
+	,{
+		Warps:[453,480]
+	}
+	,{
+		Warps:[452,451,456]
+	}
+	,{
+		Warps:[466,455,467]
+	}
+	,{
+		Warps:[445,465,462]
+	}
+	,{
+		Warps:[447,487,464]
+	}
+	,{
+		Warps:[447,448]
+	}
+	,{
+		Warps:[452]
+	}
+	,{
+		Warps:[451,443,483]
+	}
+	,{
+		Warps:[457,463,471]
+	}
+	,{
+		Warps:[464,462,473]
+	}
+	,{
+		Warps:[463,458,472]
+	}
+	,{
+		Warps:[457]
+	}
+	,{
+		Warps:[481,456]
+	}
+	,{
+		Warps:[456,451,483,482]
+	}
+	,{
+		Warps:[475,450]
+	}
+	,{
+		Warps:[448,478,470]
+	}
+	,{
+		Warps:[477,469,475]
+	}
+	,{
+		Warps:[289,462]
+	}
+	,{
+		Warps:[473,464,477,488]
+	}
+	,{
+		Warps:[463,472]
+	}
+	,{
+		Warps:[279,486]
+	}
+	,{
+		Warps:[489,470,476]
+	}
+	,{
+		Warps:[475,479]
+	}
+	,{
+		Warps:[487,472,470]
+	}
+	,{
+		Warps:[469]
+	}
+	,{
+		Warps:[490,480,476]
+	}
+	,{
+		Warps:[454,481,479]
+	}
+	,{
+		Warps:[480,466,484]
+	}
+	,{
+		Warps:[484,467,381]
+	}
+	,{
+		Warps:[467,461,485]
+	}
+	,{
+		Warps:[481,482,279]
+	}
+	,{
+		Warps:[483,294]
+	}
+	,{
+		Warps:[474,381]
+	}
+	,{
+		Warps:[458,448,477]
+	}
+	,{
+		Warps:[472,489]
+	}
+	,{
+		Warps:[488,475]
+	}
+	,{
+		Warps:[358,479,279]
+	}
+	,{
+		Warps:[49]
+	}
+	,{
+		Warps:[253,344,212]
+	}
+	,{
+		Warps:[394]
+	}
+	,{
+		Warps:[353,352,270,271]
+	}
+	,{
+		Warps:[393]
+	}
+	,{
+		Warps:[343]
+	}
+	,{
+		Warps:[157,93]
+	}
+	,{
+		Warps:[51]
+	}
+	,{
+		Warps:[65]
+	}
+	,{
+		Warps:[39]
+	}
+];
diff --git a/xtrn/tw2/structs.js b/xtrn/tw2/structs.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ed1d3b3ce5a19f489a47dbe57fb14a6efc7015a
--- /dev/null
+++ b/xtrn/tw2/structs.js
@@ -0,0 +1,317 @@
+var PlayerProperties=[
+			{
+				 prop:"UserNumber"
+				,name:"User Number"
+				,type:"Integer"
+				,def:(user == undefined?0:user.number)
+			}
+			,{
+				 prop:"Points"
+				,name:"Pointes"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Alias"
+				,name:"Alias"
+				,type:"String:42"
+				,def:(user == undefined?"":user.alias)
+			}
+			,{
+				 prop:"LastOnDay"
+				,name:"Date Last On"
+				,type:"Date"
+				,def:system.datestr()
+			}
+			,{
+				 prop:"KilledBy"
+				,name:"Killed By"
+				,type:"SignedInteger"
+				,def:0
+			}
+			,{
+				 prop:"TurnsLeft"
+				,name:"Turns Remaining"
+				,type:"Integer"
+				,def:Settings.TurnsPerDay
+			}
+			,{
+				 prop:"Sector"
+				,name:"Sector"
+				,type:"Integer"
+				,def:1
+			}
+			,{
+				 prop:"Fighters"
+				,name:"Fighters"
+				,type:"Integer"
+				,def:Settings.StartingFighters
+			}
+			,{
+				 prop:"Holds"
+				,name:"Holds"
+				,type:"Integer"
+				,def:Settings.StartingHolds
+			}
+			,{
+				 prop:"Commodities"
+				,name:"Commodities"
+				,type:"Array:3:Integer"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"Credits"
+				,name:"Credits"
+				,type:"Integer"
+				,def:Settings.StartingCredits
+			}
+			,{
+				 prop:"TeamNumber"
+				,name:"Team Number"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"LastIn"
+				,name:"Sector Last In"
+				,type:"Integer"
+				,def:1
+			}
+			,{
+				 prop:"Online"
+				,name:"Online"
+				,type:"Boolean"
+				,def:false
+			}
+			,{
+				 prop:"Ported"
+				,name:"Ported"
+				,type:"Boolean"
+				,def:false
+			}
+			,{
+				 prop:"Landed"
+				,name:"Landed"
+				,type:"Boolean"
+				,def:false
+			}
+		];
+
+var SectorProperties = [
+			{
+				 prop:"Warps"
+				,name:"Warps"
+				,type:"Array:6:Integer"
+				,def:[0,0,0,0,0,0]
+			}
+			,{
+				 prop:"Port"
+				,name:"Port"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Planet"
+				,name:"Planet"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Fighters"
+				,name:"Fighters"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"FighterOwner"
+				,name:"Fighters Owner"
+				,type:"SignedInteger"
+				,def:0
+			}
+		];
+
+var PortProperties = [
+			{
+				 prop:"Name"
+				,name:"Name"
+				,type:"String:42"
+				,def:""
+			}
+			,{
+				 prop:"Class"
+				,name:"Class"
+				,type:"Integer"
+				,def:""
+			}
+			,{
+				 prop:"Commodities"
+				,name:"Commodities"
+				,type:"Array:3:Float"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"Production"
+				,name:"Production (units/day)"
+				,type:"Array:3:SignedInteger"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"PriceVariance"
+				,name:"Price Variance (percentage)"
+				,type:"Array:3:SignedInteger"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"LastUpdate"
+				,name:"Port last produced"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"OccupiedBy"
+				,name:"Occupied By"
+				,type:"Integer"
+				,def:0
+			}
+		];
+
+var PlanetProperties = [
+			{
+				 prop:"Name"
+				,name:"Name"
+				,type:"String:42"
+				,def:""
+			}
+			,{
+				 prop:"Created"
+				,name:"Planet has been created"
+				,type:"Boolean"
+				,def:false
+			}
+			,{
+				 prop:"Commodities"
+				,name:"Commodities"
+				,type:"Array:3:Float"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"Production"
+				,name:"Production (units/day)"
+				,type:"Array:3:SignedInteger"
+				,def:[0,0,0]
+			}
+			,{
+				 prop:"LastUpdate"
+				,name:"Planet last produced"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Sector"
+				,name:"Location of planet"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"OccupiedBy"
+				,name:"Occupied By"
+				,type:"Integer"
+				,def:0
+			}
+		];
+
+var PlayerMessageProperties = [
+			{
+				 prop:"Read"
+				,name:"Message has been read"
+				,type:"Boolean"
+				,def:true
+			}
+			,{
+				 prop:"To"
+				,name:"Player the message is to"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"From"
+				,name:"Player the message is from"
+				,type:"SignedInteger"
+				,def:0
+			}
+			,{
+				 prop:"Destroyed"
+				,name:"Number of Fighters Destroyed"
+				,type:"Integer"
+				,def:0
+			}
+		];
+
+var RadioMessageProperties = [
+			{
+				 prop:"Read"
+				,name:"Message has been read"
+				,type:"Boolean"
+				,def:false
+			}
+			,{
+				 prop:"To"
+				,name:"Player the message is to"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"From"
+				,name:"Player the message is from"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Message"
+				,name:"Test of the message"
+				,type:"String:74"
+				,def:""
+			}
+		];
+
+var TeamProperties = [
+			{
+				 prop:"Password"
+				,name:"Team Password"
+				,type:"String:4"
+				,def:""
+			}
+			,{
+				 prop:"Members"
+				,name:"Team Members"
+				,type:"Array:4:Integer"
+				,def:[0,0,0,0]
+			}
+			,{
+				 prop:"Size"
+				,name:"Number of members"
+				,type:"Integer"
+				,def:0
+			}
+		];
+
+var CabalProperties = [
+			{
+				 prop:"Sector"
+				,name:"Sector"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Size"
+				,name:"Size"
+				,type:"Integer"
+				,def:0
+			}
+			,{
+				 prop:"Goal"
+				,name:"Goal"
+				,type:"Integer"
+				,def:0
+			}
+		];
diff --git a/xtrn/tw2/tw2.js b/xtrn/tw2/tw2.js
new file mode 100644
index 0000000000000000000000000000000000000000..7410b1a9e2b39af65afe9a19183a5441b58d2e5d
--- /dev/null
+++ b/xtrn/tw2/tw2.js
@@ -0,0 +1,2301 @@
+load("recordfile.js");
+load("lockfile.js");
+load("../xtrn/tw2/filename.js");
+load(fname("gamesettings.js"));
+var Settings=new GameSettings();
+
+load(fname("structs.js"));
+
+var on_at=time();
+var i;
+
+var Commodities=[
+	{
+		 name:"Ore"
+		,abbr:"Ore"
+		,disp:"Ore......."
+		,price:10
+	}
+	,{
+		 name:"Organics"
+		,abbr:"Org"
+		,disp:"Organics.."
+		,price:20
+	}
+	,{
+		 name:"Equipment"
+		,abbr:"Equ"
+		,disp:"Equipment."
+		,price:35
+	}
+];
+
+var sectors=new RecordFile(fname("sectors.dat"), SectorProperties);
+var ports=new RecordFile(fname("ports.dat"), PortProperties);
+var players=new RecordFile(fname("players.dat"), PlayerProperties);
+var teams=new RecordFile(fname("teams.dat"), TeamProperties);
+var planets=new RecordFile(fname("planets.dat"), PlanetProperties);
+var twmsg=new File(fname("twmesg.dat"));
+var twopeng=new File(fname("twopeng.dat"));
+twopeng.open("a", true);
+twmsg.open("a", true);
+var twpmsg=new RecordFile(fname("twpmesg.dat"), PlayerMessageProperties);
+var twrmsg=new RecordFile(fname("twrmesg.dat"), RadioMessageProperties);
+var cabals=new RecordFile(fname("cabal.dat"), CabalProperties);
+
+var today=system.datestr(system.datestr());
+
+js.on_exit("do_exit()");
+/* Run maintenance */
+if(Settings.MaintLastRan != system.datestr()) {
+	Settings.MaintLastRan = system.datestr();
+	Settings.save();
+	console.attributes="Y";
+	console.writeln("Running maintence program...");
+	console.crlf();
+	console.crlf();
+	console.writeln("Trade Wars maintence program");
+	console.writeln("  by Chris Sherrick (PTL)");
+	console.crlf();
+	console.writeln("This program is run once per day.");
+	twmsg.writeln(system.timestr()+": "+user.alias+": Maintence program ran");
+	console.writeln("Deleting inactive players");
+
+	var oldest_allowed=today-Settings.DaysInactivity*86400;
+	for(i=1; i<players.length; i++) {
+		var p=players.Get(i);
+		if(p.UserNumber > 0) {
+			if(system.datestr(p.LastOnDay) < oldest_allowed) {
+				p.UserNumber=0;
+				twmsg.writeln("  - "+playerlist[player]+" deleted from game");
+			}
+		}
+	}
+	console.crlf();
+	MoveCabal();
+
+	RankPlayers();
+}
+
+console.attributes="C";
+console.crlf();
+console.crlf();
+console.center("Trade Wars (v.ii)");
+console.center("By Chris Sherrick (PTL)");
+console.center("Copyright 1986 Chris Sherrick");
+console.crlf();
+console.center(system.name);
+console.center("Sysop  "+system.operator);
+console.crlf();
+console.crlf();
+console.printfile(fname("twopeng.asc"));
+if(file_exists(fname("twopeng.dat")))
+	console.printfile(fname("twopeng.dat"));
+console.crlf();
+console.attributes="W";
+console.writeln("Initializing...");
+console.writeln("Searching my records for your name.");
+var player;
+var firstnew;
+for(i=1; i<players.length; i++) {
+	player=players.Get(i);
+	if(player.UserNumber==0 && firstnew==undefined)
+		firstnew=player;
+	if(player.UserNumber == user.number)
+		break;
+}
+if(player==undefined || player.UserNumber!=user.number) {
+	console.attributes="G";
+	console.writeln("I can't find your record, so I am assuming you are a new player.");
+	console.attributes="M";
+	console.writeln("Entering a new player...");
+	player=firstnew;
+	if(player==undefined) {
+		console.writeln("I'm sorry but the game is full.");
+		console.writeln("Please leave a message for the Sysop so");
+		console.writeln("he can save a space for you when one opens up.");
+		twmsg.writeln(system.timestr()+": New player not allowed - game full.");
+		exit(0);
+	}
+	console.crlf();
+	console.writeln("Notice: If you don't play this game for "+Settings.DaysInactivity+" days, you will");
+	console.writeln("be deleted to make room for someone else.");
+	console.crlf();
+	console.writeln("Your ship is being initialized.");
+
+	/* Lock the player file and mark us online... */
+	if(!Lock(players.file.name, bbs.node_num, true, 10)) {
+		console.writeln("!!!Unable to lock player data!");
+		twmsg.writeln("!!!Unable to lock player data!");
+		exit(1);
+	}
+	player.ReInit();
+	player.Online=true;
+	player.Put();
+	Unlock(players.file.name);
+
+	twmsg.writeln(system.timestr()+" "+user.alias+": New Player logged on");
+	Instructions();
+}
+else {
+	/* Lock the player file and mark us online... */
+	if(!Lock(players.file.name, bbs.node_num, true, 10)) {
+		console.writeln("!!!Unable to lock player data!");
+		twmsg.writeln("!!!Unable to lock player data!");
+		exit(1);
+	}
+	player.Online=true;
+	player.Put();
+	Unlock(players.file.name);
+
+	console.crlf();		/* TODO: BASIC magic... N$ appears empty tw2.bas: 242 */
+	twmsg.writeln(system.timestr()+" "+user.alias+": Logged on");
+	if(today < system.datestr(player.LastOnDay)) {
+		console.writeln("I'm sorry, but you won't be allowed on for another " + parseInt((system.datestr(player.LastOnDay)-today)/86400) + " day(s)");
+		exit(0);
+	}
+	if(today==system.datestr(player.LastOnDay)) {
+		if(player.KilledBy != -99) {
+			console.writeln("You have been on today.");
+			if(player.TurnsLeft<1) {
+				console.writeln("You don't have any turns left today. You will be allowed to play tomorrow.");
+				exit(0);
+			}
+			if(player.KilledBy==user.number) {
+				console.writeln("You killed yourself today. You will be allowed to play tomorrow.");
+				exit(0);
+			}
+			console.writeln("The following happened to your ship since your last time on:");
+			var count=0;
+			for(i=0; i<twpmsg.length; i++) {
+				var msg=twpmsg.Get(i);
+
+				if(msg.To==user.number && !msg.Read) {
+					count++;
+					if(msg.From==-98)
+						console.writeln("A deleted player destroyed "+msg.Destroyed+" fighters.");
+					else if(msg.From==-1) {
+						console.attributes="R";
+						console.writeln("The Cabal destroyed "+msg.Destroyed+" fighters.");
+					}
+					else {
+						var otherplayer=players.Get(msg.From);
+
+						console.writeln(otherplayer.Alias+" "+(otherplayer.TeamNumber?" Team["+otherplayer.TeamNumber+"] ":"")+"destroyed "+msg.Destroyed+" of your fighters.");
+					}
+					msg.Read=true;
+					msg.Put();
+				}
+			}
+			if(count==0)
+				console.writeln("Nothing");
+		}
+	}
+	else {
+		player.TurnsLeft=Settings.TurnsPerDay;
+	}
+	player.LastOnDay=system.datestr();
+	if(player.KilledBy != 0) {
+		switch(player.KilledBy) {
+			case user.number:
+				console.attributes="R";
+				console.writeln("You managed to kill yourself on your last time on.");
+				break;
+			case -1:
+				console.attributes="R";
+				console.writeln("You have been killed by the Cabal!");
+				break;
+			case -98:
+				console.writeln("You have been killed by a deleted player.");
+				break;
+			default:
+				var otherplayer=players.Get(player.KilledBy);
+
+				console.writeln(otherplayer.Alias+" destroyed your ship!");
+				break;
+		}
+		player.ReInit();
+	}
+}
+
+ReadRadio();
+if(player.Sector < 1 || player.Sector >= sectors.length) {
+	console.writeln("You are being moved to sector 1");
+	player.Sector=1;
+}
+if(player.Credits > 25000) {
+	console.crlf();
+	console.writeln("Tax time! You are being taxed 5000 credits to help support the resistance");
+	console.writeln("against the evil Cabal.");
+	player.Credits -= 5000;
+}
+
+var exit_tw2=false;
+
+while(player.KilledBy==0 && exit_tw2==false) {
+	if(EnterSector()) {
+		if(CheckSector())
+			Menu();
+	}
+}
+
+function Menu()
+{
+	/* 22000 */
+	while(1) {
+		console.crlf();
+		console.attributes="C";
+		console.write("Command (?=Help)? ");
+		switch(GetKeyEcho()) {
+			case '':
+				console.writeln("? = Help");
+				break;
+			case 'A':
+				/* 25000 */
+				console.writeln("<Attack>");
+				var count=0;
+				var i;
+
+				if(player.Fighters < 1) {
+					console.writeln("You don't have any fighters.");
+					break;
+				}
+				for(i=1;i<players.length; i++) {
+					var otherplayer=players.Get(i);
+					if(otherplayer.Sector==player.Sector
+							&& otherplayer.Record!=player.Record
+							&& otherplayer.KilledBy!=0
+							&& otherplayer.UserNumber!=0
+							&& !otherplayer.Online) {
+						count++;
+						console.write("Attack "+otherplayer.Alias+" (Y/N)[Y]? ");
+						if(GetKeyEcho()!='N') {
+							console.writeln("<Yes>");
+							break;
+						}
+					}
+					otherplayer=null;
+				}
+				if(otherplayer!=null) {
+					DoBattle(otherplayer, otherplayer.TeamNumber > 0);
+					if(otherplayer.Fighters==0) {
+						KilledBy(otherplayer, player, true);
+						/* 15600 player salvages ship from otherplayer */
+						var salvaged=parseInt(otherplayer.Holds/4)+1;
+						if(player.Holds + salvaged > 50)
+							salvaged=50-player.Holds;
+						if(salvaged < 1)
+							console.writeln("You destroyed the ship, but you can't salvage anything from it");
+						else {
+							var j;
+
+							console.writeln("You destroyed the ship and salvaged these cargo holds:");
+							var holds=new Array(Commodities.length+1);
+							for(i=0; i<holds.length+1; i++)
+								holds[i]=0;
+							for(i=0; i<otherplayer.Holds; i++) {
+								var limit=0;
+								var r=random(otherplayer.Holds)+1;
+								for(j=0; j<Commodities.length; j++) {
+									limit += otherplayer.Commodities[j];
+									if(r<limit) {
+										otherplayer.Commodities[j]--;
+										holds[j]++;
+										r=0;
+										break;
+									}
+								}
+								if(r==0)
+									holds[Commodities.length]++;
+							}
+							if(holds[Commodities.length]>0) {
+								console.writeln("  "+holds[Commodities.length]+" empty.");
+								player.Holds+=holds[Commodities.length];
+							}
+							for(j=0; j<Commodities.length; j++) {
+								if(holds[j]>0) {
+									console.writeln("  "+holds[j]+" with "+Commodities[j].name.toLowerCase()+".");
+									player.Holds+=holds[j];
+									player.Commodities[j]+=holds[j];
+								}
+							}
+						}						
+					}
+				}
+				else {
+					if(count)
+						console.writeln("There are no other ships in here");
+					else
+						console.writeln("There are no ships here to attack.");
+				}
+				break;
+			case 'C':
+				/* 33640 */
+				console.writeln("<Computer>");
+				console.crlf();
+				console.attributes="W";
+				console.writeln("<Computer activated>");
+				var showhelp=true;
+				var exitcomputer=false;
+				while(!exitcomputer) {
+					if(showhelp) {
+						console.crlf();
+						console.attributes="W";
+						console.writeln("Computer commands:");
+						console.attributes="HK";
+						console.writeln("1)  Exit computer");
+						console.attributes="W";
+						console.writeln("2)  Port report");
+						console.attributes="G";
+						console.writeln("3)  Sector finder");
+						console.attributes="Y";
+						console.writeln("4)  Rank players");
+						console.attributes="HK";
+						console.writeln("5)  Send Message");
+					}
+					console.attributes="HC";
+					console.write("Computer command (?=help)? ");
+					switch(GetKeyEcho()) {
+						case '?':
+							showhelp=true;
+							break;
+						case '1':
+							/* 33990 */
+							console.crlf();
+							console.attributes="Y";
+							console.writeln("<Computer deactivated>");
+							exitcomputer=true;
+							break;
+						case '2':
+							/* 33780 */
+							console.write("What sector number is the port in? ");
+							var sec=console.getnum(sectors.length-1);
+							if(sec > 0 && sec < sectors.length) {
+								var sector=sectors.Get(sec);
+								if(sector.Port==0 || (sector.Fighters>0 && sector.Fighters!=player.Record)) {
+									console.crlf();
+									console.writeln("I have no information about that port.");
+									break;
+								}
+								if(sec==1) {
+									SolReport();
+								}
+								else {
+									PortReport(sector);
+								}
+							}
+							break;
+						case '3':
+							/* 33830 */
+							console.write("What sector do you want to get to? ");
+							var sec=console.getnum(sectors.length-1);
+							if(sec > 0 && sec < sectors.length) {
+								if(sec==player.Sector) {
+									console.writeln("You are in that sector.");
+									break;
+								}
+								console.crlf();
+								console.writeln("Computing shortest path.");
+								var path=ShortestPath(player.Sector, sec);
+								if(path==null) {
+									console.writeln("There was an error in computation between sectors.");
+								}
+								else {
+									console.writeln("The shortest path from sector "+player.Sector+" to sector "+sec+" is:");
+									var i;
+									for(i in path) {
+										if(i!=0) 
+											console.write(" - ");
+										console.write(path[i]);
+									}
+								}
+							}
+							break;
+						case '4':
+							/* 33900 */
+							console.crlf();
+							console.write("Ranking Players.");
+							var ranked=RankPlayers();
+							console.crlf();
+							console.writeln("Player Rankings: "+system.timestr());
+							console.writeln("Rank     Value      Team  Player");
+							console.writeln("==== ============= ====== ======")
+							for(rank in ranked) {
+								var p=players.Get(ranked[rank].Record);
+								console.writeln(format("%4d %13d %-6s %s"
+										,rank+1
+										,ranked[rank].Score
+										,p.TeamNumber==0?"":format("  %-2d  "
+										,p.TeamNumber),p.Alias));
+							}
+							break;
+						case '5':
+							/* 33960 */
+							console.crlf();
+							console.writeln("Warming up sub-space radio.");
+							mswait(500);
+							console.crlf();
+							console.write("Who do you wish to send this message to (search string)? ");
+							var sendto=console.getstr(42);
+							var p=MatchPlayer(sendto);
+							if(p==null)
+								break;
+							console.writeln("Tuning in to " + p.Alias + "'s frequency.");
+							console.crlf();
+							console.writeln("Due to the distances involved, messages are limited to 74 chars.");
+							console.writeln("Pressing [ENTER] with no input quits");
+							console.writeln("  [------------------------------------------------------------------------]");
+							console.write("? ");
+							var msg=console.getstr(74);
+							if(msg==null)
+								break;
+							msg=msg.replace(/\s*$/,'');
+							if(msg=='')
+								break;
+							RadioMessage(player.Record, p.Record, msg);
+							break;
+						default:
+							console.crlf();
+							console.writeln("Invalid command.  Enter ? for help");
+					}
+				}
+				break;
+			case 'D':
+				console.writeln("<Display>");
+				DisplaySector(player.Sector);
+				break;
+			case 'E':
+				/* TODO: 22800 */
+				if(user.level < 90)
+					break;
+				console.writeln("<TW Editor>");
+				console.write("Do you wish to use the editor? Y/N [N] ");
+				switch(GetKeyEcho()) {
+					case 'Y':
+						console.writeln("Running Tradewars ][ Editor...");
+						/* TODO: TWEdit */
+				}
+				break;
+			case 'F':
+				/* 24000 */
+				console.writeln("<Drop/Take Fighters>");
+				if(player.Sector < 8) {
+					console.writeln("You can't leave fighters in the Union (sectors 1-7)");
+					break;
+				}
+				var sector=sectors.Get(player.Sector);
+				if(sector.Fighters > 0 && sector.FighterOwner != player.Record) {
+					console.writeln("There are already fighters in this sector!");
+					break;
+				}
+				console.writeln("You have " + (player.Fighters+sector.Fighters) + " fighters available.");
+				console.write("How many fighters do you want defending this sector? ");
+				var newf=player.Fighters+sector.Fighters;
+				if(newf > 9999)
+					newf=9999;
+				var newf=console.getnum(newf);
+				if(newf >= 0 && newf <=player.Fighters+sector.Fighters) {
+					if((player.Fighters+sector.Fighters)-newf > 9999) {
+						console.writeln("Too many ships in your fleet!  You are limited to 9999");
+						break;
+					}
+					player.Fighters=(player.Fighters+sector.Fighters)-newf;
+					sector.Fighters=newf;
+					if(sector.Fighters > 0)
+						sector.FighterOwner=player.Record;
+					sector.Put();
+					player.Put();
+					console.writeln("Done.  You have " + player.Fighters + " fighter(s) in your fleet.");
+				}
+				break;
+			case 'G':
+				/* 27500 */
+				console.writeln("<Gamble>");
+				console.writeln("You have "+player.Credits+" credits.");
+				console.writeln("How much do you want to gamble at double or nothing (50-50 odds)");
+				console.write("[0]? ");
+				var gamble=console.getnum(player.Credits > 99999?99999:player.Credits);
+				if(gamble > 0 && gamble <=player.Credits) {
+					console.write("Flipping the coin...");
+					mswait(250);
+					if(random(2)==1) {
+						console.crlf();
+						player.Credits-=gamble;
+						console.writeln("Sorry, you lost.");
+					}
+					else {
+						console.crlf();
+						player.Credits+=gamble;
+						console.writeln("You won!");
+					}
+					player.Put();
+					console.writeln("You now have "+player.Credits+" credits.");
+				}
+				break;
+			case 'I':
+				console.writeln("<Info>");
+				PlayerInfo(player.Record);
+				break;
+			case 'L':
+				/* 31000 */
+				console.writeln("<Land/Create planet>");
+				console.crlf();
+				console.attributes="Y";
+				console.writeln("Landing...");
+				var sector=sectors.Get(player.Sector);
+				var planet=null;
+				if(sector.Planet==0) {
+					/* TODO: Race condition? */
+					CreatePlanet(sector);
+				}
+				else {
+					/* 32310 */
+					/* Lock the planet file and ensure we can land... */
+					if(!Lock(planets.file.name, bbs.node_num, true, 5)) {
+						console.writeln("The spaceport is busy.  Try again later.");
+						break;
+					}
+					planet=planets.Get(sector.Planet);
+					if(planet.OccupiedBy != 0) {
+						console.writeln("The spaceport is busy.  Try again later.");
+						Unlock(planets.file.name);
+						break;
+					}
+					planet.OccupiedBy=player.Record;
+					planet.Put();
+					Unlock(ports.file.name);
+					player.Landed=true;
+					player.Put();
+
+					Production(planet);
+					PlanetReport(planet);
+					PlanetMenu(planet);
+
+					if(!Lock(planets.file.name, bbs.node_num, true, 10))
+						twmsg.writeln("!!! Error locking ports file!");
+					planet.OccupiedBy=0;
+					planet.Put();
+					Unlock(planets.file.name);
+					player.Landed=false;
+					player.Put();
+				}
+				break;
+			case 'M':
+				/* 23000 */
+				console.writeln("<Move>");
+				if(player.TurnsLeft < 1) {
+					console.writeln("I'm sorry but you don't have any turns left.");
+					break;
+				}
+				console.write("Warps lead to: ");
+				var sector=sectors.Get(player.Sector);
+				var i;
+				var count=0;
+				for(i=0; i<sector.Warps.length; i++) {
+					if(sector.Warps[i]>0) {
+						if(count>0)
+							console.write(", ");
+						console.write(sector.Warps[i]);
+						count++;
+					}
+				}
+				console.crlf();
+				console.write("To which sector? ");
+				var to=console.getnum(sectors.length-1);
+				if(to > 0) {
+					for(i=0; i<sector.Warps.length; i++) {
+						if(sector.Warps[i]==to) {
+							player.TurnsLeft--;
+							player.LastIn=player.Sector;
+							player.Sector=to;
+							player.Put();
+							if(player.TurnsLeft==10 || player.TurnsLeft < 6) {
+								console.writeln("You have " + player.TurnsLeft + " turns left.");
+							}
+							return;
+						}
+					}
+					console.writeln("You can't get there from here.");
+				}
+				break;
+			case 'P':
+				console.writeln("<Port>");
+				console.attributes="Y";
+				console.crlf();
+				console.writeln("Docking...");
+				if(player.TurnsLeft<1) {
+					console.writeln("Sorry, but you don't have any turns left.");
+					break;
+				}
+				var sector=sectors.Get(player.Sector);
+				if(sector.Port<1) {
+					console.writeln("There are no ports in this sector.");
+					break;
+				}
+				player.TurnsLeft--;
+				player.Ported=true;
+				player.Put();
+				console.writeln("One turn deducted");
+				if(player.Sector==1) {
+					/* 33200 */
+					var prices=SolReport();
+					console.writeln("You have " + player.Credits + " credits.");
+					console.crlf();
+					/* Holds */
+					var maxbuy=parseInt(player.Credits/prices[0]);
+					if(player.Holds+maxbuy>50)
+						maxbuy=50-player.Holds;
+					if(maxbuy > 0) {
+						console.write("How many holds do you want to buy [0]? ");
+						var buy=console.getnum(maxbuy);
+						if(buy>0) {
+							player.Holds+=buy;
+							player.Credits -= buy*prices[0];
+							player.Put();
+							console.writeln("You have " + player.Credits + " credits.");
+						}
+					}
+					/* Fighters */
+					var maxbuy=parseInt(player.Credits/prices[1]);
+					if(player.Fighters+maxbuy>9999)
+						maxbuy=9999-player.Fighters;
+					if(maxbuy > 0) {
+						console.write("How many fighters do you want to buy [0]? ");
+						var buy=console.getnum(maxbuy);
+						if(buy>0) {
+							player.Fighters+=buy;
+							player.Credits -= buy*prices[1];
+							player.Put();
+							console.writeln("You have " + player.Credits + " credits.");
+						}
+					}
+					/* Turns */
+					var maxbuy=parseInt(player.Credits/prices[2]);
+					if(maxbuy > 0) {
+						console.write("How many turns do you want to buy [0]? ");
+						var buy=console.getnum(maxbuy);
+						if(buy>0) {
+							player.TurnsLeft+=buy;
+							player.Credits -= buy*prices[2];
+							player.Put();
+							console.writeln("You have " + player.Credits + " credits.");
+						}
+					}
+				}
+				else {
+					var sector=sectors.Get(player.Sector);
+					
+					/* Lock the port file and ensure we can dock... */
+					if(!Lock(ports.file.name, bbs.node_num, true, 5)) {
+						console.writeln("The port is busy.  Try again later.");
+						break;
+					}
+					var port=ports.Get(sector.Port);
+					if(port.OccupiedBy != 0) {
+						console.writeln("The port is busy.  Try again later.");
+						Unlock(ports.file.name);
+						break;
+					}
+					port.OccupiedBy=player.Record;
+					port.Put();
+					Unlock(ports.file.name);
+					Production(port);
+					var sale=PortReport(sector);
+					var count=0;
+
+					console.writeln();
+
+					/* Sell... */
+					for(i=0; i<Commodities.length; i++) {
+						if(sale[i].Vary < 0) {
+							var amount=Transact(i, sale[i].Price, sale[i].Vary, sale[i].Number);
+							if(amount >= 0) {
+								count++;
+								port.Commodities[i] += amount;
+								port.Put();
+							}
+						}
+					}
+					/* Buy... */
+					for(i=0; i<Commodities.length; i++) {
+						if(sale[i].Vary > 0) {
+							var amount=Transact(i, sale[i].Price, sale[i].Vary, sale[i].Number);
+							if(amount >= 0) {
+								count++;
+								port.Commodities[i] -= amount;
+								port.Put();
+							}
+						}
+					}
+					if(count==0) {
+						console.attributes="IC";
+						console.writeln("You don't have anything they want, and they don't have anything you can buy");
+						console.attributes="C";
+					}
+
+					if(!Lock(ports.file.name, bbs.node_num, true, 10))
+						twmsg.writeln("!!! Error locking ports file!");
+					port.OccupiedBy=0;
+					port.Put();
+					Unlock(ports.file.name);
+				}
+				player.Ported=false;
+				player.Put();
+				break;
+			case 'T':
+				/* 32799 */
+				console.attributes="HK";
+				console.writeln("<Team menu>");
+				TeamMenu();
+				break;
+			case '?':
+				console.attributes="C";
+				console.writeln("<Help>");
+				console.crlf();
+				console.writeln("A - <A>ttack a player's ship");
+				console.writeln("C - <C>omputer");
+				console.writeln("D - re<D>isplay sector");
+				if(user.level >= 90)
+					console.writeln("E - Tradewars <E>ditor");
+				console.writeln("F - take or leave <F>ighters");
+				console.writeln("G - <G>amble");
+				console.writeln("I - <I>nfo on your ship");
+				console.writeln("L - <L>and on or create a planet.");
+				console.writeln("M - <M>ove to another sector");
+				console.writeln("P - land at a space <P>ort (and trade)");
+				console.writeln("Q - <Q>uit game");
+				console.writeln("T - <T>eam menu");
+				console.writeln("Z - instructions");
+				break;
+
+			case 'Z':
+				console.writeln("<Instructions>");
+				Instructions();
+				break;
+			case 'Q':
+				console.attributes="W";
+				console.writeln("<Quit>");
+				console.attributes="W";
+				console.write("Are you sure (Y/N)? ");
+				if(console.getkeys("YN")=='Y') {
+					exit_tw2=true;
+					return;
+				}
+				break;
+		}
+	}
+}
+
+function CheckSector()
+{
+	if(player.Sector==85) {
+		console.crlf();
+		console.attributes="W";
+		console.writeln("Congratulations!  You've defeated the cabal and gained 100,000 points!");
+		player.Points += 100000;
+		player.Put();
+		console.writeln("Unfortunately, victory is fleeting...");
+
+		var sector=sectors.Get(85);
+		sector.Fighters=3000;
+		sector.FighterOwner=-1;
+		sector.Put();
+		twopeng.writeln("Congratulations go to "+player.Alias+
+           " who invaded the Cabal empire on " + system.datestr() + 
+		   " and received 100,000 points!");
+		return(false);
+	}
+	return(true);
+}
+
+function EnterSector()	/* 20000 */
+{
+	var sector=sectors.Get(player.Sector);
+	var fighterteam=-1;
+
+	console.attributes="Y";
+	DisplaySector(sector.Record);
+	if(sector.FighterOwner > 0) {
+		var otherplayer=players.Get(sector.FighterOwner);
+		if(otherplayer.TeamNumber > 0)
+			fighterteam=otherplayer.TeamNumber;
+	}
+	while(sector.FighterOwner != player.Record && sector.Fighters > 0 && fighterteam != player.TeamNumber) {
+		console.writeln("You have to destroy the fighters before you can enter this sector.");
+		console.writeln("Fighters: "+player.Fighters+" / "+sector.Fighters);
+		console.write("Option? (A,D,I,Q,R,?):? ");
+		switch(GetKeyEcho()) {
+			case 'A':
+				console.writeln("<Attack>");
+				var otherteam=false;
+
+				if(sector.FighterOwner > 0) {
+					var otherplayer=players.Get(sector.FighterOwner);
+					if(otherplayer.TeamNumber>0)
+						otherteam-true;
+				}
+				var killed=DoBattle(sector, otherteam);
+				if(killed > 0) {
+					player.Points+=k*100;
+					console.writeln("You just recieved "+(k*100)+" points for that.");
+				}
+				if(sector.Fighters==0)
+					console.writeln("You destroyed all the fighters.");
+				break;
+			case 'D':
+				console.writeln("<Display>");
+				DisplaySector(player.Sector);
+				break;
+			case 'I':
+				console.writeln("<Info>");
+				PlayerInfo(player.Record);
+				break;
+			case 'Q':
+				console.write("Are you sure (Y/N)? ");
+				if(console.getkeys("YN")=='Y') {
+					exit_tw2=true;
+					return(false);
+				}
+				break;
+			case 'R':
+				console.writeln("<Retreat>");
+				if(player.LastIn<1 || player.LastIn>=sectors.length)
+					player.LastIn=random(sectors.length-1)+1;
+				if(player.Fighters<1) {
+					if(random(2)==1) {
+						console.writeln("You escaped!");
+						player.Sector=player.LastIn;
+						return(false);
+					}
+					console.attributes="R";
+					console.writeln("You didn't escape!");
+					console.writeln("Your ship has been destroyed!");
+					console.crlf();
+					console.attributes="R";
+					console.writeln("You will start over tomorrow with a new ship.");
+					KilledBy(player, player, true);
+					return(false);
+				}
+				else {
+					player.Fighters--;
+					console.writeln("You have "+player.Fighters+" fighter(s) left.");
+					player.Sector=player.LastIn;
+					return(false);
+				}
+				break;
+			case '':
+				console.writeln("?=<Help>");
+				break;
+			case '?':
+				console.writeln("<Help>");
+				console.crlf();
+				console.writeln("A - <A>ttack");
+				console.writeln("D - re<D>isplay sector");
+				console.writeln("I - <I>nformation about your ship");
+				console.writeln("Q - <Q>uit the game");
+				console.writeln("R - <R>etreat");
+				break;
+			default:
+				console.crlf();
+				console.writeln("Invalid command.  ? = Help");
+		}
+	}
+	return(true);
+}
+
+function PlayerInfo(num)
+{
+	var p=players.Get(num);
+
+	console.attributes="G";
+	console.write("Name: "+p.Alias);
+	if(p.PlayerNumber>0)
+		console.write("  Team ["+p.TeamNumber+"]");
+	console.crlf();
+	console.writeln("Sector: "+p.Sector+"   Turns left: "+p.TurnsLeft);
+	console.writeln("Fighters: "+p.Fighters);
+	console.writeln("Cargo Holds: "+p.Holds);
+	var i;
+	for(i=0; i<Commodities.length; i++)
+		console.write("  "+Commodities[i].abbr+": "+p.Commodities[i]+" ");
+	console.crlf();
+	console.writeln("Credits: "+p.Credits);
+	console.writeln("Door Monitor points: "+p.Points);
+}
+
+function DisplaySector(secnum)
+{
+	var sector=sectors.Get(secnum);
+	var i;
+	var count=0;
+
+	console.attributes="Y";
+	console.crlf();
+	console.writeln("Sector: "+secnum);
+	console.attributes="R";
+	console.write("Ports: ");
+	if(sector.Port > 0) {
+		var port=ports.Get(sector.Port);
+		console.write(port.Name+", class "+port.Class)
+	}
+	else
+		console.write("None");
+	console.crlf();
+	if(sector.Planet) {
+		var planet=planets.Get(sector.Planet);
+		console.writeln("Planet: "+planet.Name);
+	}
+	console.attributes="C";
+	console.write("Other Ships: ");
+	for(i=1;i<players.length;i++) {
+		var otherplayer=players.Get(i);
+
+		if(otherplayer.UserNumber > 0 && otherplayer.Sector==secnum) {
+			if(otherplayer.Record==player.Record)
+				continue;
+			if(otherplayer.KilledBy!=0)
+				continue;
+
+			count++;
+			console.crlf();
+			console.write("   "+otherplayer.Alias);
+			if(otherplayer.TeamNumber>0)
+				console.write("  Team ["+otherplayer.TeamNumber+"]");
+			console.write(" with "+otherplayer.Fighters+" fighters");
+			if(otherplayer.Landed)
+				console.write(" (on planet)");
+			else if(otherplayer.Ported)
+				console.write(" (docked)");
+			else if(otherplayer.Online)
+				console.write(" (online)");
+		}
+	}
+	if(count==0)
+		console.write("None");
+	console.crlf();
+	console.attributes="G";
+	console.write("Fighters in sector: ");
+	if(sector.Fighters==0)
+		console.writeln("None");
+	else {
+		console.write(sector.Fighters);
+		if(sector.FighterOwner<0)
+			console.writeln(" (Cabal)");
+		else if(sector.FighterOwner==player.Record)
+			console.writeln(" (yours)");
+		else {
+			var otherplayer=players.Get(sector.FighterOwner);
+			console.write(" (belong to "+otherplayer.Alias);
+			if(otherplayer.TeamNumber)
+				console.write("  Team ["+otherplayer.TeamNumber+"]")
+			console.writeln(")");
+		}
+	}
+	console.attributes="M";
+	console.write("Warps lead to: ");
+	count=0;
+	for(i=0; i<sector.Warps.length; i++) {
+		if(sector.Warps[i] != 0) {
+			if(count)
+				console.write(", ");
+			console.write(sector.Warps[i]);
+			count++;
+		}
+	}
+	console.attributes="W";
+	console.crlf();
+}
+
+function KilledBy(killed, killer, notify)	/* 15300 */
+{
+	var i;
+
+	killed.KilledBy=killer.Record;
+	killed.Put();
+
+	/* Destroy all deployed fighters */
+	for(i=1; i<sectors.length; i++) {
+		var sector=sectors.Get(i);
+		if(sector.FighterOwner==player.Record) {
+			sector.Fighters=0;
+			sector.FighterOwner=0;
+			sector.Put();
+		}
+	}
+
+	if(killed.TeamNumber > 0) {
+		var team=teams.Get(killed.TeamNumber);
+		var i;
+		for(i=0; i<team.Members.length; i++) {
+			if(team.Members[i]==killed.Record) {
+				team.Members[i]=0;
+				team.Size--;
+			}
+		}
+	}
+
+	if(notify)
+		twmsg.writeln(" - "+killer.Alias+"  killed "+killed.Alias);
+}
+
+function RankPlayers()
+{
+	var i;
+	var rank=new Array();
+	var fighters=new Array();
+
+	for(i=1; i<sectors.length; i++) {
+		var sector=sectors.Get(i);
+		if(sector.Fighters > 0 && sector.FighterOwner > 0) {
+			if(fighters[sector.FighterOwner]==undefined)
+				fighters[sector.FighterOwner]=0;
+			fighters[sector.FighterOwner]+=sector.Fighters;
+		}
+	}
+	for(i=1; i<players.length; i++) {
+		var p=players.Get(i);
+		if(p.UserNumber==0)
+			continue;
+		if(p.KilledBy!=0)
+			continue;
+		var robj=new Object();
+		robj.Record=p.Record;
+		robj.Score=p.Fighters*100 + p.Holds*500 + p.Credits;
+		for(i=0; i<Commodities.length; i++)
+			robj.Score += Commodities[i].price*p.Commodities[i];
+		if(fighters[i]!=undefined)
+			robj.Score += fighters[i]*100;
+		rank.push(robj);
+	}
+
+	function sortfunc(a,b) {
+		return(a.Score-b.Score);
+	}
+
+	rank.sort(sortfunc);
+	return(rank);
+}
+
+function TWRank()
+{
+	var rf=new File(fname(Settings.TopTenFile));
+	rf.open("w");
+	rf.writeln();
+	rf.writeln("  T R A D E W A R S   I I - 500T   S C O R E B O A R D  ");
+	rf.writeln();
+	rf.writeln("Last updated at: "+system.timestr());
+	rf.writeln();
+	rf.writeln("Player Rankings");
+	rf.writeln("Rank     Value      Team   Player");
+	rf.writeln("==== ============= ====== ================");
+	var ranked=RankPlayers();
+	var i;
+	var trank=new Object();
+
+	for(i=0; i<ranked.length; i++) {
+		var p=players.Get(ranked[i].Record);
+		if(i<10)
+			rf.writeln(format("%4d %13d %6s %s",(i+1),ranked[i].Score,p.TeamNumber==0?"":p.TeamNumber.toString(),p.Alias));
+		if(p.TeamNumber.toString() != 0) {
+			if(trank[p.TeamNumber.toString()]==undefined)
+				trank[p.TeamNumber.toString()]=0;
+			trank[p.TeamNumber.toString()]+=ranked[i].Score;
+		}
+	}
+	var tsort=new Array();
+	for(tr in trank) {
+		var ts=new Object();
+		ts.Record=tr;
+		ts.Score=trank[tr];
+		tsort.push(tr);
+	}
+	if(tsort.length > 0) {
+		function sortfunc(a,b) {
+			return(a.Score-b.Score);
+		}
+
+		tsort.sort(sortfunc);
+		rf.writeln();
+		rf.writeln("Team Rankings");
+		rf.writeln("Rank     Value      Team");
+		rf.writeln("==== ============= ======");
+		for(i=0; i<tsort.length; i++) {
+			if(i>=10)
+				break;
+			rf.writeln(format("%4d %13d %6d",(i+1),tsort[i].Score,tsort[i].Record));
+		}
+	}
+	rf.close();
+}
+
+function do_exit()
+{
+	player.Online=false;
+	player.Ported=false;
+	player.Landed=false;
+	player.Put();
+	console.writeln("Returning to Door monitor...");
+	TWRank();
+}
+
+function Instructions()
+{
+	console.write("Do you want instructions (Y/N) [N]? ");
+	switch(console.getkey().toUpperCase()) {
+		case 'Y':
+			console.crlf();
+			console.printfile(fname("twinstr.doc"));
+			break;
+	}
+}
+
+function DoBattle(opp, otherteam)
+{
+	if(player.Fighters<1) {
+		console.writeln("You don't have any fighters!");
+		return(0);
+	}
+	else {
+		console.write("How many fighters do you wish to use? ");
+		var use=console.getnum(player.Fighters);
+
+		if(use > 0 && use <= player.Fighters) {
+			var lost=0;
+			var killed=0;
+
+			player.Fighters -= use;
+			while(use && opp.Fighters) {
+				if(player.TeamNumber > 0 && otherteam) {
+					if((random(10)+1) > 6) {
+						opp.Fighters--;
+						killed++;
+					}
+					else {
+						use--;
+						lost++;
+					}
+				}
+				else if(otherteam && player.TeamNumber==0) {
+					if((random(10)+1) > 6) {
+						use--;
+						lost++;
+					}
+					else {
+						opp.Fighters--;
+						killed++;
+					}
+				}
+				else {
+					if(random(2)==0) {
+						use--;
+						lost++;
+					}
+					else {
+						opp.Fighters--;
+						killed++;
+					}
+				}
+			}
+			player.Fighters += use;
+			opp.Put();
+			player.Put();
+
+			console.writeln("You lost "+lost+" fighter(s), "+player.Fighters+" remain.");
+			if(opp.Fighters > 0)
+				console.write("You destroyed "+killed+" enemy fighters, "+opp.Fighters+" remain.");
+			else
+				console.write("You destroyed all of the enemy fighters.");
+			return(killed);
+		}
+	}
+	return(0);
+}
+
+function SolReport()
+{
+	var holdprice=parseInt(50*Math.sin(.89756*(today/86400)) + .5)+500;
+	var fighterprice=parseInt(10*Math.sin(.89714*(today/86400) + 1.5707) + .5)+100;
+	var turnprice=300;
+
+	console.writeln("Commerce report for Sol: " + system.timestr());
+	console.writeln("  Cargo holds: " + holdprice + " credits/hold");
+	console.writeln("  Fighters   : " + fighterprice + " credits/fighter");
+	console.writeln("  Turns      : "+turnprice+" credits each.");
+	console.crlf();
+
+	return([holdprice,fighterprice,turnprice]);
+}
+
+function Production(place)
+{
+	var newupd=time();
+	var diffdays=(newupd-place.LastUpdate)/86400;
+
+	if(diffdays>10)
+		diffdays=10;
+	for(i=0; i<Commodities.length; i++) {
+		if(diffdays > 0) {
+			place.Commodities[i] += place.Production[i]*diffdays;
+			if(place.Commodities[i] > place.Production[i]*10)
+				place.Commodities[i] = place.Production[i]*10;
+		}
+	}
+	place.LastUpdate=newupd;
+	place.Put();
+}
+
+function PortReport(sec) {
+	var port=ports.Get(sec.Port);
+	var i;
+
+	if(port==null)
+		return(null);
+	/* 33000 */
+	Production(port);
+	var ret=new Array(Commodities.length);
+	for(i=0; i<Commodities.length; i++) {
+		ret[i]=new Object();
+		ret[i].Vary=port.PriceVariance[i];
+		ret[i].Number=parseInt(port.Commodities[i]);
+		ret[i].Price=parseInt(Commodities[i].price*(1-ret[i].Vary*ret[i].Number/port.Production[i]/1000)+.5);
+	}
+	console.crlf();
+	console.writeln("Commerce report for "+port.Name+": "+system.timestr());
+	console.crlf();
+	console.writeln(" Items     Status   # units  in holds");
+	console.writeln(" =====     ======   =======  ========");
+	console.attributes="HK";
+	for(i=0; i<Commodities.length; i++) {
+		console.attributes=['R','G','Y','B','M','C','W'][i];
+		console.writeln(format("%s %-7s  %-7d  %-7d",
+				 Commodities[i].disp
+				,ret[i].Vary<0?"Buying":"Selling"
+				,ret[i].Number
+				,player.Commodities[i]));
+	}
+	return(ret);
+}
+
+function GetKeyEcho()
+{
+	var ret=console.getkey().toUpperCase();
+	if(ret=="\x0a" || ret=="\x0d")
+		ret='';
+	console.writeln(ret);
+	return(ret);
+}
+
+function ShortestPath(start, end)
+{
+	var i,j;
+	var hops=0;
+	var univ=new Array(sectors.length);
+	var done=false;
+	var ret=new Array();
+
+	function MarkWarps(univ, pos, end, hops)
+	{
+		var i;
+
+		for(i=0; i<univ[pos].Warps.length; i++) {
+			if(univ[pos].Warps[i]==0)
+				continue;
+			if(univ[univ[pos].Warps[i]]==undefined) {
+				univ[univ[pos].Warps[i]]=sectors.Get(univ[pos].Warps[i]);
+				univ[univ[pos].Warps[i]].hops=hops;
+				if(univ[pos].Warps[i]==end)
+					return(true);
+			}
+		}
+		return(false);
+	}
+
+	/* Do the expansion */
+	univ[start]=sectors.Get(start);
+	univ[start].hops=hops;
+	while(!done) {
+		for(i=1; i<sectors.length; i++) {
+			if(univ[i]!=undefined && univ[i].hops==hops) {
+				if(MarkWarps(univ, i, end, hops+1)) {
+					done=true;
+					break;
+				}
+			}
+		}
+		hops++;
+	}
+	ret.push(end);
+	for(i=end;i!=start;) {
+		var lasthop=i;
+		for(j=0; j<univ[i].Warps.length; j++) {
+			if(univ[univ[i].Warps[j]]!=undefined && univ[univ[i].Warps[j]].hops<univ[i].hops) {
+				i=univ[i].Warps[j];
+				if(i!=start)
+					ret.unshift(i);
+				break;
+			}
+		}
+		if(i==lasthop)
+			return(null);
+	}
+	return(ret);
+}
+
+function MatchPlayer(name)
+{
+	var i;
+
+	name=name.toUpperCase();
+	for(i=1; i<players.length; i++) {
+		var p=players.Get(i);
+		if(p.UserNumber==0)
+			continue;
+		if(p.KilledBy!=0)
+			continue;
+		if(p.Alias.toUpperCase().indexOf(name)!=-1) {
+			console.write(p.Alias+" (Y/N)[Y]? ");
+			switch(GetKeyEcho()) {
+				case 'N':
+					break;
+				default:
+					return(p);
+			}
+		}
+	}
+	console.writeln("Not found.");
+	return(null);
+}
+
+function RadioMessage(from, to, msg)
+{
+	var i;
+
+	var rmsg;
+	for(i=0; i<twrmsg.length; i++) {
+		var rmsg=twrmsg.Get(i);
+		if(rmsg.Read)
+			break;
+		rmsg=null;
+	}
+	if(rmsg==null)
+		rmsg=twrmsg.New();
+	rmsg.Read=false;
+	rmsg.From=from;
+	rmsg.To=to;
+	rmsg.Message=msg;
+	rmsg.Put();
+	console.writeln("Message sent.");
+	return;
+}
+
+function CreatePlanet(sector)
+{
+	console.writeln("There isn't a planet in this sector.");
+	console.writeln("Planets cost 10,000 credits.");
+	if(player.Credits < 10000) {
+		console.writeln("You're too poor to buy one.");
+		return;
+	}
+	console.writeln("You have " + player.Credits + " credits.");
+	console.write("Do you wish to buy a planet(Y/N) [N]? ");
+	switch(GetKeyEcho()) {
+		case 'Y':
+			var i;
+			var planet;
+			for(i=1; i<planets.length; i++) {
+				planet=planets.Get(i);
+				if(!planet.Created)
+					break;
+				planet=null;
+			}
+			if(planet==null) {
+				console.crlf();
+				console.writeln("I'm sorry, but all planets are taken.");
+				console.writeln("One has to be destroyed before you can buy a planet.");
+			}
+			else {
+				planet.Name='';
+				while(planet.Name=='') {
+					console.write("What do you want to name this planet? (41 chars. max)? ");
+					planet.Name=console.getstr(41);
+				}
+				for(i=0; i<Commodities.length; i++) {
+					planet.Commodities[i]=1;
+					planet.Production[i]=1;
+				}
+				player.Credits-=10000;
+				player.Put();
+				planet.Sector=sector.Record;
+				sector.Planet=planet.Record;
+				planet.LastUpdated=time();
+				planet.Put();
+				sector.Put();
+				twmsg.writeln("  -  "+player.Alias+" made a planet: "+planet.Name);
+				console.crlf();
+				console.writeln("Planet created");
+				break;
+			}
+
+		default:
+			break;
+	}
+}
+
+function PlanetReport(planet)
+{
+	console.crlf();
+	console.writeln("Planet: "+planet.Name);
+	console.writeln(" Item      Prod.  Amount  in holds");
+	console.writeln(" ====      =====  ======  ========");
+	var i;
+	var freeholds=player.Holds;
+	for(i=0; i<Commodities.length; i++) {
+		console.writeln(format("%s   %2d  %6d %8d"
+				,Commodities[i].disp
+				,planet.Production[i]
+				,parseInt(planet.Commodities[i])
+				,player.Commodities[i]));
+		freeholds-=player.Commodities[i];
+	}
+	console.writeln("You have "+freeholds+" free cargo holds.");
+}
+
+function PlanetMenu(planet)
+{
+	var key;
+	var freeholds=player.Holds;
+	var i;
+	
+	for(i=0; i<Commodities.length; i++)
+		freeholds-=player.Commodities[i];
+
+	while(true) {
+		console.crlf();
+		console.write("Planet command (?=help)[A]? ");
+		key=GetKeyEcho();
+		switch(key) {
+			case '':
+			case 'A':
+				console.writeln("<Take all>");
+				if(freeholds < 1) {
+					console.writeln("You don't have any free holds.");
+					continue;
+				}
+				for(i=Commodities.length-1; i>=0; i--) {
+					var take=parseInt(planet.Commodities[i]);
+					if(take > freeholds)
+						take=freeholds;
+					if(take) {
+						console.writeln("You took " + take + " holds of "+Commodities[i].name.toLowerCase());
+						player.Commodities[i]+=take;
+						planet.Commodities[i]-=take;
+						freeholds-=take;
+					}
+					if(freeholds < 1) {
+						console.writeln("Your cargo holds are full.");
+						break;
+					}
+				}
+				player.Put();
+				planet.Put();
+				break;
+			case 'I':
+				console.writeln("<Increase productivity>");
+				console.crlf();
+				console.writeln("You have "+player.Credits+" credits.");
+				var opts="";
+				for(i=0; i<Commodities.length; i++) {
+					console.writeln((i+1)+" - "+Commodities[i].name+" costs "+(Commodities[i].price*20));
+					if(i)
+						opts += ',';
+					opts += (i+1).toString();
+				}
+				console.write("Which one do you want to increase ("+opts+")? ");
+				var keynum=parseInt(GetKeyEcho());
+				if(keynum > 0 && keynum <= Commodities.length) {
+					keynum--;
+					if(planet.Production[keynum]>19) {
+						console.writeln("It's at its maximum value.");
+						continue;
+					}
+					var max=parseInt(player.Credits/(Commodities[keynum].price*20));
+					if(max<1) {
+						console.writeln("You're too poor.  You only have "+player.Credits+" credits.");
+						continue;
+					}
+					if(planet.Production[keynum]+max > 19)
+						max=20-planet.Production[keynum];
+					console.write(Commodities[keynum].name+": Increase by how many units? ");
+					var incr=console.getnum(max);
+					if(incr > 0 && incr <= max) {
+						player.Credits -= incr*Commodities[keynum].price*20;
+						planet.Production[keynum]+=incr;
+						planet.Put();
+						player.Put();
+					}
+				}
+				break;
+			case 'D':
+				console.crlf();
+				console.attributes="RI7H";
+				console.writeln("*** DESTROY THE PLANET ***");
+				console.crlf();
+				console.attributes="Y";
+				console.write("Are you sure (Y/N)[N]? ");
+				if(GetKeyEcho()=='Y') {
+					planet.Created=false;
+					var sector=sectors.Get(planet.Sector);
+					sector.Planet=0;
+					planet.Sector=0;
+					planet.Put();
+					sector.Put();
+					twmsg.writeln("  -  " + player.Alias + " destroyed the planet in sector " + sector.Record);
+					console.writeln("Planet destroyed.");
+					return;
+				}
+				break;
+			case 'L':
+				return;
+			case 'R':
+				PlanetReport(planet);
+				break;
+			case '?':
+				console.crlf();
+				for(i=0; i<Commodities.length; i++)
+					console.writeln((i+1)+" - take "+Commodities[i].name.toLowerCase());
+				console.writeln("A - take <A>ll");
+				console.writeln("D - <D>estroy the planet");
+				console.writeln("I - <I>ncrease productivity");
+				console.writeln("L - <L>eave planet");
+				console.writeln("R - planet <R>eport");
+				break;
+			default:
+				var keynum=parseInt(key);
+				if(keynum > 0 && keynum <= Commodities.length) {
+					keynum--;
+					var max=freeholds;
+					if(max > parseInt(planet.Commodities[keynum]))
+						max=parseInt(planet.Commodities[keynum]);
+					console.writeln("<Take "+Commodities[keynum].name.toLowerCase()+">");
+					console.write("How much [" + max + "]? ");
+					var take=console.getnum(max);
+					if(take > max) {
+						console.writeln("They don't have that many.");
+						continue;
+					}
+					if(take > freeholds) {
+						console.writeln("You don't have enough free cargo holds.");
+						continue;
+					}
+					planet.Commodities[keynum]-=take;
+					player.Commodities[keynum]+=take;
+					freeholds -= take;
+					planet.Put();
+					player.Put();
+				}
+				else {
+					console.writeln("Invalid command.  Enter ? for help");
+				}
+		}
+	}
+}
+
+function ReadRadio()
+{
+	var i;
+	var rmsg;
+	var count=0;
+	
+	console.crlf();
+	console.writeln("Checking for Radio Messages sent to you.");
+	for(i=0; i<twrmsg.length; i++) {
+		var rmsg=twrmsg.Get(i);
+		if(rmsg.Read)
+			continue;
+		if(rmsg.To != player.Record)
+			continue;
+		console.write("Message from ");
+		if(rmsg.From > 0) {
+			var p=players.Get(rmsg.From);
+			console.write(p.Alias);
+		}
+		else {
+			console.write("A deleted player");
+		}
+		console.writeln(":");
+		console.writeln(rmsg.Message);
+		rmsg.Read=true;
+		rmsg.Put();
+		count++;
+	}
+	if(count < 1)
+		console.writeln("None Received.");
+}
+
+function Transact(type, price, vary, avail)
+{
+	var buy=vary<0?false:true;
+	var youare=buy?"buy":"sell";
+	var weare=buy?"sell":"buy";
+	var emptyholds=player.Holds;
+	var max=0;
+
+	var i;
+	for(i=0; i<Commodities.length; i++)
+		emptyholds -= player.Commodities[i];
+
+	if(buy)
+		max=emptyholds;
+	else
+		max=player.Commodities[type];
+
+	if(max > parseInt(avail))
+		max=parseInt(avail);
+
+	if(max < 1)
+		return(-1);
+
+	console.crlf();
+	console.writeln("You have "+player.Credits+" credits and "+emptyholds+" empty cargo holds.");
+	console.crlf();
+	console.writeln("We are "+weare+"ing up to "+avail+".  You have "+player.Commodities[type]+" in your holds.");
+
+	console.write("How many holds of "+Commodities[type].name.toLowerCase()+" do you want to "+youare+" ["+max+"]? ");
+	var amount=console.getnum(max,max);
+
+	if(amount>0 && amount<=max) {
+		var done=false;
+		console.writeln("Agreed, "+amount+" units.");
+		var haggles=random(3)+2;
+		var offer=0;
+		for(var hag=0; hag<haggles; hag++) {
+			if(hag==haggles-1)
+				console.write("Our final offer is ");
+			else
+				console.write("We'll "+weare+" them for ");
+			console.writeln(parseInt(price*amount*(1+vary/1000)+.5));
+			offer=0;
+			while(offer==0) {
+				console.write("Your offer? ");
+				offer=console.getnum(buy?player.Credits:(price*amount*10));
+				if(offer==0)
+					break;
+				if(offer < price*amount/10 || offer > price*amount*10) {
+					console.writeln("That was pretty funny, Now make a serious offer.");
+					offer=0;
+				}
+			}
+			if(offer==0)
+				break;
+			if(!buy && offer <= price*amount) {
+				console.writeln("We'll take them!");
+				player.Credits += offer;
+				player.Commodities[type] -= amount;
+				player.Put();
+				return(amount);
+			}
+			if(buy && offer >= price*amount) {
+				console.writeln("Sold!");
+				player.Credits -= offer;
+				player.Commodities[type] += amount;
+				player.Put();
+				return(amount);
+			}
+			var worstoffer=parseInt(amount*price*(1-vary/250/(hag+1)) + .5);
+			if(buy && offer < worstoffer)
+				break;
+			if(!buy && offer > worstoffer)
+				break;
+			price = .7*price + .3*offer/amount;
+		}
+
+		if(offer > 0) {
+			if(buy) {
+				console.writeln("Too low.  We'll sell them to local traders.");
+				return(0);
+			}
+			console.writeln("Too high.  We'll buy them from local traders.");
+		}
+		return(0);
+	}
+	return(0);
+}
+
+function TeamMenu()
+{
+	function TeamHelp() {
+		console.crlf();
+		console.attributes="HY";
+		console.writeln("1)  Exit Team menu");
+		console.attributes="HC";
+		console.writeln("2)  Create a Team");
+		console.attributes="HG";
+		console.writeln("3)  Join a Team");
+		console.attributes="HW";
+		console.writeln("4)  Quit a Team");
+		if(player.TeamNumber > 0) {
+			console.attributes="HM";
+			console.writeln("5)  Cash Transfer");
+			console.attributes="HK";
+			console.writeln("6)  Fighter Transfer");
+			console.attributes="HB";
+			console.writeln("7)  Search for Team member(s)");
+		}
+	}
+
+	TeamHelp();
+
+	while(1) {
+		console.crlf();
+		console.attributes="W";
+		console.write("Team Command (?=help)? ");
+		switch(GetKeyEcho()) {
+			case '?':
+				TeamHelp();
+				break;
+			case '1':
+				return;
+			case '2':
+				if(player.TeamNumber > 0) {
+					console.writeln("You already belong to a Team! ");
+					console.writeln("You must quit a team to form another Team.");
+					break;
+				}
+				var password='';
+				while(password.length != 4) {
+					console.writeln("To form a Team you will need to input a 4 character Team Password");
+					console.write("Enter Password [ENTER]=quit? ");
+					password=console.getstr(4);
+					if(password=='')
+						break;
+					if(password.length != 4)
+						console.writeln("Password MUST be 4 characters");
+				}
+				if(password=='')
+					break;
+				console.crlf();
+				console.writeln("REMEMBER YOUR TEAM PASSWORD!");
+				var team=null;
+				for(i=1; i<teams.length; i++) {
+					team=teams.Get(i);
+					if(team.Size > 0)
+						break;
+					team=null;
+				}
+				if(team==null)
+					team=teams.New();
+				team.Password=password;
+				team.Size=1;
+				team.Members[0]=player.Record;
+				player.TeamNumber=team.Record;
+				team.Put();
+				player.Put();
+				console.attributes="HYI";
+				twmsg.writeln(player.Alias+" Created Team "+team.Record+" the " /* TNAM$ */);
+				console.writeln("Team number [" + team.Record + "] CREATED!");
+				console.attributes="HK";
+				break;
+			case '3':
+				if(player.TeamNumber > 0) {
+					console.writeln("You already belong to a Team! ");
+					console.writeln("You must quit one team to join another Team.");
+					break;
+				}
+				console.write("What Team number do you wish to join (0=quit)? ");
+				var tnum=console.getnum(teams.length-1);
+				if(tnum > 0 && tnum < teams.length) {
+					var team=teams.Get(tnum);
+					if(team.Size > 3) {
+						console.writeln("The Team you picked has a maximum amount of members!");
+						break;
+					}
+					console.write("Please enter Password to Join Team #"+team.Record+" ? ");
+					var pass=console.getstr(4);
+					if(pass != team.Password) {
+						console.writeln("Invalid Password entered!");
+						break;
+					}
+					var i;
+					for(i=0; i<team.Members.length; i++) {
+						if(team.Members[i]==0) {
+							team.Members[i]=player.Record;
+							team.Size++;
+							player.TeamNumber=team.Record;
+							team.Put();
+							player.Put();
+							twmsg.writeln(player.Alias + " Joined Team "+team.Record);
+							console.attributes="HC";
+							console.writeln("Your Team info has been recorded!  Have fun!");
+							console.attributes="HK";
+							break;
+						}
+					}
+				}
+				break;
+			case '4':
+				if(player.TeamNumber != 0) {
+					console.writeln("You don't belong to a Team!");
+					break;
+				}
+				console.write("Are you sure you wish to quit your Team [N]? ");
+				if(GetKeyEcho()=='Y') {
+					var team=teams.Get(player.TeamNumber);
+					player.TeamNumber=0;
+					var i;
+					for(i=0; i<team.Members.length; i++) {
+						if(team.Members[i]==player.Record) {
+							team.Members[i]=0;
+							team.Size--;
+							player.Put();
+							team.Put();
+							console.crlf();
+							console.attributes="HG";
+							console.writeln("You have been removed from Team play");
+							console.attributes="HK";
+						}
+					}
+				}
+				break;
+			case '5':
+				console.write("Transfer Credits to another Team member [N]? ");
+				if(GetKeyEcho()=='Y') {
+					if(player.Credits < 1) {
+						console.writeln("You don't have any Credits.");
+						break;
+					}
+					var i;
+
+					var otherplayer=null;
+					for(i=1;i<players.length; i++) {
+						otherplayer=players.Get(i);
+						if(otherplayer.Sector==player.Sector
+								&& otherplayer.Record!=player.Record
+								&& otherplayer.KilledBy!=0
+								&& otherplayer.UserNumber!=0
+								&& otherplayer.TeamNumber==player.TeamNumber) {
+							console.write("Transfer Credits to " + otherplayer.Alias + " (Y/[N])? ");
+							if(GetKeyEcho()=='Y')
+								break;
+						}
+						otherplayer=null;
+					}
+					if(otherplayer==null) {
+						console.writeln("There is no one else in this sector");
+						break;
+					}
+					while(1) {
+						console.writeln("You have" + player.Credits + " credits.");
+						console.writeln(otherplayer.Alias + " has" + otherplayer.Credits + " credits.");
+						console.write("How many Credits do you wish to Transfer? ");
+						var transfer=console.getnum(player.Credits);
+						if(transfer<1 || transfer > player.Credits)
+							break;
+						if(otherplayer.Credits + transfer > 25000) {
+							console.writeln("You Team mate will have more than 25,000 credits");
+							console.write("Do you wish to complete the Transfer [N]? ");
+							if(GetKeyEcho()=='Y')
+								break;
+						}
+						else
+							break;
+					}
+					otherplayer.Credits += transfer;
+					player.Credits -= transfer;
+					player.Put();
+					otherplayer.Put();
+					console.writeln("Credits Transfered!");
+				}
+			case '6':
+				console.write("Transfer Fighters to another Team member [N]? ");
+				if(GetKeyEcho()=='Y') {
+					if(player.Fighters < 1) {
+						console.writeln("You don't have any Fighters.");
+						break;
+					}
+					var i;
+
+					var otherplayer=null;
+					for(i=1;i<players.length; i++) {
+						otherplayer=players.Get(i);
+						if(otherplayer.Sector==player.Sector
+								&& otherplayer.Record!=player.Record
+								&& otherplayer.KilledBy!=0
+								&& otherplayer.UserNumber!=0
+								&& otherplayer.TeamNumber==player.TeamNumber) {
+							console.write("Transfer Fighters to " + otherplayer.Alias + " (Y/[N])? ");
+							if(GetKeyEcho()=='Y')
+								break;
+						}
+						otherplayer=null;
+					}
+					if(otherplayer==null) {
+						console.writeln("There is no one else in this sector");
+						break;
+					}
+					while(1) {
+						console.writeln("You have" + player.Fighters + " fighters.");
+						console.writeln(otherplayer.Alias + " has" + otherplayer.Fighters + " fighters.");
+						console.write("How many Fighters do you wish to Transfer? ");
+						var transfer=console.getnum(player.Fighters);
+						if(transfer<1 || transfer > player.Fighters)
+							break;
+						if(otherplayer.Fighters + transfer > 9999)
+							console.writeln("Maximum amount of fighters per player is 9999");
+						else
+							break;
+					}
+					otherplayer.Fighters += transfer;
+					player.Fighters -= transfer;
+					player.Put();
+					otherplayer.Put();
+					console.writeln("Fighters Transfered!");
+				}
+			case '7':
+				console.writeln("Locating Other Team members.");
+				console.crlf();
+				console.writeln("Name                                     Sector");
+				console.writeln("====================                     ======");
+				var count=0;
+				var i;
+				for(i=1;i<players.length; i++) {
+					otherplayer=players.Get(i);
+					if(otherplayer.Record!=player.Record
+							&& otherplayer.UserNumber!=0
+							&& otherplayer.TeamNumber==player.TeamNumber) {
+						count++;
+					}
+					console.write(format("%-41s ",otherplayer.Alias));
+					if(otherplayer.KilledBy != 0)
+						console.write(" Dead!");
+					else
+						console.write(otherplayer.Sector);
+					console.crlf();
+				}
+				console.crlf();
+				if(count==0)
+					console.writeln("None Found");
+				break;
+		}
+	}
+}
+
+function CabalAttack(cabal)
+{
+	/* Cabal groups lower than 6 (wandering and defence) do not attack players */
+	if(cabal.Record < 6)
+		return;
+
+	/* Look for another player in the sector (attacking by rank) */
+	var i;
+	var attackwith=0;
+
+	var ranks=RankPlayers();
+	var sector=sectors.Get(cabal.Sector);
+	if(sector.FighterOwner != -1)	/* Huh? */
+		return;
+
+	sector.Fighters -= cabal.Size;
+	if(sector.Fighters < 0)
+		sector.Fighters=0;
+
+	for(i=0; i<ranks.length; i++) {
+		var otherplayer=players.Get(ranks[i].Record);
+
+		if(otherplayer.Sector != cabal.Sector)
+			continue;
+		if(otherplayer.UserNumber==0)
+			continue;
+		if(otherplayer.KilledBy != 0)
+			continue;
+		else if(cabal.Record<9)	/* Attack Group */
+			attackwith=20;
+		else if(cabal.Record==9) { /* Top player hunter */
+			if(i==0)
+				attackwith=cabal.Size;
+			else
+				attackwith=0;
+		}
+
+		if(attackwith==0)
+			continue;
+		if(attackwith > cabal.Size)
+			attackwith = cabal.Size;
+
+		cabal.Size -= attackwith;
+		/* Attack the player */
+		var killed=0;
+		var lost=0;
+		while(otherplayer.Fighters > 0 && attackwith > 0) {
+			if(random(2)==1) {
+				attackwith--;
+				lost++;
+			}
+			else {
+				otherplayer.Fighters--;
+				killed++;
+			}
+		}
+		cabal.Size += attackwith;
+		twmsg.writeln("      Group "+cabal.Record+" --> "+otherplayer.Alias+": lost "+killed+ ", dstrd "+killed+" ("+(cabal.Size==0?"Cabal":"Player")+" dstrd)");
+		if(cabal.Size==0)
+			cabal.ReInit();
+		else				/* Player destroyed by the cabal! */
+			otherplayer.KilledBy=-1;
+		otherplayer.Put();
+		cabal.Put();
+	}
+	sector.Fighters += cabal.Size;
+	if(cabal.Size > 0)
+		sector.FighterOwner=-1;
+	sector.Put();
+}
+
+function MoveCabalGroup(cabal, target)
+{
+	if(cabal.Sector==0 || cabal.Size < 1)
+		return;
+	var sector=sectors.Get(cabal.Sector);
+
+	sector.Fighters -= cabal.Size;
+	if(sector.Fighters < 1) {
+		sector.Fighters=0;
+		sector.FighterOwner=0;
+	}
+	sector.Put();
+
+	/* Set new sector */
+	cabal.Sector=target;
+	sector=sectors.Get(cabal.Sector);
+
+	/* Attack dropped fighters */
+	if(sector.Fighters > 0 && sector.FighterOwner != -1) {
+		var killed=0;
+		var lost=0;
+		var ownername="Deleted Player";
+		if(sector.FighterOwner > 0) {
+			var fowner=players.Get(sector.FighterOwner);
+			ownername=fowner.Alias;
+		}
+		while(cabal.Size > 0 && sector.Fighters > 0) {
+			if(random(2)==1) {
+				cabal.Size--;
+				lost++;
+			}
+			else {
+				sector.Fighters--;
+				killed++;
+			}
+		}
+		/* Place into twpmsg.dat */
+		var i;
+		var msg=null;
+		for(i=0; i<twpmsg.length; i++) {
+			msg=twpmsg.Get(i);
+			if(msg.Read)
+				break;
+			msg=null;
+		}
+		if(msg==null)
+			msg=twpmsg.New();
+		msg.Read=false;
+		msg.To=sector.FighterOwner;
+		msg.From=-1;
+		msg.Destroyed=killed;
+		msg.Put();
+		twmsg.writeln("      Group "+cabal.Record+" --> Sector "+target+" ("+ownername+"): lost "+killed+", dstrd "+lost+" ("+(sector.Fighters==0?"Player":"Cabal")+" ftrs dstrd)");
+		if(cabal.Size==0) {
+			cabal.ReInit();
+			cabal.Put();
+			return;
+		}
+		else {
+			sector.FighterOwner=-1;
+			sector.Fighters=cabal.Size;
+		}
+		sector.Put();
+	}
+
+	CabalAttack(cabal);
+	if(cabal.Sector==0 || cabal.Size < 1)
+		return;
+
+	/* Merge into another group */
+	var i;
+	for(i=1; i<cabals.length; i++) {
+		if(i==cabal.Record)
+			continue;
+		var othercabal=cabals.Get(i);
+		/* Merge Groups */
+		if(othercabal.Sector==cabal.Sector) {
+			if(othercabal.Record < cabal.Record) {
+				othercabal.Size += cabal.Size;
+				cabal.ReInit();
+			}
+			else {
+				cabal.Size += othercabal.Size;
+				othercabal.ReInit();
+			}
+			cabal.Put();
+			othercabal.Put();
+		}
+	}
+}
+
+function MoveCabal()
+{
+	var total=0;
+	var i;
+
+	console.writeln("Moving the Cabal.");
+	twmsg.writeln("    Cabal report:");
+	/* Validate Groups and count the total */
+	for(i=1; i<cabals.length; i++) {
+		var cabal=cabals.Get(i);
+		var sector=sectors.Get(cabal.Sector);
+		cabal.Size=sector.Fighters;
+		if(sector.FighterOwner != -1 || sector.Fighters==0) {
+			cabal.Sector=0;
+			cabal.Size=0;
+			cabal.Goal=0;
+		}
+		cabal.Put();
+		total+=cabal.Size;
+	}
+
+	/* Move group 2 into sector 85 (merge into group 1) */
+	var cabal=cabals.Get(2);
+	MoveCabalGroup(cabal, 85);
+
+	/* Note, this seems to have a max limit of 2000 for regeneration */
+	var regen=Settings.CabalRegeneration;
+	if(total+regen > 2000)
+		regen=2000-total;
+	if(regen<1)
+		regen=0;
+
+	cabal=cabals.Get(1);
+	cabal.Size += regen;
+
+	/* Split off group 2 */
+	group2=cabals.Get(2);
+	if(cabal.Size > 1000) {
+		group2.Size=cabal.Size-1000;
+		group2.Sector=85;
+		MoveCabalGroup(group2, 83);
+	}
+
+	/* Create wandering groups */
+	for(i=3; i<6; i++) {
+		var wgroup=cabals.Get(i);
+		if(wgroup.Size < 1 || wgroup.Sector < 1 || wgroup.Sector >= sectors.length) {
+			if(group2.size >= 600) {
+				wgroup.Size=100;
+				group2.size-=100;
+				wgroup.Sector=83;
+				wgroup.Goal=0;
+				while(wgroup.Goal < 8)
+					wgroup.Goal=random(sectors.length);
+			}
+			else {
+				wgroup.ReInit();
+			}
+			wgroup.Put();
+		}
+	}
+
+	/* Create attack groups */
+	for(i=6; i<9; i++) {
+		var agroup=cabals.Get(i);
+		if(agroup.Size < 1 || agroup.Sector < 1 || agroup.Sector >= sectors.length) {
+			if(group2.size >= 550) {
+				agroup.Size=50;
+				group2.size-=50;
+				agroup.Sector=83;
+				agroup.Goal=0;
+				while(agroup.Goal < 8)
+					agroup.Goal=random(sectors.length);
+			}
+			else {
+				agroup.ReInit();
+			}
+			agroup.Put();
+		}
+	}
+	
+	/* Create hunter group */
+	var hgroup=cabals.Get(9);
+	if(hgroup.Size < 1 || hgroup.Sector < 1 || hgroup.Sector >= sectors.length) {
+		if(group2.size >= 500) {
+			hgroup.Size=group2.Size-500;
+			group2.size-=hgroup.Size;
+			hgroup.Sector=83;
+			hgroup.Goal=0;
+		}
+		else {
+			hgroup.ReInit();
+		}
+		hgroup.Put();
+	}
+	group2.Put();
+
+	/* Move wandering groups */
+	for(i=3; i<6; i++) {
+		var wgroup=cabals.Get(i);
+		if(wgroup.Size < 1 || wgroup.Sector == 0)
+			continue;
+		/* Choose new target */
+		if(wgroup.Sector == wgroup.Goal) {
+			wgroup.Goal=0;
+			while(wgroup.Goal < 8)
+				wgroup.Goal=random(sectors.length);
+		}
+		if(wgroup.Size < 50 || wgroup.Size > 100)
+			wgroup.Goal=85;
+		var path=ShortestPath(wgroup.Sector, wgroup.Goal);
+		while(path[0] < 8)
+			path.shift();
+		MoveCabalGroup(wgroup,path[0]);
+	}
+
+	/* Move Attack Groups */
+	for(i=6; i<9; i++) {
+		var agroup=cabals.Get(i);
+		if(agroup.Size < 1 || agroup.Sector == 0)
+			continue;
+		/* Choose new target */
+		if(agroup.Sector == agroup.Goal) {
+			agroup.Goal=0;
+			while(agroup.Goal < 8)
+				agroup.Goal=random(sectors.length);
+		}
+		if(agroup.Size < 20 || agroup.Size > 50)
+			agroup.Goal=85;
+		var path=ShortestPath(agroup.Sector, agroup.Goal);
+		var next;
+		while(path.length > 0 && agroup.Size > 0) {
+			var next=path.shift();
+			if(next < 8)
+				continue;
+			MoveCabalGroup(agroup,next);
+		}
+	}
+
+	/* Move hunter groups... */
+	for(i=9; i<10; i++) {
+		var hgroup=cabals.Get(i);
+		if(hgroup.Size < 1 || hgroup.Sector == 0)
+			continue;
+		/* Choose target */
+		var ranks=RankPlayers();
+		if(ranks.length < 0) {
+			var player=players.Get(ranks[0].Record);
+			hgroup.Goal=player.Sector;
+			var path=ShortestPath(hgroup.Sector, hgroup.Goal);
+			var next;
+			while(path.length > 0 && hgroup.Size > 0) {
+				var next=path.shift();
+				MoveCabalGroup(agroup,next);
+			}
+		}
+	}
+}
diff --git a/xtrn/tw2/twinstr.doc b/xtrn/tw2/twinstr.doc
new file mode 100644
index 0000000000000000000000000000000000000000..078bd67583fbeca7b9d7891ff70696bd34ffd5ca
--- /dev/null
+++ b/xtrn/tw2/twinstr.doc
@@ -0,0 +1,218 @@
+                        TRADE WARS (v.ii)
+                    by CHRIS SHERRICK (PTL)
+                Copyright 1986   Chris Sherrick
+
+                 RBBS version brought to you by
+                      The Reno RBBS and     
+                Sysop John Morris / 702-673-3387
+
+	This is a multi-player game that is a cross between a war game and
+a space trading game.  Players compete against one another and are even
+able to attack and kill each other.  You have a ship that can roam the
+universe, from space port to space port trading metals, organics and equipment
+to earn credits (money.)  Once you've earned some credits, you can buy
+fighters or cargo holds.  With more cargo holds, you can carry more merchandise
+and earn more credits.  With fighters, you can attack and destroy other
+players' ships and steal cargo holds from them.  You can also defend a
+space port (or a series of sectors and space ports) which will give you
+exclusive trading and make even more credits.  The goal of this game is
+simple:  to control the universe.
+
+GETTING STARTED
+     All you have to do to play this game is to log on.  The computer
+will automatically recognize you and enter you in the game if there is
+room for you.  If there isn't room for you, don't worry.  Old players
+are often deleted and room should open up in several days. You should
+also leave a message for the sysop telling him you want to play because
+he might be able to delete an old player before his time to make room
+for you.  When you start, the computer will give you a ship along with
+some cargo holds and some fighters and you will be on your way to becoming
+the most powerful person in the universe.
+
+ONCE YOU'RE IN...
+     Once you're in, the computer will remember everything you do.  If
+you exit the game in the middle, or even hang up on the game, it will
+remember what you did and and allow you to continue the next time you
+decide to play.  You are allowed so many turns a day, and each time you
+move from sector to sector or land at a space port, you lose one turn.
+Unfortunately, how many turns you've used up is remembered.  If someone
+has left some fighters to protect the sector, you have to fight off his
+fighters before you you are allowed to do anything in that sector.  You
+can also retreat at the cost of one fighter though.
+     However, once you're in a sector, you can trade at space ports, take
+or leave fighters within the sector to defend it, and even attack other
+peoples' ships.  Every time you attack someone's ship, they will know
+who did it.  This also goes for you; if someone kills your fighters, you
+will know who did it.  So experiment!  Feel free to wipe someone out...
+they might even return the favor.  Start a war!
+
+THE CABAL
+     You're not alone in the universe.  The evil Cabal, a race of warring
+creatures, wander around seeking whom they can devour.  These evil warriors
+dwell in a portion of the known universe and if you are mighty enough,
+you can conquer them.  The Cabal exist for the sole purpose to annoy players,
+but an outstanding Trade Wars player can actually defeat the Cabal and
+receive 100,000 points!  Also, there is a bounty on the Cabal:
+For every Cabal fighter you destroy, you will receive 100 points. 
+But beware, these guys are tough.
+
+ONCE YOU'RE IN A SECTOR      Once you're in a sector, there are several
+things you can do.  The following is a list of available commands:
+
+A - ATTACK
+     This command allows your fighters to attack another player's ship
+in the same sector.  When you attack another's ship, the computer will
+ask you the number of fighters you want to use.  Then the computer will
+do the fighting for you.  On every attack, someone will lose a fighter,
+and there is a 50% chance it will be yours.  If you don't lose one, the
+other guy will.  The computer will keep fighting until either you lose
+that many fighters, or you wipe out all the other persons fighters.  Then
+it will give you a total telling you how good (or bad) you did.  It is
+possible to lose 500 fighters in one stroke, so be careful with this one.
+If you kill off all the fighters protecting another player's ship, you
+can attack the ship and salvage 1/4 of its cargo.
+
+C - COMPUTER
+     Each ship has an on-board computer.  It can be called from within
+a sector.  The computer has four functions, a port report, a sector finder,
+a ranking routine, and a radio message routine.  The port report will give 
+the quantity of any unprotected port so you can immediately know where there 
+is some good trading.  The computer will ask you for what sector the port 
+is in.  Just enter the sector number.  For example, for Sol, enter a '1'.
+If there isn't a port in that sector, or someone is protecting that port 
+with fighters, the computer will respond with "No information available."
+     The sector finder will tell you how to get to any sector you specify.
+If you want to know how to get to another sector, run this program.  It
+will tell you which sectors to take to get to the sector you want.  This
+will be very useful until you get a map made.
+     The ranking routine ranks all the players playing the game.  Along
+side the player is his or her value in credits.  This includes everything,
+including fighters dropped in sectors.  Note that a person who has been
+killed has a value of zero.
+     The last function is the Send message function.  You will be asked
+for a 'search string'.. For instance if you wanted to send a message to
+Chris Sherrick, you could input  Sherr  for the search string. Or you can
+simply enter the persons full name.  Once you have located the proper 
+player to send the message to, you will be given a space of 74 characters
+to write your message in.
+
+D - DISPLAY SECTOR
+     This will give you info about the sector you are in.  It will tell
+you the sector you are in, the name and class of any ports in the sector,
+other players' ships and the the number of fighters protecting them, the
+number of fighters protecting the sector and who they belong to, and what
+sectors the warps lead to.  Note the difference between fighters protecting
+the sector and the fighters accompanying ships.  The fighters protecting
+the sector are the ones you have to fight in order to get into the sector.
+The fighters accompanying the ships are the ones you have to destroy to
+get to the other players' ships (using the 'A' command.)
+
+F - TAKE OR LEAVE FIGHTERS
+     This lets you leave fighters to defend a sector or take the ones
+already there.  If there are fighters protecting a sector, no one can
+enter that sector without defeating them.  The computer will ask you how
+many fighters you want defending the sector.  Note: this is DEFENDING
+THE SECTOR.  If you have some there already, and you enter a number less
+than the number there, you will take the remaining fighters.  If you want
+to leave three fighters in an empty sector, enter '3'.  If you have seven
+fighters in a sector and want to take them all, enter '0'. (None will
+be left defending the sector.)  If you have four fighters in a sector
+and want to take three and leave one, enter '1' and the remaining three
+will go with you.  You are not allowed to leave fighters in sectors 1-7.
+Sectors 1-7 is the Union (the local government) and they don't like having
+fighters in their presence.
+
+G - GAMBLE
+     Due to popular demand, a new command has been added: Gambling.  You
+gamble with credits and have 50-50 odds.  Just type G when you're in a
+sector.  Warning: DON'T BET ALL YOU CREDITS!  If you lose all your credits,
+and you have empty cargo holds there is nothing you can do.  You just
+have to wait until someone destroys you.
+
+I - INFO ABOUT YOUR SHIP
+     This command will give you information about your ship.  It will
+tell you the sector you are in, the number of turns left, the number of
+fighters in your fleet, the number of cargo holds on your ship and what
+they contain, and how many credits you have.
+
+L - LAND/CREATE A PLANET
+     Planets are similar to ports, only they produce everything, and give
+their merchandise away instead of bartering with them. If you <L>and in
+a sector containing no planets you will be able to Create a planet. But
+you will need 10,000 credits to do so. Sounds nice doesn't it?  
+One thing you should know about planets is what productivity is.
+Productivity is how many units that planet produces per 24 hours.  You can
+ increase the productivity (by putting money into a planet)  
+Planets start with an initial productivity of 1 in ore, organics,
+and equipment.  They have a maximum productivity of 20 each.  I highly
+recommend leaving fighters in a sector with a planet in it because it
+doesn't cost a thing to destroy a planet.  All you have to do is land
+at it.  There is one planet allowed per sector.
+
+M - MOVE
+     This allows you to move from sector to sector.  The Union has established
+a web of warps from sector to sector that you can travel through.  Each
+move takes up one turn and you have a limited number of turns a day. 
+If you move into a sector with fighters protecting it, you will have to
+fight them before you can enter.  You can attack or retreat.  If you retreat,
+you will return to the sector from which you came from, but you won't
+use up another turn.  It will cost you one fighter to retreat and if you
+don't have one left, there is a 50% chance you will make it.
+
+P - PORT
+     This command allows you to land and trade with space ports, providing
+there is one in your sector.  Docking at a space port uses up one turn
+When you trade, you trade in units.  One unit is enough to fill one cargo
+hold aboard your ship.  There are three types of merchandise: ore, organics
+(org.), and equipment (eqp.) Each port has a class that determines what
+it will sell and buy.  A class 1 port sells eqp. and buys everything else. 
+A class 2 port sells organics and buys everything else, and a class 3
+port sells ore and buys everything else.  When you dock, you will haggle
+over the prices.  They will give you an offer, and you will counter offer. 
+This will continue until either they take your offer, or decide to go
+elsewhere to do business.  The prices depend on how much they have or
+need.  The more they have or need, the better the bargain.  Ports produce
+a limited amount of merchandise a day. If you can capture one with fighters,
+don't trade with it for several days and let the prices get better and
+better.  How much of a bargain varies from port to port.  Sol (in sector
+1) is a special port.  It sells fighters, cargo holds, and turns.  When
+you buy turns, they are a temporary one shot deal; you buy turns, not
+the number of turns allotted per day. These prices of fighters and cargo
+holds vary depending on what day of the week it is; you don't haggle over
+these prices.
+
+Q - QUIT GAME
+     This command allows you to quit the game and return to the BBS. 
+You can also hang up, but I would rather have you simply Quit.  
+It makes sure that nothing is going to go wrong.  If you quit and
+you haven't used up all your turns, you can come back later on and continue
+with your remaining turns.
+
+T - TEAM MENU
+     Entering T will get you the Team menu.  This menu consists of Six
+separate functions. If you don't belong to a team, only three options are
+visible. At the team menu prompt you can enter '2' to create a Team, you
+will be asked for a Team password (which will be needed by other players
+to join your team).. That is basically it to creating a Team. Note: when
+you create a team, you do not need to join it afterwards. The next function,
+'3', is Join a Team.  You will be asked for the Team number you wish to 
+join, and if a spot is open on that team, you will be asked for the team
+password. If you enter the correct password, you are then recorded as a 
+member of that Team. Command '4' is the Quit a team command. You will need
+to quit a team if you want to create a new team or join another one.
+     If you are a member of a team, you will have 3 more functions. '5' is
+the Transfer credit command. You can transfer your credits to a Team member.
+(as long as they are in the same sector as yourself) Note: you cannot 
+transfer credits FROM a team mate to yourself. Entering '6' will give you
+the Fighter Transfer option. This works in the exact same manner as the
+credit transfer function, only with fighters. The last Team function is
+the Locate team mates command, '7'. This will give you a list of Team mates
+and the sector they are located in, if any.
+
+? - HELP!
+     This command will give you a list of the commands you can use.
+
+Z - INSTRUCTIONS
+     This will reprint these instructions.
+
+     This is all there is to the game.  Play it and have fun! ����������������������������������������������������������������������
\ No newline at end of file
diff --git a/xtrn/tw2/twint500.js b/xtrn/tw2/twint500.js
new file mode 100644
index 0000000000000000000000000000000000000000..54ea45535b035a29095e14414491413c016ffdb7
--- /dev/null
+++ b/xtrn/tw2/twint500.js
@@ -0,0 +1,178 @@
+load("../xtrn/tw2/filename.js");
+load(fname("gamesettings.js"));
+load(fname("sector_map.js"));
+load(fname("ports_map.js"));
+load("recordfile.js");
+
+var Settings=new GameSettings();
+
+function ConfigureSettings()
+{
+	var i;
+	var last=0;
+
+	for(;;) {
+		var list=new Array();
+		var str;
+
+		for(i=0; i<GameSettingProperties.length; i++)
+			list.push(format("%-35s %s",GameSettingProperties[i].name,Settings[GameSettingProperties[i].prop]));
+
+		i=uifc.list(WIN_MID|WIN_ORG|WIN_ACT|WIN_ESC, 0, 0, 0, last, last, "Configuration", list);
+		if(i==-1) {
+			if(uifc.changes) {
+				var q=uifc.list(WIN_MID|WIN_SAV, 0, 0, 0, 0, 0, "Save Changes?", ["Yes", "No"]);
+				if(q!=-1) {
+					if(q==0)
+						Settings.save();
+					break;
+				}
+			}
+			else
+				break;
+		}
+		else {
+			last=i;
+			switch(GameSettingProperties[i].type) {
+				case "String":
+					str=uifc.input(WIN_MID, GameSettingProperties[i].name, Settings[GameSettingProperties[i].prop], 0, K_EDIT);
+					if(str!=undefined)
+						Settings[GameSettingProperties[i].prop]=str;
+					break;
+				case "Date":
+					str=uifc.input(WIN_MID, GameSettingProperties[i].name, Settings[GameSettingProperties[i].prop], 8, K_EDIT);
+					if(str!=undefined)
+						Settings[GameSettingProperties[i].prop]=str;
+					break;
+				case "Integer":
+					str=uifc.input(WIN_MID, GameSettingProperties[i].name, Settings[GameSettingProperties[i].prop].toString(), 0, K_NUMBER|K_EDIT);
+					if(str!=undefined)
+						Settings[GameSettingProperties[i].prop]=parseInt(str);
+					break;
+				case "Boolean":
+					Settings[GameSettingProperties[i].prop]=!Settings[GameSettingProperties[i].prop];
+					break;
+			}
+		}
+	}
+}
+
+if(uifc == undefined) {
+	writeln("UIFC interface not available!");
+	exit(1);
+}
+
+uifc.init("TradeWars 2 Initialization");
+ConfigureSettings();
+
+if(uifc.list(WIN_MID|WIN_SAV, 0, 0, 0, 0, 0, "Reset Game?", ["No", "Yes"])!=1)
+	exit(1);
+
+load(fname("structs.js"));
+
+file_remove(fname("sectors.dat"));
+file_remove(fname("ports.dat"));
+file_remove(fname("players.dat"));
+file_remove(fname("planets.dat"));
+file_remove(fname("twmesg.dat"));
+file_remove(fname("twpmesg.dat"));
+file_remove(fname("twrmesg.dat"));
+file_remove(fname("teams.dat"));
+file_remove(fname("twopeng.dat"));
+file_remove(fname("cabals.dat"));
+var sectors=new RecordFile(fname("sectors.dat"), SectorProperties);
+var ports=new RecordFile(fname("ports.dat"), PortProperties);
+var players=new RecordFile(fname("players.dat"), PlayerProperties);
+var teams=new RecordFile(fname("teams.dat"), TeamProperties);
+var planets=new RecordFile(fname("planets.dat"), PlanetProperties);
+var twmsg=new File(fname("twmesg.dat"));
+var twpmsg=new RecordFile(fname("twpmesg.dat"), PlayerMessageProperties);
+var twrmsg=new RecordFile(fname("twrmesg.dat"), RadioMessageProperties);
+var cabals=new RecordFile(fname("cabal.dat"), CabalProperties);
+var i;
+
+uifc.pop("Creating Players");
+player=players.New();
+player.UserNumber=0;
+player.Put();
+for(i=0; i<Settings.MaxPlayers; i++) {
+	player=players.New();
+	player.UserNumber=0;
+	player.Put();
+}
+
+uifc.pop("Creating Planets");
+planet=planets.New();
+planet.Put();
+for(i=0; i<Settings.MaxPlanets; i++) {
+	planet=planets.New();
+	planet.Put();
+}
+
+uifc.pop("SysOp Messages");
+twmsg.open("w");
+twmsg.writeln(system.timestr()+" TW 500 initialized");
+twmsg.close();
+
+uifc.pop("Player Messages");
+for(i=0; i<100; i++) {
+	msg=twpmsg.New();
+	msg.Put();
+}
+
+uifc.pop("Radio Messages");
+for(i=0; i<2; i++) {
+	msg=twrmsg.New();
+	twrmsg.Read=true;
+	msg.Put();
+}
+
+uifc.pop("Teams");
+var team=teams.New();
+team.Put();
+
+uifc.pop("Placing Ports");
+/* Place ports */
+for(i=0; i<ports_init.length; i++) {
+	sector_map[ports_init[i].Position-1].Port=i+1;
+	ports_init[i].LastUpdate=system.datestr(time()-15*86400);
+}
+
+uifc.pop("Initializing the Cabal");
+sector_map[85-1].Fighters=3000;
+sector_map[85-1].FightersOwner="The Cabal";
+for(i=1; i<=10; i++) {
+	var grp=cabals.New();
+	if(i==1) {
+		grp.Size=3000;
+		grp.Sector=85;
+		grp.Goal=85;
+	}
+	grp.Put();
+}
+
+uifc.pop("Writing Sectors");
+/* Write sectors.dat */
+sector=sectors.New();
+sector.Put();
+for(i=0; i<sector_map.length; i++) {
+	sector=sectors.New();
+	for(prop in sector_map[i])
+		sector[prop]=sector_map[i][prop];
+	sector.Put();
+}
+
+uifc.pop("Writing Ports");
+/* Write ports.ini */
+port=ports.New();
+port.Put();
+for(i=0; i<ports_init.length; i++) {
+	port=ports.New();
+	for(prop in ports_init[i])
+		port[prop]=ports_init[i][prop];
+	port.Production=[ports_init[i].OreProduction, ports_init[i].OrgProduction, ports_init[i].EquProduction];
+	port.PriceVariance=[ports_init[i].OreDeduction,ports_init[i].OrgDeduction,ports_init[i].EquDeduction];
+	port.Put();
+}
+uifc.pop();
+uifc.bail();
diff --git a/xtrn/tw2/twopeng.asc b/xtrn/tw2/twopeng.asc
new file mode 100644
index 0000000000000000000000000000000000000000..5ac3e842387d975da9821780f45bdaaabed01520
--- /dev/null
+++ b/xtrn/tw2/twopeng.asc
@@ -0,0 +1,23 @@
+l
+           h.‡.ny.‰hw.
+     ny.–hw.†r.—w.r.
+        iw.   nr²²²²²²²²²²²²²²²•ihw.    nh.Œ.
+    .Š. nr²²²Œy.‰hw..„y.
+         w.‡nr²²²ˆhw.
+                  nr²²²–hw.gÜÛÛÛÜ
+       ny.‰r²²² hw.  r3±±±±†0.†g4ÛÛÛÛÛÛÛ
+w0          .    r.  nr²²²„h3±±Ž±±g0ß4ÛÛÛÛÛ0ß
+                  nr²²²RADE  h3±±‚w0. r3±±±„±±€0.†y.ˆgßßß
+      w.….r3±±‚±±€±±‚±±•ny.   hr.
+           w.r3±±€±±iw0.nhr3±±€±±…c4°°°°°°°°°
+r0              .Ž3±±±„±±±y0ARS‡iw.  nhc4°°
+w0     .i.¡nhc4°°
+w0                          .”c4°°°°°°°°°
+ny          .†hw.Œ.ˆ.„c4°°‰r0.  w.
+ny                              ..hc4°°„w0.
+       kÛgÛ  mÛÛÛ–w.‰c4°°°°°°°°°
+k0       ÛcÛÛ mÛÛÛÛžny. hc500T (yteamsc)iw.‡nh.
+   iÜyÜrÜnhkÜwÛÛÛÛÛÛÛÛÛÛ²±°Ÿ.
+   ißyßrßnhkßwÛÛÛÛmÛÛÛÛÛwÛÛÛÛÛÛÛ߉r.Šw.ny. ihw.
+      nh.    mÛÛÛÛ‹w. r.    w.–.†r.
+c  ˆmÛÛÛŠw.n