make-mp-data 1.5.0 → 1.5.2
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.
- package/.gcloudignore +17 -0
- package/.vscode/launch.json +54 -19
- package/.vscode/settings.json +2 -0
- package/.vscode/tasks.json +12 -0
- package/components/ai.js +93 -0
- package/{src → components}/chart.js +14 -0
- package/{src → components}/cli.js +7 -1
- package/components/project.js +166 -0
- package/components/prompt.txt +98 -0
- package/{src → components}/utils.js +142 -41
- package/{schemas → dungeons}/adspend.js +2 -2
- package/{schemas → dungeons}/anon.js +2 -2
- package/{schemas → dungeons}/big.js +2 -2
- package/dungeons/business.js +327 -0
- package/{schemas → dungeons}/complex.js +10 -10
- package/dungeons/foobar.js +241 -0
- package/{schemas → dungeons}/funnels.js +3 -4
- package/dungeons/gaming.js +314 -0
- package/{schemas → dungeons}/mirror.js +2 -2
- package/{schemas/foobar.js → dungeons/sanity.js} +20 -27
- package/dungeons/scd.js +205 -0
- package/dungeons/session-replay.js +175 -0
- package/{schemas → dungeons}/simple.js +3 -3
- package/dungeons/userAgent.js +190 -0
- package/env.yaml +1 -0
- package/index.js +482 -167
- package/package.json +13 -6
- package/scripts/deploy.sh +11 -0
- package/scripts/jsdoctest.js +1 -1
- package/scripts/{new.sh → new-dungeon.sh} +39 -10
- package/scripts/new-project.mjs +14 -0
- package/scripts/update-deps.sh +4 -0
- package/tests/benchmark/concurrency.mjs +2 -2
- package/tests/cli.test.js +121 -0
- package/tests/e2e.test.js +134 -186
- package/tests/int.test.js +14 -12
- package/tests/jest.config.js +8 -0
- package/tests/testCases.mjs +1 -1
- package/tests/testSoup.mjs +4 -3
- package/tests/unit.test.js +16 -15
- package/tsconfig.json +1 -1
- package/types.d.ts +40 -8
- package/scripts/deps.sh +0 -3
- /package/{src → components}/defaults.js +0 -0
- /package/dungeons/{.gitkeep → customers/.gitkeep} +0 -0
- /package/scripts/{go.sh → run-index.sh} +0 -0
|
@@ -12,7 +12,7 @@ dayjs.extend(utc);
|
|
|
12
12
|
require('dotenv').config();
|
|
13
13
|
const { domainSuffix, domainPrefix } = require('./defaults');
|
|
14
14
|
|
|
15
|
-
/** @typedef {import('../types').
|
|
15
|
+
/** @typedef {import('../types').Dungeon} Config */
|
|
16
16
|
/** @typedef {import('../types').EventConfig} EventConfig */
|
|
17
17
|
/** @typedef {import('../types').ValueValid} ValueValid */
|
|
18
18
|
/** @typedef {import('../types').HookedArray} hookArray */
|
|
@@ -23,6 +23,7 @@ const { domainSuffix, domainPrefix } = require('./defaults');
|
|
|
23
23
|
let globalChance;
|
|
24
24
|
let chanceInitialized = false;
|
|
25
25
|
|
|
26
|
+
const ACTUAL_NOW = dayjs.utc();
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
/*
|
|
@@ -96,7 +97,8 @@ function pick(items) {
|
|
|
96
97
|
*/
|
|
97
98
|
function date(inTheLast = 30, isPast = true, format = 'YYYY-MM-DD') {
|
|
98
99
|
const chance = getChance();
|
|
99
|
-
const now = global.
|
|
100
|
+
// const now = global.FIXED_NOW ? dayjs.unix(global.FIXED_NOW) : dayjs();
|
|
101
|
+
const now = ACTUAL_NOW;
|
|
100
102
|
if (Math.abs(inTheLast) > 365 * 10) inTheLast = chance.integer({ min: 1, max: 180 });
|
|
101
103
|
return function () {
|
|
102
104
|
const when = chance.integer({ min: 0, max: Math.abs(inTheLast) });
|
|
@@ -149,14 +151,17 @@ function datesBetween(start, end) {
|
|
|
149
151
|
/**
|
|
150
152
|
* returns a random date
|
|
151
153
|
* @param {any} start
|
|
152
|
-
* @param {any} end
|
|
154
|
+
* @param {any} end
|
|
153
155
|
*/
|
|
154
|
-
function day(start, end
|
|
156
|
+
function day(start, end) {
|
|
157
|
+
// if (!end) end = global.FIXED_NOW ? global.FIXED_NOW : dayjs().unix();
|
|
158
|
+
if (!start) start = ACTUAL_NOW.subtract(30, 'd').toISOString();
|
|
159
|
+
if (!end) end = ACTUAL_NOW.toISOString();
|
|
155
160
|
const chance = getChance();
|
|
156
161
|
const format = 'YYYY-MM-DD';
|
|
157
162
|
return function (min, max) {
|
|
158
163
|
start = dayjs(start);
|
|
159
|
-
end = dayjs
|
|
164
|
+
end = dayjs(end);
|
|
160
165
|
const diff = end.diff(start, 'day');
|
|
161
166
|
const delta = chance.integer({ min: min, max: diff });
|
|
162
167
|
const day = start.add(delta, 'day');
|
|
@@ -174,18 +179,30 @@ function day(start, end = global.NOW) {
|
|
|
174
179
|
* @param {ValueValid} value
|
|
175
180
|
*/
|
|
176
181
|
function choose(value) {
|
|
182
|
+
let wasFunctionCalled = false;
|
|
177
183
|
const chance = getChance();
|
|
184
|
+
|
|
178
185
|
try {
|
|
179
186
|
// Keep resolving the value if it's a function
|
|
180
187
|
while (typeof value === 'function') {
|
|
181
188
|
value = value();
|
|
189
|
+
wasFunctionCalled = true;
|
|
182
190
|
}
|
|
183
191
|
|
|
192
|
+
// allow functions which create arrays of objects to pass through
|
|
193
|
+
// if (Array.isArray(value) && wasFunctionCalled && value.length > 1 && value[0] === null) {
|
|
194
|
+
// return value.slice(1);
|
|
195
|
+
// }
|
|
196
|
+
|
|
184
197
|
// Now, if the resolved value is an array, use chance.pickone
|
|
185
|
-
if (Array.isArray(value)) {
|
|
198
|
+
if (Array.isArray(value) && !wasFunctionCalled) {
|
|
186
199
|
return chance.pickone(value);
|
|
187
200
|
}
|
|
188
201
|
|
|
202
|
+
if (Array.isArray(value) && wasFunctionCalled) {
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
|
|
189
206
|
if (typeof value === 'string') {
|
|
190
207
|
return value;
|
|
191
208
|
}
|
|
@@ -199,6 +216,7 @@ function choose(value) {
|
|
|
199
216
|
}
|
|
200
217
|
catch (e) {
|
|
201
218
|
console.error(`\n\nerror on value: ${value};\n\n`, e, '\n\n');
|
|
219
|
+
throw e;
|
|
202
220
|
return '';
|
|
203
221
|
}
|
|
204
222
|
}
|
|
@@ -311,6 +329,58 @@ function range(a, b, step = 1) {
|
|
|
311
329
|
};
|
|
312
330
|
|
|
313
331
|
|
|
332
|
+
function companyName(words = 2, separator = " ") {
|
|
333
|
+
const industryAdjectives = ["advanced", "premier", "integrated", "optimized", "comprehensive", "expert",
|
|
334
|
+
"visionary", "progressive", "transformative", "pioneering", "streamlined",
|
|
335
|
+
"cutting-edge", "impactful", "purpose-driven", "value-oriented", "future-ready",
|
|
336
|
+
"scalable", "responsive", "data-driven", "cloud-based", "user-friendly",
|
|
337
|
+
"high-performance", "secure", "compliant", "ethical", "inclusive",
|
|
338
|
+
"transparent", "community-focused", "environmentally-conscious", "socially-responsible", "innovative", "dynamic", "global", "leading", "reliable", "trusted",
|
|
339
|
+
"strategic", "efficient", "sustainable", "creative", "agile", "resilient",
|
|
340
|
+
"collaborative", "customer-centric", "forward-thinking", "results-driven", "gizmo", "contraption", "doodle", "whimsy", "quirk", "spark", "zing",
|
|
341
|
+
"zap", "pop", "fizz", "whirl", "twirl", "swirl", "jumble", "tumble",
|
|
342
|
+
"hodgepodge", "mishmash", "kaleidoscope", "labyrinth", "maze", "puzzle",
|
|
343
|
+
"enigma", "conundrum", "paradox", "oxymoron", "chimera", "centaur",
|
|
344
|
+
"griffin", "phoenix", "unicorn", "dragon", "mermaid", "yeti", "bigfoot",
|
|
345
|
+
"loch ness monster", "chupacabra", "kraken", "leviathan", "behemoth",
|
|
346
|
+
"juggernaut", "goliath", "david", "odyssey", "pilgrimage", "crusade",
|
|
347
|
+
"quest", "adventure", "escapade", "frolic", "romp", "lark", "spree",
|
|
348
|
+
"binge", "jag", "bender", "tear", "rampage", "riot", "ruckus", "rumpus",
|
|
349
|
+
"hullabaloo", "brouhaha", "kerfuffle", "shindig", "hootenanny", "jamboree",
|
|
350
|
+
"fiesta", "carnival", "gala", "soiree", "bash", "fete", "jubilee"
|
|
351
|
+
|
|
352
|
+
];
|
|
353
|
+
|
|
354
|
+
const companyNouns = [
|
|
355
|
+
"solutions", "group", "partners", "ventures", "holdings", "enterprises",
|
|
356
|
+
"systems", "technologies", "innovations", "associates", "corporation", "inc.",
|
|
357
|
+
"ltd.", "plc.", "gmbh", "s.a.", "llc.", "network", "alliance", "consortium", "collective", "foundation", "institute",
|
|
358
|
+
"laboratory", "agency", "bureau", "department", "division", "branch",
|
|
359
|
+
"office", "center", "hub", "platform", "ecosystem", "marketplace",
|
|
360
|
+
"exchange", "clearinghouse", "repository", "archive", "registry",
|
|
361
|
+
"database", "framework", "infrastructure", "architecture", "protocol",
|
|
362
|
+
"standard", "specification", "guideline", "blueprint", "roadmap",
|
|
363
|
+
"strategy", "plan", "initiative", "program", "project", "campaign",
|
|
364
|
+
"operation", "mission", "task", "force", "team", "crew", "squad",
|
|
365
|
+
"unit", "cell", "pod", "cohort", "community", "network", "circle",
|
|
366
|
+
"forum", "council", "board", "committee", "panel", "jury", "tribunal"
|
|
367
|
+
];
|
|
368
|
+
|
|
369
|
+
let name = "";
|
|
370
|
+
const cycle = [industryAdjectives, companyNouns];
|
|
371
|
+
for (let i = 0; i < words; i++) {
|
|
372
|
+
const index = i % cycle.length;
|
|
373
|
+
const word = cycle[index][Math.floor(Math.random() * cycle[index].length)];
|
|
374
|
+
if (name === "") {
|
|
375
|
+
name = word;
|
|
376
|
+
} else {
|
|
377
|
+
name += separator + word;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return name;
|
|
382
|
+
}
|
|
383
|
+
|
|
314
384
|
|
|
315
385
|
/*
|
|
316
386
|
----
|
|
@@ -628,13 +698,13 @@ function validateEventConfig(events) {
|
|
|
628
698
|
}
|
|
629
699
|
|
|
630
700
|
function validTime(chosenTime, earliestTime, latestTime) {
|
|
631
|
-
if (!earliestTime) earliestTime = global.
|
|
632
|
-
if (!latestTime) latestTime = global.
|
|
701
|
+
if (!earliestTime) earliestTime = global.FIXED_BEGIN ? global.FIXED_BEGIN : dayjs().subtract(30, 'd').unix(); // 30 days ago
|
|
702
|
+
if (!latestTime) latestTime = global.FIXED_NOW ? global.FIXED_NOW : dayjs().unix();
|
|
633
703
|
|
|
634
704
|
if (typeof chosenTime === 'number') {
|
|
635
705
|
if (chosenTime > 0) {
|
|
636
706
|
if (chosenTime > earliestTime) {
|
|
637
|
-
if (chosenTime < latestTime) {
|
|
707
|
+
if (chosenTime < (latestTime)) {
|
|
638
708
|
return true;
|
|
639
709
|
}
|
|
640
710
|
|
|
@@ -808,8 +878,8 @@ let soupHits = 0;
|
|
|
808
878
|
* @param {number} [peaks=5]
|
|
809
879
|
*/
|
|
810
880
|
function TimeSoup(earliestTime, latestTime, peaks = 5, deviation = 2, mean = 0) {
|
|
811
|
-
if (!earliestTime) earliestTime = global.
|
|
812
|
-
if (!latestTime) latestTime = global.
|
|
881
|
+
if (!earliestTime) earliestTime = global.FIXED_BEGIN ? global.FIXED_BEGIN : dayjs().subtract(30, 'd').unix(); // 30 days ago
|
|
882
|
+
if (!latestTime) latestTime = global.FIXED_NOW ? global.FIXED_NOW : dayjs().unix();
|
|
813
883
|
const chance = getChance();
|
|
814
884
|
const totalRange = latestTime - earliestTime;
|
|
815
885
|
const chunkSize = totalRange / peaks;
|
|
@@ -871,7 +941,9 @@ function person(userId, bornDaysAgo = 30, isAnonymous = false, hasAvatar = false
|
|
|
871
941
|
let randomAvatarNumber = integer(1, 99);
|
|
872
942
|
let avPath = gender === 'male' ? `/men/${randomAvatarNumber}.jpg` : `/women/${randomAvatarNumber}.jpg`;
|
|
873
943
|
let avatar = avatarPrefix + avPath;
|
|
874
|
-
let created = dayjs
|
|
944
|
+
let created = dayjs().subtract(bornDaysAgo, 'day').format('YYYY-MM-DD');
|
|
945
|
+
|
|
946
|
+
|
|
875
947
|
// const created = date(bornDaysAgo, true)();
|
|
876
948
|
|
|
877
949
|
|
|
@@ -920,36 +992,64 @@ function person(userId, bornDaysAgo = 30, isAnonymous = false, hasAvatar = false
|
|
|
920
992
|
};
|
|
921
993
|
|
|
922
994
|
|
|
923
|
-
|
|
995
|
+
function wrapFunc(obj, func, recursion = 0, parentKey = null, grandParentKey = null, whitelist = [
|
|
996
|
+
"events",
|
|
997
|
+
"superProps",
|
|
998
|
+
"userProps",
|
|
999
|
+
"scdProps",
|
|
1000
|
+
"mirrorProps",
|
|
1001
|
+
"groupEvents",
|
|
1002
|
+
"groupProps"
|
|
1003
|
+
]) {
|
|
1004
|
+
if (recursion === 0) {
|
|
1005
|
+
// Only process top-level keys in the whitelist
|
|
1006
|
+
for (const key in obj) {
|
|
1007
|
+
if (whitelist.includes(key)) {
|
|
1008
|
+
obj[key] = wrapFunc(obj[key], func, recursion + 1, key, null, whitelist);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
} else {
|
|
1012
|
+
if (Array.isArray(obj) && grandParentKey === 'properties') {
|
|
1013
|
+
return func(obj);
|
|
1014
|
+
} else if (typeof obj === 'object' && obj !== null) {
|
|
1015
|
+
for (const key in obj) {
|
|
1016
|
+
if (obj.hasOwnProperty(key)) {
|
|
1017
|
+
obj[key] = wrapFunc(obj[key], func, recursion + 1, key, parentKey, whitelist);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return obj;
|
|
1023
|
+
}
|
|
924
1024
|
|
|
925
1025
|
//UNUSED
|
|
926
1026
|
|
|
927
|
-
function fixFunkyTime(earliestTime, latestTime) {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
}
|
|
1027
|
+
// function fixFunkyTime(earliestTime, latestTime) {
|
|
1028
|
+
// if (!earliestTime) earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
|
|
1029
|
+
// // if (typeof earliestTime !== "number") {
|
|
1030
|
+
// // if (parseInt(earliestTime) > 0) earliestTime = parseInt(earliestTime);
|
|
1031
|
+
// // if (dayjs(earliestTime).isValid()) earliestTime = dayjs(earliestTime).unix();
|
|
1032
|
+
// // }
|
|
1033
|
+
// if (typeof earliestTime !== "number") earliestTime = dayjs.unix(earliestTime).unix();
|
|
1034
|
+
// if (typeof latestTime !== "number") latestTime = global.NOW;
|
|
1035
|
+
// if (typeof latestTime === "number" && latestTime > global.NOW) latestTime = global.NOW;
|
|
1036
|
+
// if (earliestTime > latestTime) {
|
|
1037
|
+
// const tempEarlyTime = earliestTime;
|
|
1038
|
+
// const tempLateTime = latestTime;
|
|
1039
|
+
// earliestTime = tempLateTime;
|
|
1040
|
+
// latestTime = tempEarlyTime;
|
|
1041
|
+
// }
|
|
1042
|
+
// if (earliestTime === latestTime) {
|
|
1043
|
+
// earliestTime = dayjs.unix(earliestTime)
|
|
1044
|
+
// .subtract(integer(1, 14), "day")
|
|
1045
|
+
// .subtract(integer(1, 23), "hour")
|
|
1046
|
+
// .subtract(integer(1, 59), "minute")
|
|
1047
|
+
// .subtract(integer(1, 59), "second")
|
|
1048
|
+
// .unix();
|
|
1049
|
+
// }
|
|
1050
|
+
// return [earliestTime, latestTime];
|
|
1051
|
+
|
|
1052
|
+
// }
|
|
953
1053
|
|
|
954
1054
|
|
|
955
1055
|
|
|
@@ -984,7 +1084,7 @@ module.exports = {
|
|
|
984
1084
|
exhaust,
|
|
985
1085
|
integer,
|
|
986
1086
|
TimeSoup,
|
|
987
|
-
|
|
1087
|
+
companyName,
|
|
988
1088
|
generateEmoji,
|
|
989
1089
|
|
|
990
1090
|
|
|
@@ -1020,5 +1120,6 @@ module.exports = {
|
|
|
1020
1120
|
streamJSON,
|
|
1021
1121
|
streamCSV,
|
|
1022
1122
|
datesBetween,
|
|
1023
|
-
weighChoices
|
|
1123
|
+
weighChoices,
|
|
1124
|
+
wrapFunc,
|
|
1024
1125
|
};
|
|
@@ -14,9 +14,9 @@ const dayjs = require("dayjs");
|
|
|
14
14
|
const utc = require("dayjs/plugin/utc");
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
const { uid, comma } = require('ak-tools');
|
|
17
|
-
const { pickAWinner, weighNumRange, date, integer } = require('../
|
|
17
|
+
const { pickAWinner, weighNumRange, date, integer } = require('../components/utils');
|
|
18
18
|
|
|
19
|
-
/** @type {import('../types').
|
|
19
|
+
/** @type {import('../types').Dungeon} */
|
|
20
20
|
const config = {
|
|
21
21
|
token: "",
|
|
22
22
|
seed: "foo bar",
|
|
@@ -14,11 +14,11 @@ const dayjs = require("dayjs");
|
|
|
14
14
|
const utc = require("dayjs/plugin/utc");
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
const { uid, comma } = require('ak-tools');
|
|
17
|
-
const { pickAWinner, weighNumRange, date, integer } = require('../
|
|
17
|
+
const { pickAWinner, weighNumRange, date, integer } = require('../components/utils');
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
/** @type {import('../types').
|
|
21
|
+
/** @type {import('../types').Dungeon} */
|
|
22
22
|
const config = {
|
|
23
23
|
token: "",
|
|
24
24
|
seed: "foo bar",
|
|
@@ -16,9 +16,9 @@ const dayjs = require("dayjs");
|
|
|
16
16
|
const utc = require("dayjs/plugin/utc");
|
|
17
17
|
dayjs.extend(utc);
|
|
18
18
|
const { uid, comma } = require('ak-tools');
|
|
19
|
-
const { pickAWinner, weighNumRange, date, integer } = require('../
|
|
19
|
+
const { pickAWinner, weighNumRange, date, integer } = require('../components/utils');
|
|
20
20
|
|
|
21
|
-
/** @type {import('../types').
|
|
21
|
+
/** @type {import('../types').Dungeon} */
|
|
22
22
|
const config = {
|
|
23
23
|
token: "",
|
|
24
24
|
seed: "lets go",
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the default configuration file for the data generator in COMPLEX mode
|
|
3
|
+
* notice how the config object is structured, and see it's type definition in ./types.d.ts
|
|
4
|
+
* feel free to modify this file to customize the data you generate
|
|
5
|
+
* see helper functions in utils.js for more ways to generate data
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const Chance = require('chance');
|
|
10
|
+
const chance = new Chance();
|
|
11
|
+
const { weighNumRange, date, integer, pickAWinner, exhaust } = require('../components/utils.js');
|
|
12
|
+
const u = require('ak-tools');
|
|
13
|
+
|
|
14
|
+
const channel_ids = [...Array(1234).keys()].map(i => i + 1).map(n => `channel_id_${n}`);
|
|
15
|
+
const channel_names = chance.n(u.makeName, 1234);
|
|
16
|
+
const video_ids = [...Array(50000).keys()].map(i => i + 1).map(n => n.toString());
|
|
17
|
+
const video_names = chance.n(u.makeName, 50000);
|
|
18
|
+
|
|
19
|
+
const EVENTS = 50_000
|
|
20
|
+
const USERS = EVENTS / 100
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/** @type {import('../types.js').Dungeon} */
|
|
24
|
+
const config = {
|
|
25
|
+
token: "",
|
|
26
|
+
seed: "it's business time...",
|
|
27
|
+
numDays: 90, //how many days worth of data
|
|
28
|
+
numEvents: EVENTS, //how many events
|
|
29
|
+
numUsers: USERS, //how many users
|
|
30
|
+
format: 'json', //csv or json
|
|
31
|
+
region: "US",
|
|
32
|
+
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
33
|
+
hasSessionIds: false, //if true, hasSessionIds are created for each user
|
|
34
|
+
hasLocation: true,
|
|
35
|
+
hasAndroidDevices: true,
|
|
36
|
+
hasIOSDevices: true,
|
|
37
|
+
hasDesktopDevices: true,
|
|
38
|
+
hasBrowser: true,
|
|
39
|
+
hasCampaigns: true,
|
|
40
|
+
isAnonymous: false,
|
|
41
|
+
hasAdSpend: true,
|
|
42
|
+
|
|
43
|
+
hasAvatar: false,
|
|
44
|
+
makeChart: true,
|
|
45
|
+
|
|
46
|
+
batchSize: 500_000,
|
|
47
|
+
concurrency: 500,
|
|
48
|
+
|
|
49
|
+
funnels: [
|
|
50
|
+
{
|
|
51
|
+
sequence: ["watch video", "like video", "subscribe", "purchase video"],
|
|
52
|
+
conversionRate: 35,
|
|
53
|
+
props: {
|
|
54
|
+
channel_id: pickAWinner(channel_ids),
|
|
55
|
+
video_id: weighNumRange(1, 50000, 1.4),
|
|
56
|
+
category: pickAWinner(["funny", "educational", "music", "news", "sports", "cooking", "DIY", "travel", "gaming"]),
|
|
57
|
+
isFeatured: () => { chance.bool({ likelihood: 25 }); },
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
sequence: ["watch video", "dislike video"],
|
|
62
|
+
conversionRate: 10,
|
|
63
|
+
order: "sequential",
|
|
64
|
+
props: {
|
|
65
|
+
channel_id: pickAWinner(channel_ids),
|
|
66
|
+
video_id: weighNumRange(1, 50000, .67),
|
|
67
|
+
category: pickAWinner(["funny", "educational", "music", "news", "sports", "cooking", "DIY", "travel", "gaming"]),
|
|
68
|
+
isFeatured: () => { chance.bool({ likelihood: 25 }); },
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
events: [
|
|
73
|
+
{
|
|
74
|
+
"event": "watch video",
|
|
75
|
+
"weight": 75,
|
|
76
|
+
"properties": {
|
|
77
|
+
"#hashtags": makeHashTags,
|
|
78
|
+
"watch time (sec)": weighNumRange(10, 600, .25),
|
|
79
|
+
"quality": pickAWinner(["2160p", "1440p", "1080p", "720p", "480p", "360p", "240p"], 1)
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"event": "like video",
|
|
84
|
+
"weight": 30,
|
|
85
|
+
"properties": {
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"event": "dislike video",
|
|
91
|
+
"weight": 15,
|
|
92
|
+
"properties": {
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"event": "subscribe",
|
|
98
|
+
"weight": 10,
|
|
99
|
+
"properties": {
|
|
100
|
+
"UI": pickAWinner(["button", "link", "modal", "menu"]),
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"event": "search",
|
|
105
|
+
"weight": 10,
|
|
106
|
+
"properties": {
|
|
107
|
+
term: () => { return chance.word(); },
|
|
108
|
+
"# results": weighNumRange(1, 100, .25),
|
|
109
|
+
"UI": pickAWinner(["button", "link", "modal", "menu"]),
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"event": "comment",
|
|
114
|
+
"weight": 6,
|
|
115
|
+
"properties": {
|
|
116
|
+
length: weighNumRange(1, 500, .25),
|
|
117
|
+
video_id: weighNumRange(1, 50000, .72),
|
|
118
|
+
"has replies": [true, false, false, false, false],
|
|
119
|
+
"has photos": [true, false, false, false, false],
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"event": "save video",
|
|
125
|
+
"weight": 17,
|
|
126
|
+
"properties": {
|
|
127
|
+
video_id: weighNumRange(1, 50000, 1.4),
|
|
128
|
+
UI: pickAWinner(["toolbar", "menu", "keyboard"])
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"event": "create playlist",
|
|
134
|
+
"weight": 5,
|
|
135
|
+
"properties": {
|
|
136
|
+
"# of videos": weighNumRange(1, 100, .25),
|
|
137
|
+
"UI": pickAWinner(["toolbar", "menu", "keyboard"]),
|
|
138
|
+
"visibility": pickAWinner(["public", "private", "unlisted"]),
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"event": "purchase video",
|
|
143
|
+
"weight": 12,
|
|
144
|
+
"properties": {
|
|
145
|
+
video_id: weighNumRange(1, 50000, 1.4),
|
|
146
|
+
basket: makeProducts(5),
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"event": "support ticket",
|
|
153
|
+
"weight": 10,
|
|
154
|
+
"properties": {
|
|
155
|
+
description: chance.sentence.bind(chance),
|
|
156
|
+
severity: ["low", "medium", "high"],
|
|
157
|
+
ticket_id: chance.guid.bind(chance)
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"event": "app error",
|
|
162
|
+
"weight": 15,
|
|
163
|
+
"properties": {
|
|
164
|
+
code: pickAWinner(["404", "500", "403", "401", "400", "503", "504", "429"]),
|
|
165
|
+
error: chance.sentence.bind(chance),
|
|
166
|
+
component: pickAWinner(["video player", "search", "comment", "profile", "settings", "billing", "support"]),
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"event": "sign up",
|
|
171
|
+
"isFirstEvent": true,
|
|
172
|
+
"weight": 0,
|
|
173
|
+
"properties": {
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
superProps: {
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
},
|
|
182
|
+
/*
|
|
183
|
+
user properties work the same as event properties
|
|
184
|
+
each key should be an array or function reference
|
|
185
|
+
*/
|
|
186
|
+
userProps: {
|
|
187
|
+
title: chance.profession.bind(chance),
|
|
188
|
+
luckyNumber: weighNumRange(42, 420),
|
|
189
|
+
experiment: designExperiment(),
|
|
190
|
+
spiritAnimal: ["unicorn", "dragon", "phoenix", "sasquatch", "yeti", "kraken", "jackalope", "thunderbird", "mothman", "nessie", "chupacabra", "jersey devil", "bigfoot", "weindgo", "bunyip", "mokele-mbembe", "tatzelwurm", "megalodon"],
|
|
191
|
+
|
|
192
|
+
ip: chance.ip.bind(chance),
|
|
193
|
+
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
/** each generates it's own table */
|
|
197
|
+
scdProps: {
|
|
198
|
+
plan: ["free", "free", "free", "free", "basic", "basic", "basic", "premium", "premium", "enterprise"],
|
|
199
|
+
MRR: weighNumRange(0, 10000, .15),
|
|
200
|
+
NPS: weighNumRange(0, 10, 2, 150),
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
mirrorProps: {
|
|
204
|
+
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
for group analytics keys, we need an array of arrays [[],[],[]]
|
|
209
|
+
each pair represents a group_key and the number of profiles for that key
|
|
210
|
+
*/
|
|
211
|
+
groupKeys: [
|
|
212
|
+
['channel_id', 1234, ["save video", "comment", "watch video", "purchase video", "like video", "dislike video", "subscribe"]],
|
|
213
|
+
|
|
214
|
+
],
|
|
215
|
+
groupProps: {
|
|
216
|
+
channel_id: {
|
|
217
|
+
"name": exhaust(channel_names),
|
|
218
|
+
"viewers": weighNumRange(5, 500, .25),
|
|
219
|
+
"rating": weighNumRange(1, 5),
|
|
220
|
+
"reviews": weighNumRange(0, 35)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
lookupTables: [
|
|
226
|
+
{
|
|
227
|
+
key: "video_id",
|
|
228
|
+
entries: 50000,
|
|
229
|
+
attributes: {
|
|
230
|
+
isFlagged: [true, false, false, false, false],
|
|
231
|
+
copyright: ["all rights reserved", "creative commons", "creative commons", "public domain", "fair use"],
|
|
232
|
+
uploader_id: chance.guid.bind(chance),
|
|
233
|
+
"uploader influence": ["low", "low", "low", "medium", "medium", "high"],
|
|
234
|
+
thumbs: weighNumRange(0, 4000, .25),
|
|
235
|
+
video_name: exhaust(video_names),
|
|
236
|
+
rating: ["G", "PG", "PG-13", "R", "NC-17", "PG-13", "R", "NC-17", "R", "PG", "PG"]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
],
|
|
241
|
+
|
|
242
|
+
hook: function (record, type, meta) {
|
|
243
|
+
return record;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
function makeHashTags() {
|
|
250
|
+
const possibleHashtags = [];
|
|
251
|
+
for (let i = 0; i < 20; i++) {
|
|
252
|
+
possibleHashtags.push('#' + u.makeName(2, ''));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const numHashtags = integer(integer(1, 5), integer(5, 10));
|
|
256
|
+
const hashtags = [];
|
|
257
|
+
for (let i = 0; i < numHashtags; i++) {
|
|
258
|
+
hashtags.push(chance.pickone(possibleHashtags));
|
|
259
|
+
}
|
|
260
|
+
return [hashtags];
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
function makeProducts(maxItems = 10) {
|
|
264
|
+
return function () {
|
|
265
|
+
const categories = ["Device Accessories", "eBooks", "Automotive", "Baby Products", "Beauty", "Books", "Camera & Photo", "Cell Phones & Accessories", "Collectible Coins", "Consumer Electronics", "Entertainment Collectibles", "Fine Art", "Grocery & Gourmet Food", "Health & Personal Care", "Home & Garden", "Independent Design", "Industrial & Scientific", "Accessories", "Major Appliances", "Music", "Musical Instruments", "Office Products", "Outdoors", "Personal Computers", "Pet Supplies", "Software", "Sports", "Sports Collectibles", "Tools & Home Improvement", "Toys & Games", "Video, DVD & Blu-ray", "Video Games", "Watches"];
|
|
266
|
+
const slugs = ['/sale/', '/featured/', '/home/', '/search/', '/wishlist/', '/'];
|
|
267
|
+
const assetExtension = ['.png', '.jpg', '.jpeg', '.heic', '.mp4', '.mov', '.avi'];
|
|
268
|
+
const data = [];
|
|
269
|
+
const numOfItems = integer(1, 12);
|
|
270
|
+
|
|
271
|
+
for (var i = 0; i < numOfItems; i++) {
|
|
272
|
+
const category = chance.pickone(categories);
|
|
273
|
+
const slug = chance.pickone(slugs);
|
|
274
|
+
const asset = chance.pickone(assetExtension);
|
|
275
|
+
const product_id = chance.guid();
|
|
276
|
+
const price = integer(1, 300);
|
|
277
|
+
const quantity = integer(1, 5);
|
|
278
|
+
|
|
279
|
+
const item = {
|
|
280
|
+
product_id: product_id,
|
|
281
|
+
sku: integer(11111, 99999),
|
|
282
|
+
amount: price,
|
|
283
|
+
quantity: quantity,
|
|
284
|
+
value: price * quantity,
|
|
285
|
+
featured: chance.pickone([true, false]),
|
|
286
|
+
category: category,
|
|
287
|
+
urlSlug: slug + category,
|
|
288
|
+
asset: `${category}-${integer(1, 20)}${asset}`
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
data.push(item);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return [data];
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
function designExperiment() {
|
|
300
|
+
return function () {
|
|
301
|
+
const variants = ["A", "B", "C", "Control"];
|
|
302
|
+
const variant = chance.pickone(variants);
|
|
303
|
+
const experiments = ["no password", "social sign in", "new tutorial", "new search"];
|
|
304
|
+
const experiment = chance.pickone(experiments);
|
|
305
|
+
const multi_variates = ["A/B", "A/B/C", "A/B/C/D", "Control"];
|
|
306
|
+
const multi_variate = chance.pickone(multi_variates);
|
|
307
|
+
const impression_id = chance.guid();
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
const chosen = {
|
|
312
|
+
variant,
|
|
313
|
+
experiment,
|
|
314
|
+
multi_variate,
|
|
315
|
+
impression_id
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
return [chosen];
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
module.exports = config;
|