typescript-virtual-container 1.5.8 → 1.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -187,6 +187,28 @@ OPTIONS
187
187
 
188
188
  EXAMPLES
189
189
  cmatrix`,
190
+ "column": `COLUMN(1) User Commands COLUMN(1)
191
+
192
+ NAME
193
+ column - columnate lists
194
+
195
+ SYNOPSIS
196
+ column [OPTION]... [FILE]...
197
+
198
+ DESCRIPTION
199
+ The column utility formats its input into multiple columns.
200
+ Rows are filled before columns. Input is taken from FILE or stdin.
201
+
202
+ OPTIONS
203
+ -t determine the number of columns the input contains and create
204
+ a table (useful for pretty-printing)
205
+ -s specify a set of characters to be used to delimit columns
206
+ (default: whitespace)
207
+
208
+ EXAMPLES
209
+ mount | column -t
210
+ cat /etc/passwd | column -t -s:
211
+ column -t file.txt`,
190
212
  "cowsay": `COWSAY(1) User Commands COWSAY(1)
191
213
 
192
214
  NAME
@@ -810,6 +832,31 @@ SYNOPSIS
810
832
 
811
833
  OPTIONS
812
834
  -p no error if existing, make parent directories as needed`,
835
+ "mktemp": `MKTEMP(1) User Commands MKTEMP(1)
836
+
837
+ NAME
838
+ mktemp - create a temporary file or directory
839
+
840
+ SYNOPSIS
841
+ mktemp [OPTION]... [TEMPLATE]
842
+
843
+ DESCRIPTION
844
+ Create a temporary file or directory, safely, and print its name.
845
+ TEMPLATE must contain at least 3 consecutive 'X's in last component.
846
+ If TEMPLATE is not specified, use tmp.XXXXXXXXXX.
847
+ Files are created in /tmp.
848
+
849
+ OPTIONS
850
+ -d create a directory, not a file
851
+
852
+ EXIT STATUS
853
+ 0 on success
854
+ 1 if the file/directory could not be created
855
+
856
+ EXAMPLES
857
+ mktemp
858
+ mktemp -d
859
+ mktemp /tmp/foo.XXXXXX`,
813
860
  "mv": `MV(1) User Commands MV(1)
814
861
 
815
862
  NAME
@@ -841,6 +888,30 @@ SYNOPSIS
841
888
 
842
889
  DESCRIPTION
843
890
  Print OS, kernel, uptime, package count, and related system details.`,
891
+ "nl": `NL(1) User Commands NL(1)
892
+
893
+ NAME
894
+ nl - number lines of files
895
+
896
+ SYNOPSIS
897
+ nl [OPTION]... [FILE]...
898
+
899
+ DESCRIPTION
900
+ Write each FILE to standard output, with line numbers added.
901
+ With no FILE, or when FILE is -, read standard input.
902
+
903
+ OPTIONS
904
+ -b, --body-numbering=STYLE use STYLE for numbering body lines
905
+ a number all lines
906
+ t number only non-empty lines (default)
907
+ -n, --number-format=FORMAT use FORMAT for line numbers
908
+ ln left justified, no leading zeros
909
+ rn right justified, no leading zeros (default)
910
+ rz right justified, leading zeros
911
+
912
+ EXAMPLES
913
+ nl /etc/passwd
914
+ cat file.txt | nl`,
844
915
  "node": `NODE(1) User Commands NODE(1)
845
916
 
846
917
  NAME
@@ -867,6 +938,24 @@ DESCRIPTION
867
938
 
868
939
  NOTES
869
940
  Requires package installation: apt install npm.`,
941
+ "nproc": `NPROC(1) User Commands NPROC(1)
942
+
943
+ NAME
944
+ nproc - print the number of processing units available
945
+
946
+ SYNOPSIS
947
+ nproc [OPTION]...
948
+
949
+ DESCRIPTION
950
+ Print the number of processing units available to the current process.
951
+ In this environment, always returns 4.
952
+
953
+ OPTIONS
954
+ --all print the number of installed processors
955
+
956
+ EXAMPLES
957
+ nproc
958
+ make -j$(nproc)`,
870
959
  "npx": `NPX(1) User Commands NPX(1)
