Julien Chaumond commited on
Commit
d0aa19c
0 Parent(s):
server/data/personas.json ADDED
The diff for this file is too large to render. See raw diff
 
server/lib/Extensions.ts ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ interface Array<T> {
3
+ randomItem: () => T;
4
+ randomIndex: () => number;
5
+ last: () => T;
6
+ }
7
+
8
+ interface ReadonlyArray<T> {
9
+ randomItem: () => T;
10
+ randomIndex: () => number;
11
+ last: () => T;
12
+ }
13
+
14
+ Array.prototype.randomItem = function() {
15
+ return this[Math.floor(Math.random()*this.length)];
16
+ }
17
+
18
+ Array.prototype.randomIndex = function() {
19
+ return Math.floor(Math.random()*this.length);
20
+ }
21
+
22
+ Array.prototype.last = function() {
23
+ return this[this.length - 1];
24
+ }
25
+
26
+ interface String {
27
+ capitalize: () => string;
28
+ }
29
+
30
+ String.prototype.capitalize = function() {
31
+ return this.charAt(0).toUpperCase() + this.slice(1);
32
+ }
33
+
34
+
35
+ "foo"; // Trick ts-node into actually running the Extensions.ts file.
36
+
server/lib/Log.ts ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as colors from 'colors';
2
+ import * as util from 'util';
3
+
4
+ type ConsoleType = "out" | "info" | "error";
5
+ interface ConsoleTypeData {
6
+ [text: string]: string | undefined;
7
+ }
8
+
9
+ export default class Log {
10
+ private __name: string | undefined;
11
+
12
+ private types: ConsoleTypeData = {
13
+ "out": "white",
14
+ "info": "cyan",
15
+ "error": "red",
16
+ }
17
+
18
+ constructor(name?: string) {
19
+ this.__name = name;
20
+ }
21
+
22
+ private get date(): string {
23
+ return colors.grey(`[${ new Date().toISOString() }] `);
24
+ }
25
+
26
+ private get name(): string {
27
+ return this.__name
28
+ ? `{${ this.__name.toUpperCase() }} `
29
+ : '';
30
+ }
31
+
32
+ private format(...args: any[]) {
33
+ return args.map(o => {
34
+ if (o instanceof Error) {
35
+ return [
36
+ "",
37
+ '-------------------------------------------------------',
38
+ `${o.name} - ${o.message}`,
39
+ '-------------------------------------------------------',
40
+ `${o.stack || 'NO STACK'}`,
41
+ ""
42
+ ].map(l => colors.red(l)).join('\n');
43
+ } else if (typeof o === 'string') {
44
+ return o;
45
+ } else {
46
+ return util.inspect(o, { depth: 20 });
47
+ }
48
+ }).join(' ');
49
+ }
50
+
51
+ print(type: ConsoleType): (...args: any[]) => void {
52
+ return (...args) => {
53
+ const output = this.format(...args);
54
+ const color = this.types[type];
55
+
56
+ for (const line of output.split('\n')) {
57
+ process.stdout.write(`${this.date}${this.name}${ color ? colors[color](line) : line }\n`);
58
+ }
59
+ };
60
+ }
61
+
62
+ static attach(name?: string) {
63
+ const logger = new Log(name);
64
+
65
+ console.log = logger.print("out");
66
+ console.info = logger.print("info");
67
+ console.error = logger.print("error");
68
+ }
69
+ }
70
+
71
+
72
+ export const c = {
73
+ __log: (args: any[], opts: {
74
+ color?: colors.Color,
75
+ colors?: boolean,
76
+ } = {}) => {
77
+ const inspectOpts = (opts.colors !== undefined)
78
+ ? { depth: 20, compact: false, breakLength: Infinity, colors: opts.colors }
79
+ : { depth: 20, compact: false, breakLength: Infinity, colors: true }
80
+ ;
81
+ const s = args.map(o => {
82
+ if (o instanceof Error) {
83
+ // return colors.red(`${o.name}: ${o.message}\n${o.stack}`);
84
+ return (o.stack || `${o.name}: ${o.message}`)
85
+ .split('\n')
86
+ .map(x => colors.red(x))
87
+ .join('\n')
88
+ ;
89
+ } else if (typeof o === 'string') {
90
+ return o;
91
+ } else {
92
+ return util.inspect(o, inspectOpts);
93
+ }
94
+ }).join(' ');
95
+ console.log(opts.color ? opts.color(s) : s);
96
+ },
97
+ log: (...args: any[]) => {
98
+ c.__log(args);
99
+ },
100
+ debug: (...args: any[]) => {
101
+ c.__log(args, { color: colors.gray, colors: false });
102
+ },
103
+ success: (...args: any[]) => {
104
+ c.__log(args, { color: colors.green });
105
+ },
106
+ error: (...args: any[]) => {
107
+ c.__log(args, { color: colors.red });
108
+ },
109
+ info: (...args: any[]) => {
110
+ c.__log(args, { color: colors.cyan });
111
+ },
112
+ introspect: (...args: any[]) => {
113
+ c.__log(args.map(a => [
114
+ a,
115
+ typeof a,
116
+ a.constructor.name,
117
+ ]));
118
+ },
119
+ }
server/lib/RootDirFinder.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { normalize } from 'path';
2
+
3
+ const rootDirFinder = function(): string {
4
+ const parts = __dirname.split('/');
5
+ let level = parts.length - 1;
6
+ while (level > 0) {
7
+ const currentPath = parts.slice(0, level).join('/');
8
+ try {
9
+ require(`${currentPath}/package.json`);
10
+ return currentPath;
11
+ } catch (err) { }
12
+ level --;
13
+ }
14
+ return "";
15
+ };
16
+ const __rootDir: string = normalize(rootDirFinder()+'/..');
17
+
18
+ export default __rootDir;
server/lib/Utils.ts ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ export function capitalize(s: string): string {
3
+ return s.charAt(0).toUpperCase() + s.slice(1);
4
+ }
server/lib/obj.d.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Hf helper type for a dictionary-like object with arbitrary keys.
3
+ */
4
+ declare interface Obj<T = any> {
5
+ [key: string]: T
6
+ }
7
+
8
+ type Extend<T, U = any> = T & Obj<U>;
server/package-lock.json ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "foobar-server",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "@types/body-parser": {
8
+ "version": "1.17.0",
9
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz",
10
+ "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==",
11
+ "requires": {
12
+ "@types/connect": "*",
13
+ "@types/node": "*"
14
+ }
15
+ },
16
+ "@types/connect": {
17
+ "version": "3.4.32",
18
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
19
+ "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==",
20
+ "requires": {
21
+ "@types/node": "*"
22
+ }
23
+ },
24
+ "@types/express": {
25
+ "version": "4.16.1",
26
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.1.tgz",
27
+ "integrity": "sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg==",
28
+ "requires": {
29
+ "@types/body-parser": "*",
30
+ "@types/express-serve-static-core": "*",
31
+ "@types/serve-static": "*"
32
+ }
33
+ },
34
+ "@types/express-serve-static-core": {
35
+ "version": "4.16.4",
36
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.4.tgz",
37
+ "integrity": "sha512-x/8h6FHm14rPWnW2HP5likD/rsqJ3t/77OWx2PLxym0hXbeBWQmcPyHmwX+CtCQpjIfgrUdEoDFcLPwPZWiqzQ==",
38
+ "requires": {
39
+ "@types/node": "*",
40
+ "@types/range-parser": "*"
41
+ }
42
+ },
43
+ "@types/mime": {
44
+ "version": "2.0.1",
45
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
46
+ "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw=="
47
+ },
48
+ "@types/node": {
49
+ "version": "12.0.0",
50
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.0.tgz",
51
+ "integrity": "sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg=="
52
+ },
53
+ "@types/node-fetch": {
54
+ "version": "2.3.3",
55
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.3.3.tgz",
56
+ "integrity": "sha512-MIplfRxrDTsIbOLGyFqNWTmxho5Fs710Kul35tEcaqkx9He86mGbSCDvILL0LCMfmm+oJ8tDg51crE9+pJGgiQ==",
57
+ "requires": {
58
+ "@types/node": "*"
59
+ }
60
+ },
61
+ "@types/range-parser": {
62
+ "version": "1.2.3",
63
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
64
+ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
65
+ },
66
+ "@types/serve-static": {
67
+ "version": "1.13.2",
68
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz",
69
+ "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==",
70
+ "requires": {
71
+ "@types/express-serve-static-core": "*",
72
+ "@types/mime": "*"
73
+ }
74
+ },
75
+ "accepts": {
76
+ "version": "1.3.7",
77
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
78
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
79
+ "requires": {
80
+ "mime-types": "~2.1.24",
81
+ "negotiator": "0.6.2"
82
+ }
83
+ },
84
+ "array-flatten": {
85
+ "version": "1.1.1",
86
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
87
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
88
+ },
89
+ "body-parser": {
90
+ "version": "1.18.3",
91
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
92
+ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
93
+ "requires": {
94
+ "bytes": "3.0.0",
95
+ "content-type": "~1.0.4",
96
+ "debug": "2.6.9",
97
+ "depd": "~1.1.2",
98
+ "http-errors": "~1.6.3",
99
+ "iconv-lite": "0.4.23",
100
+ "on-finished": "~2.3.0",
101
+ "qs": "6.5.2",
102
+ "raw-body": "2.3.3",
103
+ "type-is": "~1.6.16"
104
+ }
105
+ },
106
+ "bytes": {
107
+ "version": "3.0.0",
108
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
109
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
110
+ },
111
+ "colors": {
112
+ "version": "1.3.3",
113
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz",
114
+ "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg=="
115
+ },
116
+ "content-disposition": {
117
+ "version": "0.5.2",
118
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
119
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
120
+ },
121
+ "content-type": {
122
+ "version": "1.0.4",
123
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
124
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
125
+ },
126
+ "cookie": {
127
+ "version": "0.3.1",
128
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
129
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
130
+ },
131
+ "cookie-signature": {
132
+ "version": "1.0.6",
133
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
134
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
135
+ },
136
+ "debug": {
137
+ "version": "2.6.9",
138
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
139
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
140
+ "requires": {
141
+ "ms": "2.0.0"
142
+ }
143
+ },
144
+ "depd": {
145
+ "version": "1.1.2",
146
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
147
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
148
+ },
149
+ "destroy": {
150
+ "version": "1.0.4",
151
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
152
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
153
+ },
154
+ "ee-first": {
155
+ "version": "1.1.1",
156
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
157
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
158
+ },
159
+ "encodeurl": {
160
+ "version": "1.0.2",
161
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
162
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
163
+ },
164
+ "escape-html": {
165
+ "version": "1.0.3",
166
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
167
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
168
+ },
169
+ "etag": {
170
+ "version": "1.8.1",
171
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
172
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
173
+ },
174
+ "express": {
175
+ "version": "4.16.4",
176
+ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
177
+ "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
178
+ "requires": {
179
+ "accepts": "~1.3.5",
180
+ "array-flatten": "1.1.1",
181
+ "body-parser": "1.18.3",
182
+ "content-disposition": "0.5.2",
183
+ "content-type": "~1.0.4",
184
+ "cookie": "0.3.1",
185
+ "cookie-signature": "1.0.6",
186
+ "debug": "2.6.9",
187
+ "depd": "~1.1.2",
188
+ "encodeurl": "~1.0.2",
189
+ "escape-html": "~1.0.3",
190
+ "etag": "~1.8.1",
191
+ "finalhandler": "1.1.1",
192
+ "fresh": "0.5.2",
193
+ "merge-descriptors": "1.0.1",
194
+ "methods": "~1.1.2",
195
+ "on-finished": "~2.3.0",
196
+ "parseurl": "~1.3.2",
197
+ "path-to-regexp": "0.1.7",
198
+ "proxy-addr": "~2.0.4",
199
+ "qs": "6.5.2",
200
+ "range-parser": "~1.2.0",
201
+ "safe-buffer": "5.1.2",
202
+ "send": "0.16.2",
203
+ "serve-static": "1.13.2",
204
+ "setprototypeof": "1.1.0",
205
+ "statuses": "~1.4.0",
206
+ "type-is": "~1.6.16",
207
+ "utils-merge": "1.0.1",
208
+ "vary": "~1.1.2"
209
+ }
210
+ },
211
+ "finalhandler": {
212
+ "version": "1.1.1",
213
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
214
+ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
215
+ "requires": {
216
+ "debug": "2.6.9",
217
+ "encodeurl": "~1.0.2",
218
+ "escape-html": "~1.0.3",
219
+ "on-finished": "~2.3.0",
220
+ "parseurl": "~1.3.2",
221
+ "statuses": "~1.4.0",
222
+ "unpipe": "~1.0.0"
223
+ }
224
+ },
225
+ "forwarded": {
226
+ "version": "0.1.2",
227
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
228
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
229
+ },
230
+ "fresh": {
231
+ "version": "0.5.2",
232
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
233
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
234
+ },
235
+ "http-errors": {
236
+ "version": "1.6.3",
237
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
238
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
239
+ "requires": {
240
+ "depd": "~1.1.2",
241
+ "inherits": "2.0.3",
242
+ "setprototypeof": "1.1.0",
243
+ "statuses": ">= 1.4.0 < 2"
244
+ }
245
+ },
246
+ "iconv-lite": {
247
+ "version": "0.4.23",
248
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
249
+ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
250
+ "requires": {
251
+ "safer-buffer": ">= 2.1.2 < 3"
252
+ }
253
+ },
254
+ "inherits": {
255
+ "version": "2.0.3",
256
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
257
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
258
+ },
259
+ "ipaddr.js": {
260
+ "version": "1.9.0",
261
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
262
+ "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
263
+ },
264
+ "media-typer": {
265
+ "version": "0.3.0",
266
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
267
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
268
+ },
269
+ "merge-descriptors": {
270
+ "version": "1.0.1",
271
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
272
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
273
+ },
274
+ "methods": {
275
+ "version": "1.1.2",
276
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
277
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
278
+ },
279
+ "mime": {
280
+ "version": "1.4.1",
281
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
282
+ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
283
+ },
284
+ "mime-db": {
285
+ "version": "1.40.0",
286
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
287
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
288
+ },
289
+ "mime-types": {
290
+ "version": "2.1.24",
291
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
292
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
293
+ "requires": {
294
+ "mime-db": "1.40.0"
295
+ }
296
+ },
297
+ "ms": {
298
+ "version": "2.0.0",
299
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
300
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
301
+ },
302
+ "negotiator": {
303
+ "version": "0.6.2",
304
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
305
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
306
+ },
307
+ "node-fetch": {
308
+ "version": "2.5.0",
309
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
310
+ "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
311
+ },
312
+ "on-finished": {
313
+ "version": "2.3.0",
314
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
315
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
316
+ "requires": {
317
+ "ee-first": "1.1.1"
318
+ }
319
+ },
320
+ "parseurl": {
321
+ "version": "1.3.3",
322
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
323
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
324
+ },
325
+ "path-to-regexp": {
326
+ "version": "0.1.7",
327
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
328
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
329
+ },
330
+ "proxy-addr": {
331
+ "version": "2.0.5",
332
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
333
+ "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
334
+ "requires": {
335
+ "forwarded": "~0.1.2",
336
+ "ipaddr.js": "1.9.0"
337
+ }
338
+ },
339
+ "qs": {
340
+ "version": "6.5.2",
341
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
342
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
343
+ },
344
+ "range-parser": {
345
+ "version": "1.2.0",
346
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
347
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
348
+ },
349
+ "raw-body": {
350
+ "version": "2.3.3",
351
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
352
+ "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
353
+ "requires": {
354
+ "bytes": "3.0.0",
355
+ "http-errors": "1.6.3",
356
+ "iconv-lite": "0.4.23",
357
+ "unpipe": "1.0.0"
358
+ }
359
+ },
360
+ "safe-buffer": {
361
+ "version": "5.1.2",
362
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
363
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
364
+ },
365
+ "safer-buffer": {
366
+ "version": "2.1.2",
367
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
368
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
369
+ },
370
+ "send": {
371
+ "version": "0.16.2",
372
+ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
373
+ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
374
+ "requires": {
375
+ "debug": "2.6.9",
376
+ "depd": "~1.1.2",
377
+ "destroy": "~1.0.4",
378
+ "encodeurl": "~1.0.2",
379
+ "escape-html": "~1.0.3",
380
+ "etag": "~1.8.1",
381
+ "fresh": "0.5.2",
382
+ "http-errors": "~1.6.2",
383
+ "mime": "1.4.1",
384
+ "ms": "2.0.0",
385
+ "on-finished": "~2.3.0",
386
+ "range-parser": "~1.2.0",
387
+ "statuses": "~1.4.0"
388
+ }
389
+ },
390
+ "serve-static": {
391
+ "version": "1.13.2",
392
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
393
+ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
394
+ "requires": {
395
+ "encodeurl": "~1.0.2",
396
+ "escape-html": "~1.0.3",
397
+ "parseurl": "~1.3.2",
398
+ "send": "0.16.2"
399
+ }
400
+ },
401
+ "setprototypeof": {
402
+ "version": "1.1.0",
403
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
404
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
405
+ },
406
+ "statuses": {
407
+ "version": "1.4.0",
408
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
409
+ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
410
+ },
411
+ "type-is": {
412
+ "version": "1.6.18",
413
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
414
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
415
+ "requires": {
416
+ "media-typer": "0.3.0",
417
+ "mime-types": "~2.1.24"
418
+ }
419
+ },
420
+ "unpipe": {
421
+ "version": "1.0.0",
422
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
423
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
424
+ },
425
+ "utils-merge": {
426
+ "version": "1.0.1",
427
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
428
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
429
+ },
430
+ "vary": {
431
+ "version": "1.1.2",
432
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
433
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
434
+ }
435
+ }
436
+ }
server/package.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "foobar-server",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "@types/express": "^4.16.1",
13
+ "@types/node": "^12.0.0",
14
+ "@types/node-fetch": "^2.3.3",
15
+ "colors": "^1.3.3",
16
+ "express": "^4.16.4",
17
+ "node-fetch": "^2.5.0"
18
+ }
19
+ }
server/personalities.ts ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const __ = require('./lib/Extensions');
2
+ import * as fs from 'fs';
3
+ import fetch from 'node-fetch';
4
+ import { c } from './lib/Log';
5
+ import __rootDir from './lib/RootDirFinder';
6
+
7
+ (async () => {
8
+ const response = await fetch(`http://pouet.eastus.cloudapp.azure.com:8080/personality/all?all=true`, {
9
+ method: 'POST',
10
+ });
11
+ const personas = (await response.json()).personality as string[];
12
+ c.debug(`Personas from server: ${personas.length}`);
13
+ c.debug(`Deduped: ${ (new Set(personas)).size }`);
14
+
15
+ const o: Obj<string> = {};
16
+ for (const persona of personas) {
17
+ const slug = persona
18
+ .replace(/\W/g, '-')
19
+ .replace(/-+$/, "") // <- trim trailing dash
20
+ .replace(/--+/g, "-") // <- never allow more than one consecutive dash
21
+ ;
22
+ o[slug] = persona;
23
+ }
24
+ c.debug(
25
+ `After slugification: ${ (new Set(Object.keys(o))).size }`
26
+ );
27
+
28
+ await fs.promises.writeFile(
29
+ __rootDir+`/server/data/personas.json`,
30
+ JSON.stringify(o, null, 2)
31
+ );
32
+ process.exit();
33
+ })();
34
+
server/server.ts ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const __ = require('./lib/Extensions');
2
+ import * as fs from 'fs';
3
+ import * as express from 'express';
4
+ import __rootDir from './lib/RootDirFinder';
5
+ import { c } from './lib/Log';
6
+ import * as Utils from './lib/Utils';
7
+ const app = express();
8
+ const PORT = 3000;
9
+ const __frontDir = __rootDir+`/front`;
10
+
11
+ // Express setup
12
+ app.set('trust proxy', 'loopback');
13
+ const staticHandler = express.static(__frontDir);
14
+ const staticHandlerNoHtml: express.RequestHandler = function(req, res, next) {
15
+ if (req.path === '/' || req.path.endsWith('.html')) {
16
+ return next();
17
+ } else {
18
+ return staticHandler(req, res, next);
19
+ }
20
+ };
21
+ app.use(staticHandlerNoHtml);
22
+
23
+ const PERSONAS = {
24
+ MAP: new Map<string, string>(), /// <- <slug, text>
25
+ LST: [] as { slug: string, text: string }[],
26
+ };
27
+ (async () => {
28
+ const o: Obj<string> = JSON.parse(await fs.promises.readFile(__rootDir+`/server/data/personas.json`, 'utf8'));
29
+ for (const [k, v] of Object.entries(o)) {
30
+ PERSONAS.MAP.set(k, v);
31
+ PERSONAS.LST.push({ slug: k, text: v });
32
+ }
33
+ c.debug(`personas:loaded`);
34
+ })();
35
+
36
+
37
+ const templateHtml = async (slug: string, text: string): Promise<string> => {
38
+ const jsStr = `window.PERSONA_FOOBAR = ${ JSON.stringify({ slug, text }) };`;
39
+ /// Transform text. Should be the exact same function client-side.
40
+ const persona = text.split('.').map(x => Utils.capitalize(x)).join(`.<br>`);
41
+ let s = await fs.promises.readFile(__frontDir+`/index.html`, 'utf8');
42
+ s = s.replace('/* //u */', jsStr);
43
+ s = s.replace('<!-- p -->', persona);
44
+ return s;
45
+ }
46
+
47
+ // GET /
48
+
49
+ app.get('/', async function(req, res) {
50
+ const p = PERSONAS.LST.randomItem();
51
+ res.send(
52
+ await templateHtml(p.slug, p.text)
53
+ );
54
+ });
55
+
56
+ // GET persona/:slug
57
+
58
+ app.get('/persona/:slug', async function(req, res) {
59
+ const slug: string = req.params.slug;
60
+ const text = PERSONAS.MAP.get(slug);
61
+ if (!text) {
62
+ return res.redirect('/');
63
+ }
64
+ res.send(
65
+ await templateHtml(slug, text)
66
+ );
67
+ });
68
+
69
+ // GET /shuffle
70
+
71
+ app.get('/shuffle', function(req, res) {
72
+ res.json(
73
+ PERSONAS.LST.randomItem()
74
+ );
75
+ });
76
+
77
+
78
+ // Start engine.
79
+
80
+ app.listen(PORT, () => {
81
+ c.debug(`Running on ${PORT}`);
82
+ });
server/supervisor.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #!/bin/bash
2
+ supervisor -w dist/ dist/server.js
server/tsconfig.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2018",
4
+ "module": "commonjs",
5
+ "outDir": "dist/",
6
+ "strictNullChecks": true,
7
+ "strictBindCallApply": true,
8
+ "lib": ["es6", "es2016", "es2017", "es2018", "esnext"]
9
+ }
10
+ }