871
960
 
872
961
  NAME
@@ -880,6 +969,41 @@ DESCRIPTION
880
969
 
881
970
  NOTES
882
971
  Requires package installation: apt install npm.`,
972
+ "pacman": `PACMAN(1) User Commands PACMAN(1)
973
+
974
+ NAME
975
+ pacman - play ASCII Pac-Man in the terminal
976
+
977
+ SYNOPSIS
978
+ pacman
979
+
980
+ DESCRIPTION
981
+ pacman launches an interactive ASCII Pac-Man game using myman
982
+ maze graphics. Eat all dots to win. Avoid ghosts or lose a life.
983
+ Eat a power pellet to enter fright mode and eat ghosts for points.
984
+
985
+ CONTROLS
986
+ W, Up move up
987
+ S, Down move down
988
+ A, Left move left
989
+ D, Right move right
990
+ Q, Ctrl+C quit
991
+
992
+ GHOSTS
993
+ Blinky (red) directly chases Pac-Man
994
+ Pinky (pink) targets 4 tiles ahead of Pac-Man
995
+ Inky (cyan) uses Blinky's position to compute target
996
+ Clyde (orange) chases when far, scatters when close
997
+
998
+ SCORING
999
+ Dot 10 points
1000
+ Power pellet 50 points
1001
+ Ghost 200 points (during fright mode)
1002
+
1003
+ NOTES
1004
+ Ghosts slow down during fright mode. Fright mode ends after
1005
+ a few seconds; ghosts flash before returning to normal.
1006
+ Left and right tunnel exits wrap around the maze.`,
883
1007
  "passwd": `PASSWD(1) User Commands PASSWD(1)
884
1008
 
885
1009
  NAME
@@ -891,6 +1015,26 @@ SYNOPSIS
891
1015
  DESCRIPTION
892
1016
  Update the authentication token (password) for USER.
893
1017
  Without USER, change the current user's password.`,
1018
+ "paste": `PASTE(1) User Commands PASTE(1)
1019
+
1020
+ NAME
1021
+ paste - merge lines of files
1022
+
1023
+ SYNOPSIS
1024
+ paste [OPTION]... [FILE]...
1025
+
1026
+ DESCRIPTION
1027
+ Write lines consisting of the sequentially corresponding lines from
1028
+ each FILE, separated by TABs, to standard output.
1029
+
1030
+ OPTIONS
1031
+ -d, --delimiters=LIST use characters from LIST instead of TABs
1032
+ -s, --serial paste one file at a time instead of in parallel
1033
+
1034
+ EXAMPLES
1035
+ paste file1 file2
1036
+ paste -d: /etc/passwd /etc/shadow
1037
+ paste -d, a.txt b.txt c.txt`,
894
1038
  "ping": `PING(8) User Commands PING(8)
895
1039
 
896
1040
  NAME
@@ -1080,6 +1224,28 @@ SYNOPSIS
1080
1224
 
1081
1225
  DESCRIPTION
1082
1226
  Rename positional parameters by discarding the first N arguments.`,
1227
+ "shuf": `SHUF(1) User Commands SHUF(1)
1228
+
1229
+ NAME
1230
+ shuf - generate random permutations
1231
+
1232
+ SYNOPSIS
1233
+ shuf [OPTION]... [FILE]
1234
+ shuf -i LO-HI [OPTION]...
1235
+ shuf -e [OPTION]... [ARG]...
1236
+
1237
+ DESCRIPTION
1238
+ Write a random permutation of the input lines to standard output.
1239
+
1240
+ OPTIONS
1241
+ -i LO-HI treat each number LO through HI as an input line
1242
+ -n COUNT output at most COUNT lines
1243
+ -e treat each ARG as an input line
1244
+
1245
+ EXAMPLES
1246
+ shuf /etc/passwd
1247
+ shuf -i 1-10
1248
+ shuf -n 3 /etc/hosts`,
1083
1249
  "sl": `SL(1) User Commands SL(1)
1084
1250
 
1085
1251
  NAME
@@ -1195,6 +1361,24 @@ SYNOPSIS
1195
1361
  OPTIONS
1196
1362
  -i run login shell as target user
1197
1363
  -u USER run command as USER`,
1364
+ "tac": `TAC(1) User Commands TAC(1)
1365
+
1366
+ NAME
1367
+ tac - concatenate and print files in reverse
1368
+
1369
+ SYNOPSIS
1370
+ tac [OPTION]... [FILE]...
1371
+
1372
+ DESCRIPTION
1373
+ Write each FILE to standard output, last line first.
1374
+ With no FILE, or when FILE is -, read standard input.
1375
+
1376
+ OPTIONS
1377
+ -s, --separator=STRING use STRING as the record separator
1378
+
1379
+ EXAMPLES
1380
+ tac /var/log/syslog
1381
+ echo -e "a\\nb\\nc" | tac`,
1198
1382
  "tail": `TAIL(1) User Commands TAIL(1)
1199
1383
 
1200
1384
  NAME
@@ -1245,6 +1429,29 @@ SYNOPSIS
1245
1429
 
1246
1430
  DESCRIPTION
1247
1431
  Evaluate conditional expressions for scripts and shell logic.`,
1432
+ "timeout": `TIMEOUT(1) User Commands TIMEOUT(1)
1433
+
1434
+ NAME
1435
+ timeout - run a command with a time limit
1436
+
1437
+ SYNOPSIS
1438
+ timeout DURATION COMMAND [ARG]...
1439
+
1440
+ DESCRIPTION
1441
+ Start COMMAND, and kill it if still running after DURATION seconds.
1442
+ In this environment, the time limit is simulated and the command
1443
+ always runs to completion.
1444
+
1445
+ OPTIONS
1446
+ DURATION An integer number of seconds (e.g. 5).
1447
+
1448
+ EXIT STATUS
1449
+ 124 if the command times out
1450
+ Otherwise the exit status of COMMAND.
1451
+
1452
+ EXAMPLES
1453
+ timeout 5 sleep 10
1454
+ timeout 30 curl http://example.com/`,
1248
1455
  "touch": `TOUCH(1) User Commands TOUCH(1)
1249
1456
 
1250
1457
  NAME
@@ -1406,6 +1613,26 @@ DESCRIPTION
1406
1613
  The following entries are displayed for each user: login name,
1407
1614
  the tty name, the remote host, login time, idle time, JCPU, PCPU,
1408
1615
  and the command line of the current process.`,
1616
+ "wait": `WAIT(1) Bash Builtin Commands WAIT(1)
1617
+
1618
+ NAME
1619
+ wait - wait for job completion
1620
+
1621
+ SYNOPSIS
1622
+ wait [jobspec or pid ...]
1623
+
1624
+ DESCRIPTION
1625
+ Wait for each specified process or job and return its termination
1626
+ status. If no arguments are given, wait for all currently active
1627
+ background jobs.
1628
+
1629
+ In this environment, background jobs are fire-and-forget; wait
1630
+ returns immediately with exit code 0.
1631
+
1632
+ EXAMPLES
1633
+ sleep 5 &
1634
+ wait
1635
+ echo "done"`,
1409
1636
  "wc": `WC(1) User Commands WC(1)
1410
1637
 
1411
1638
  NAME
@@ -0,0 +1,8 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /**
3
+ * Play ASCII Pac-Man in the terminal (myman-wip-2009-10-30 maze graphics).
4
+ * Controls: WASD or arrow keys to move, Q to quit.
5
+ * @category misc
6
+ * @params [""]
7
+ */
8
+ export declare const pacmanCommand: ShellModule;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Play ASCII Pac-Man in the terminal (myman-wip-2009-10-30 maze graphics).
3
+ * Controls: WASD or arrow keys to move, Q to quit.
4
+ * @category misc
5
+ * @params [""]
6
+ */
7
+ export const pacmanCommand = {
8
+ name: "pacman",
9
+ description: "Play ASCII Pac-Man (myman graphics, WASD/arrows)",
10
+ category: "misc",
11
+ params: [],
12
+ run: () => {
13
+ return { openPacman: true, exitCode: 0 };
14
+ },
15
+ };
@@ -5,6 +5,7 @@ import { awkCommand } from "./awk";
5
5
  import { base64Command } from "./base64";
6
6
  import { basenameCommand, dirnameCommand } from "./basename";
7
7
  import { bcCommand } from "./bc";
8
+ import { columnCommand, mktempCommand, nlCommand, nprocCommand, pasteCommand, shufCommand, tacCommand, timeoutCommand, waitCommand } from "./coreutils";
8
9
  import { bunzip2Command, bzip2Command } from "./bzip2";
9
10
  import { lsofCommand } from "./lsof";
10
11
  import { perlCommand } from "./perl";
@@ -32,6 +33,7 @@ import { fileCommand } from "./file";
32
33
  import { findCommand } from "./find";
33
34
  import { freeCommand } from "./free";
34
35
  import { cmatrixCommand, cowsayCommand, cowthinkCommand, fortuneCommand, slCommand, yesCommand } from "./fun";
36
+ import { pacmanCommand } from "./pacman";
35
37
  import { grepCommand } from "./grep";
36
38
  import { groupsCommand } from "./groups";
37
39
  import { gunzipCommand, gzipCommand } from "./gzip";
@@ -177,6 +179,7 @@ const BASE_COMMANDS = [
177
179
  cowthinkCommand,
178
180
  cmatrixCommand,
179
181
  slCommand,
182
+ pacmanCommand,
180
183
  htopCommand,
181
184
  // Network
182
185
  curlCommand,
@@ -227,6 +230,16 @@ const BASE_COMMANDS = [
227
230
  straceCommand,
228
231
  // Scripting
229
232
  perlCommand,
233
+ // Coreutils (extended)
234
+ timeoutCommand,
235
+ mktempCommand,
236
+ nprocCommand,
237
+ waitCommand,
238
+ shufCommand,
239
+ pasteCommand,
240
+ tacCommand,
241
+ nlCommand,
242
+ columnCommand,
230
243
  ];
231
244
  const customCommands = [];
232
245
  const commandRegistry = new Map();
@@ -180,6 +180,41 @@ async function _runCommandDirectInner(name, args, authUser, hostname, mode, cwd,
180
180
  }
181
181
  }
182
182
  }
183
+ // Shell function defined via sh.ts (stored as __func_<name>)
184
+ const funcBody = env.vars[`__func_${name}`];
185
+ if (funcBody) {
186
+ const shMod = resolveModule("sh");
187
+ if (!shMod)
188
+ return { stderr: `${name}: sh not available`, exitCode: 127 };
189
+ const savedPositional = {};
190
+ args.forEach((a, i) => {
191
+ savedPositional[String(i + 1)] = env.vars[String(i + 1)];
192
+ env.vars[String(i + 1)] = a;
193
+ });
194
+ savedPositional["0"] = env.vars["0"];
195
+ env.vars["0"] = name;
196
+ try {
197
+ return await shMod.run({
198
+ authUser, hostname,
199
+ activeSessions: shell.users.listActiveSessions(),
200
+ rawInput: funcBody,
201
+ mode,
202
+ args: ["-c", funcBody],
203
+ stdin,
204
+ cwd,
205
+ shell,
206
+ env,
207
+ });
208
+ }
209
+ finally {
210
+ for (const [k, v] of Object.entries(savedPositional)) {
211
+ if (v === undefined)
212
+ delete env.vars[k];
213
+ else
214
+ env.vars[k] = v;
215
+ }
216
+ }
217
+ }
183
218
  const aliasVal = env.vars[`__alias_${name}`];
184
219
  if (aliasVal) {
185
220
  return runCommand(`${aliasVal} ${args.join(" ")}`, authUser, hostname, mode, cwd, shell, stdin, env);
@@ -20,9 +20,11 @@ function parseBlocks(lines) {
20
20
  continue;
21
21
  }
22
22
  // Function definition: name() { or function name { or name() { body }
23
- const funcMatchInline = line.match(/^(?:function\s+)?(\w+)\s*\(\s*\)\s*\{(.+)\}\s*$/);
24
- const funcMatch = funcMatchInline ?? (line.match(/^(?:function\s+)?(\w+)\s*\(\s*\)\s*\{?\s*$/) ||
25
- line.match(/^function\s+(\w+)\s*\{?\s*$/));
23
+ // Shell allows any non-whitespace identifier as function name (incl. ':')
24
+ const funcNamePat = "[^\\s(){}]+";
25
+ const funcMatchInline = line.match(new RegExp(`^(?:function\\s+)?(${funcNamePat})\\s*\\(\\s*\\)\\s*\\{(.+)\\}\\s*$`));
26
+ const funcMatch = funcMatchInline ?? (line.match(new RegExp(`^(?:function\\s+)?(${funcNamePat})\\s*\\(\\s*\\)\\s*\\{?\\s*$`)) ||
27
+ line.match(new RegExp(`^function\\s+(${funcNamePat})\\s*\\{?\\s*$`)));
26
28
  if (funcMatch) {
27
29
  const funcName = funcMatch[1];
28
30
  const body = [];
@@ -60,9 +60,9 @@ function bootstrapEtc(vfs, hostname, props) {
60
60
  ensureFile(vfs, "/etc/profile", `${[
61
61
  "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
62
62
  "if [ \"$(id -u)\" -eq 0 ]; then",
63
- " export PS1='\\[\\e[37;1m\\][\\[\\e[31;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w\\[\\e[37;1m\\]]\\[\\e[31;1m\\]\\$\\[\\e[0m\\] '",
63
+ " export PS1='\\[\\e[37;1m\\][\\[\\e[31;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w]\\[\\e[31;1m\\]\\$\\[\\e[0m\\] '",
64
64
  "else",
65
- " export PS1='\\[\\e[37;1m\\][\\[\\e[35;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w\\[\\e[37;1m\\]]\\[\\e[0m\\]\\$ '",
65
+ " export PS1='\\[\\e[37;1m\\][\\[\\e[35;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w]\\[\\e[0m\\]\\$ '",
66
66
  "fi",
67
67
  ].join("\n")}\n`);
68
68
  ensureFile(vfs, "/etc/issue", "Fortune GNU/Linux 24.04 LTS \\n \\l\n");
@@ -1285,7 +1285,7 @@ Installed-Size: 6800
1285
1285
  Maintainer: Fortune Package Team <dpkg@fortune.local>
1286
1286
  Architecture: amd64
1287
1287
  Version: 1.22.6nyx1
1288
- Depends: libc6 (>= 2.17), libzstd1 (>= 1.5.8)
1288
+ Depends: libc6 (>= 2.17), libzstd1 (>= 1.5.9)
1289
1289
  Description: Fortune package management system
1290
1290
  This package provides the low-level infrastructure for handling the
1291
1291
  installation and removal of Fortune software packages.
@@ -1453,7 +1453,7 @@ function bootstrapRoot(vfs) {
1453
1453
  ensureDir(vfs, "/root/.local/share", 0o755);
1454
1454
  ensureFile(vfs, "/root/.bashrc", `${[
1455
1455
  "# root .bashrc",
1456
- "export PS1='\\[\\e[37;1m\\][\\[\\e[31;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w\\[\\e[37;1m\\]]\\[\\e[31;1m\\]\\$\\[\\e[0m\\] '",
1456
+ "export PS1='\\[\\e[37;1m\\][\\[\\e[31;1m\\]\\u\\[\\e[37;1m\\]@\\[\\e[34;1m\\]\\h\\[\\e[0m\\] \\w]\\[\\e[31;1m\\]\\$\\[\\e[0m\\] '",
1457
1457
  "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
1458
1458
  "export LANG=en_US.UTF-8",
1459
1459
  "alias ll='ls -la'",
@@ -1,5 +1,5 @@
1
- import type { TerminalSize } from "./shellRuntime";
2
1
  import type { ShellStream } from "../types/streams";
2
+ import type { TerminalSize } from "./shellRuntime";
3
3
  export type NanoExitReason = "saved" | "aborted";
4
4
  export interface NanoEditorOptions {
5
5
  stream: ShellStream;
@@ -444,8 +444,14 @@ export class NanoEditor {
444
444
  moveCursor(dRow, _dCol) {
445
445
  this.cursorRow = Math.max(0, Math.min(this.lines.length - 1, this.cursorRow + dRow));
446
446
  this.cursorCol = Math.min(this.cursorCol, this.currentLine().length);
447
+ const prevScrollTop = this.scrollTop;
447
448
  this.clampScroll();
448
- this.renderCursor();
449
+ if (this.scrollTop !== prevScrollTop) {
450
+ this.renderEditArea();
451
+ }
452
+ else {
453
+ this.renderCursor();
454
+ }
449
455
  }
450
456
  moveCursorLeft() {
451
457
  if (this.cursorCol > 0) {
@@ -455,8 +461,14 @@ export class NanoEditor {
455
461
  this.cursorRow--;
456
462
  this.cursorCol = this.currentLine().length;
457
463
  }
464
+ const prevScrollTop = this.scrollTop;
458
465
  this.clampScroll();
459
- this.renderCursor();
466
+ if (this.scrollTop !== prevScrollTop) {
467
+ this.renderEditArea();
468
+ }
469
+ else {
470
+ this.renderCursor();
471
+ }
460
472
  }
461
473
  moveCursorRight() {
462
474
  const line = this.currentLine();
@@ -467,8 +479,14 @@ export class NanoEditor {
467
479
  this.cursorRow++;
468
480
  this.cursorCol = 0;
469
481
  }
482
+ const prevScrollTop = this.scrollTop;
470
483
  this.clampScroll();
471
- this.renderCursor();
484
+ if (this.scrollTop !== prevScrollTop) {
485
+ this.renderEditArea();
486
+ }
487
+ else {
488
+ this.renderCursor();
489
+ }
472
490
  }
473
491
  moveCursorHome() {
474
492
  this.cursorCol = 0;
@@ -483,7 +501,7 @@ export class NanoEditor {
483
501
  this.cursorRow = Math.max(0, Math.min(this.lines.length - 1, this.cursorRow + dir * editRows));
484
502
  this.cursorCol = Math.min(this.cursorCol, this.currentLine().length);
485
503
  this.clampScroll();
486
- this.renderCursor();
504
+ this.renderEditArea();
487
505
  }
488
506
  moveWordRight() {
489
507
  const line = this.currentLine();
@@ -0,0 +1,59 @@
1
+ import type { ShellStream } from "../types/streams";
2
+ import type { TerminalSize } from "./shellRuntime";
3
+ export interface PacmanGameOptions {
4
+ stream: ShellStream;
5
+ terminalSize: TerminalSize;
6
+ onExit: () => void;
7
+ }
8
+ export declare class PacmanGame {
9
+ private stream;
10
+ private onExit;
11
+ private grid;
12
+ private visualGrid;
13
+ private pacR;
14
+ private pacC;
15
+ private pacDir;
16
+ private pacNextDir;
17
+ private pacMouthOpen;
18
+ private pacAlive;
19
+ private ghosts;
20
+ private score;
21
+ private lives;
22
+ private level;
23
+ private dotsTotal;
24
+ private dotsEaten;
25
+ private frightDuration;
26
+ private gameOver;
27
+ private won;
28
+ private msgTicks;
29
+ private msg;
30
+ private globalMode;
31
+ private globalModeTick;
32
+ private readonly modeSchedule;
33
+ private modeIdx;
34
+ private tick;
35
+ private intervalId;
36
+ private inputKey;
37
+ private escBuf;
38
+ private deathTick;
39
+ private deathAnimating;
40
+ private prevLines;
41
+ constructor(opts: PacmanGameOptions);
42
+ private countDots;
43
+ private initGhosts;
44
+ start(): void;
45
+ stop(): void;
46
+ handleInput(chunk: Buffer): void;
47
+ private gameTick;
48
+ private isWalkable;
49
+ private movePacman;
50
+ private activateFright;
51
+ private ghostTarget;
52
+ private moveGhost;
53
+ private checkCollisions;
54
+ private tickFrightCountdowns;
55
+ private respawn;
56
+ private buildLines;
57
+ private renderFull;
58
+ private renderDiff;
59
+ }