@it-healer/human-design-calculator 1.0.0

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/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Human Design Bodygraph Calculator CLI
2
+
3
+ CLI-инструмент для расчёта бодиграфа Human Design. Принимает дату, время, таймзону и координаты рождения, выдаёт полный JSON со всеми расчётами и опционально генерирует SVG-визуализацию бодиграфа.
4
+
5
+ ## Установка
6
+
7
+ ```bash
8
+ npm install
9
+ ```
10
+
11
+ ## Файлы эфемерид (Swiss Ephemeris)
12
+
13
+ Для высокоточных расчётов необходимо скачать файлы Swiss Ephemeris (.se1) и поместить их в папку `ephemeris/`.
14
+
15
+ ### Где скачать
16
+
17
+ Файлы доступны на официальном FTP-сервере Swiss Ephemeris:
18
+
19
+ **https://www.astro.com/ftp/swisseph/ephe/**
20
+
21
+ Необходимые файлы (суммарно ~10 MB):
22
+
23
+ | Файл | Описание | Размер |
24
+ |-----------------|----------------------------------|----------|
25
+ | `sepl_18.se1` | Планеты (от Солнца до Плутона) | ~3.5 MB |
26
+ | `semo_18.se1` | Луна | ~5.5 MB |
27
+ | `seas_18.se1` | Астероиды (включая True Node) | ~0.5 MB |
28
+
29
+ Файлы `*_18.se1` покрывают период **600 BC — 2400 AD**, что достаточно для любых расчётов.
30
+
31
+ ### Скачивание одной командой
32
+
33
+ ```bash
34
+ cd ephemeris
35
+ curl -O https://www.astro.com/ftp/swisseph/ephe/sepl_18.se1
36
+ curl -O https://www.astro.com/ftp/swisseph/ephe/semo_18.se1
37
+ curl -O https://www.astro.com/ftp/swisseph/ephe/seas_18.se1
38
+ ```
39
+
40
+ > **Без файлов эфемерид** инструмент всё равно работает — Swiss Ephemeris автоматически переключается на встроенный алгоритм Moshier (менее точный, но достаточный для Gate/Line/Color).
41
+
42
+ ## Использование
43
+
44
+ ```bash
45
+ npm run start -- 22.04.1993 08:40 Europe/Kyiv 48.5678 39.3031 ./chart.svg
46
+ ```
47
+
48
+ Или напрямую через `node`:
49
+
50
+ ```bash
51
+ node src/index.js 22.04.1993 08:40 Europe/Kyiv 48.5678 39.3031 ./chart.svg
52
+ ```
53
+
54
+ ### Параметры
55
+
56
+ | # | Описание | Пример |
57
+ |-----|--------------------------------------------|------------------------------------|
58
+ | 1 | Дата рождения (DD.MM.YYYY или YYYY-MM-DD) | `22.04.1993` |
59
+ | 2 | Локальное время рождения (HH:MM) | `08:40` |
60
+ | 3 | Таймзона в формате IANA | `Europe/Kyiv`, `America/New_York` |
61
+ | 4 | Широта места рождения | `48.5678` |
62
+ | 5 | Долгота места рождения | `39.3031` |
63
+ | 6 | Путь для сохранения SVG (опционально) | `./chart.svg` |
64
+
65
+ Если 6-й параметр не указан, выводится только JSON без генерации SVG.
66
+
67
+ ### Примеры
68
+
69
+ Только JSON:
70
+ ```bash
71
+ npm run start -- 25.09.1983 14:30 America/New_York 42.4264 -71.065
72
+ ```
73
+
74
+ JSON + SVG-визуализация:
75
+ ```bash
76
+ npm run start -- 25.09.1983 14:30 America/New_York 42.4264 -71.065 ./bodygraph.svg
77
+ ```
78
+
79
+ ## SVG-визуализация
80
+
81
+ При указании пути для SVG генерируется визуализация бодиграфа:
82
+
83
+ - 9 центров с цветовой раскраской (определённые/неопределённые)
84
+ - 36 каналов (активные выделены)
85
+ - 64 гейта с номерами в кружках
86
+ - Цветовая кодировка: чёрный — Personality, красный — Design, синий — оба
87
+ - Контур человеческой фигуры на фоне
88
+
89
+ ## Выходной JSON
90
+
91
+ Инструмент выводит JSON со следующими полями:
92
+
93
+ ```
94
+ input — входные параметры
95
+ birthDateUTC — дата рождения в UTC
96
+ designDateUTC — дата дизайна (88° ретроград Солнца) в UTC
97
+ activations — активации для Personality и Design
98
+ personality/design — для каждого из 13 тел: gate, line, color, tone, base
99
+ Sun, Earth, Moon, Mercury, Venus, Mars, Jupiter,
100
+ Saturn, Uranus, Neptune, Pluto, NorthNode, SouthNode
101
+ type — Generator, Manifesting Generator, Projector, Manifestor, Reflector
102
+ strategy — To Respond, To Inform, To Wait for the Invitation, To Wait a Lunar Cycle
103
+ signature — Satisfaction, Peace, Success, Surprise
104
+ notSelfTheme — Frustration, Anger, Bitterness, Disappointment
105
+ authority — Solar Plexus, Sacral, Spleen, Ego, Self Projected, Outer Authority, Lunar
106
+ definition — None, Single, Split, Wide Split, Triple Split, Quad Split
107
+ profile — "Line/Line" (например "1/3")
108
+ incarnationCross — полное название инкарнационного креста
109
+ variable — "P[L/R][L/R] D[L/R][L/R]"
110
+ channels — массив активных каналов ("9-52", "29-46", ...)
111
+ activatedGates — массив всех уникальных активированных гейтов
112
+ definedCenters — массив определённых центров
113
+ undefinedCenters — массив неопределённых центров
114
+ centerDefinition — объект с булевыми флагами для каждого центра
115
+ circuitries — массив контуров (Individual, Tribal, Collective Logic, Collective Abstract)
116
+ determination — Appetite, Taste, Thirst, Touch, Sound, Light
117
+ environment — Caves, Markets, Kitchens, Mountains, Valleys, Shores
118
+ view — Survival, Possibility, Power, Wanting, Probability, Personal
119
+ motivation — Fear, Hope, Desire, Need, Guilt, Innocence
120
+ cognition — Smell, Taste, Outer Vision, Inner Vision, Feeling, Touch
121
+ sense — Security, Uncertainty, Action, Meditation, Judgment, Acceptance
122
+ ```
123
+
124
+ ## Технические детали
125
+
126
+ - **Node.js** — чистый JavaScript, без TypeScript
127
+ - **Swiss Ephemeris** (`swisseph` npm) — астрономические вычисления планетарных позиций
128
+ - **Luxon** — конвертация локального времени в UTC с учётом таймзоны
129
+ - **Бинарный поиск** для нахождения даты Дизайна (~50 итераций vs 800K+ в линейном подходе)
130
+ - 13 небесных тел: Sun, Earth, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, North Node, South Node
131
+ - Полная иерархия активации: Gate → Line → Color → Tone → Base
File without changes
Binary file
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@it-healer/human-design-calculator",
3
+ "version": "1.0.0",
4
+ "description": "Human Design bodygraph calculator CLI — calculates type, authority, profile, channels, gates, and generates SVG visualization",
5
+ "author": {
6
+ "name": "PAVLO POPOV",
7
+ "url": "https://it-healer.com"
8
+ },
9
+ "homepage": "https://it-healer.com",
10
+ "main": "src/index.js",
11
+ "bin": {
12
+ "hd-calculator": "src/index.js"
13
+ },
14
+ "files": [
15
+ "src/",
16
+ "ephemeris/"
17
+ ],
18
+ "scripts": {
19
+ "start": "node src/index.js"
20
+ },
21
+ "keywords": [
22
+ "human-design",
23
+ "bodygraph",
24
+ "astrology",
25
+ "swiss-ephemeris",
26
+ "cli"
27
+ ],
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "luxon": "^3.4.0",
31
+ "swisseph": "^0.5.17"
32
+ }
33
+ }
@@ -0,0 +1,43 @@
1
+ const { GATE_ORDER } = require('./data/gates');
2
+
3
+ /**
4
+ * Convert ecliptic longitude (decimal degrees 0-360) to HD activation.
5
+ *
6
+ * HD gates start at Gate 41 at 02°00'00" Aquarius.
7
+ * Offset from 00° Aries = 58 degrees exactly.
8
+ *
9
+ * The zodiac wheel (360°) subdivides into:
10
+ * 64 gates × 6 lines × 6 colors × 6 tones × 5 bases = 69,120 total subdivisions
11
+ */
12
+ function getActivation(longitude) {
13
+ let adjusted = longitude + 58;
14
+ if (adjusted >= 360) adjusted -= 360;
15
+
16
+ const pct = adjusted / 360;
17
+
18
+ const gateIndex = Math.floor(pct * 64);
19
+ const gate = GATE_ORDER[gateIndex];
20
+
21
+ const exactLine = 384 * pct; // 64 * 6
22
+ const line = Math.floor((exactLine % 6) + 1);
23
+
24
+ const exactColor = 2304 * pct; // 64 * 6 * 6
25
+ const color = Math.floor((exactColor % 6) + 1);
26
+
27
+ const exactTone = 13824 * pct; // 64 * 6 * 6 * 6
28
+ const tone = Math.floor((exactTone % 6) + 1);
29
+
30
+ const exactBase = 69120 * pct; // 64 * 6 * 6 * 6 * 5
31
+ const base = Math.floor((exactBase % 5) + 1);
32
+
33
+ return { gate, line, color, tone, base };
34
+ }
35
+
36
+ /** Get activation for the opposite point (Earth = Sun+180°, SouthNode = NorthNode+180°) */
37
+ function getOppositeActivation(longitude) {
38
+ let opposite = longitude + 180;
39
+ if (opposite >= 360) opposite -= 360;
40
+ return getActivation(opposite);
41
+ }
42
+
43
+ module.exports = { getActivation, getOppositeActivation };
@@ -0,0 +1,138 @@
1
+ const { DateTime } = require('luxon');
2
+ const {
3
+ initEphemeris, dateToJulianDay, julianDayToDate,
4
+ getAllPositions, PLANET_NAMES,
5
+ } = require('./ephemeris');
6
+ const { getActivation, getOppositeActivation } = require('./activation');
7
+ const { findDesignDate } = require('./design-date');
8
+ const {
9
+ getAllActivatedGates, getChannels, getDefinedCenters,
10
+ getType, getTypeProperties, getAuthority, getDefinition,
11
+ getProfile, getVariable, getCircuitries,
12
+ } = require('./type');
13
+ const {
14
+ getIncarnationCross, getDetermination, getEnvironment,
15
+ getView, getMotivation, getCognition, getSense,
16
+ } = require('./properties');
17
+ const { CENTER_NAMES } = require('./data/centers');
18
+
19
+ function julianDayToISO(jd) {
20
+ const d = julianDayToDate(jd);
21
+ const totalHours = d.hour;
22
+ const hours = Math.floor(totalHours);
23
+ const totalMinutes = (totalHours - hours) * 60;
24
+ const minutes = Math.floor(totalMinutes);
25
+ const seconds = Math.floor((totalMinutes - minutes) * 60);
26
+ return DateTime.utc(d.year, d.month, d.day, hours, minutes, seconds).toISO();
27
+ }
28
+
29
+ function calculateBodygraph(dateStr, timeStr, tz, lat, lon, ephemerisPath) {
30
+ initEphemeris(ephemerisPath);
31
+
32
+ // 1. Convert local time → UTC
33
+ const localDt = DateTime.fromISO(`${dateStr}T${timeStr}`, { zone: tz });
34
+ if (!localDt.isValid) {
35
+ throw new Error(`Invalid date/time/timezone: ${dateStr} ${timeStr} ${tz}`);
36
+ }
37
+ const utcDt = localDt.toUTC();
38
+
39
+ // 2. Birth Julian Day
40
+ const hourDecimal = utcDt.hour + utcDt.minute / 60 + utcDt.second / 3600;
41
+ const birthJD = dateToJulianDay(utcDt.year, utcDt.month, utcDt.day, hourDecimal);
42
+
43
+ // 3. Personality planetary positions and activations
44
+ const personalityPositions = getAllPositions(birthJD);
45
+ const personalityActs = {};
46
+ for (const planet of PLANET_NAMES) {
47
+ personalityActs[planet] = getActivation(personalityPositions[planet].longitude);
48
+ }
49
+ personalityActs['Earth'] = getOppositeActivation(personalityPositions.Sun.longitude);
50
+ personalityActs['SouthNode'] = getOppositeActivation(personalityPositions.NorthNode.longitude);
51
+
52
+ // 4. Find Design Date (88° retrograde sun)
53
+ const designJD = findDesignDate(birthJD);
54
+
55
+ // 5. Design planetary positions and activations
56
+ const designPositions = getAllPositions(designJD);
57
+ const designActs = {};
58
+ for (const planet of PLANET_NAMES) {
59
+ designActs[planet] = getActivation(designPositions[planet].longitude);
60
+ }
61
+ designActs['Earth'] = getOppositeActivation(designPositions.Sun.longitude);
62
+ designActs['SouthNode'] = getOppositeActivation(designPositions.NorthNode.longitude);
63
+
64
+ // 6. Derive gates, channels, centers
65
+ const acts = { personality: personalityActs, design: designActs };
66
+ const activatedGates = getAllActivatedGates(acts);
67
+ const channels = getChannels(activatedGates);
68
+ const definedCenters = getDefinedCenters(channels);
69
+
70
+ // 7. Derive type, authority, definition
71
+ const type = getType(channels, definedCenters, activatedGates);
72
+ const { strategy, signature, notSelfTheme } = getTypeProperties(type);
73
+ const authority = getAuthority(definedCenters, activatedGates);
74
+ const definition = getDefinition(channels, definedCenters, activatedGates);
75
+ const profile = getProfile(personalityActs.Sun.line, designActs.Sun.line);
76
+ const variable = getVariable(
77
+ personalityActs.Sun.tone, personalityActs.NorthNode.tone,
78
+ designActs.Sun.tone, designActs.NorthNode.tone,
79
+ );
80
+ const circuitries = getCircuitries(channels);
81
+
82
+ // 8. Derive properties
83
+ const incarnationCross = getIncarnationCross(personalityActs.Sun, designActs.Sun);
84
+ const determination = getDetermination(designActs.Sun);
85
+ const environment = getEnvironment(designActs.NorthNode);
86
+ const view = getView(personalityActs.NorthNode);
87
+ const motivation = getMotivation(personalityActs.Sun);
88
+ const cognition = getCognition(designActs.Sun);
89
+ const sense = getSense(personalityActs.Sun);
90
+
91
+ // 9. Center definition flags
92
+ const centerDef = {};
93
+ const defined = [];
94
+ const undefined_ = [];
95
+ for (const c of CENTER_NAMES) {
96
+ const isDef = definedCenters.has(c);
97
+ centerDef[c] = isDef;
98
+ if (isDef) defined.push(c);
99
+ else undefined_.push(c);
100
+ }
101
+
102
+ // 10. Assemble result
103
+ return {
104
+ input: {
105
+ date: dateStr,
106
+ time: timeStr,
107
+ timezone: tz,
108
+ latitude: lat,
109
+ longitude: lon,
110
+ },
111
+ birthDateUTC: utcDt.toISO(),
112
+ designDateUTC: julianDayToISO(designJD),
113
+ activations: acts,
114
+ type,
115
+ strategy,
116
+ signature,
117
+ notSelfTheme,
118
+ authority,
119
+ definition,
120
+ profile,
121
+ incarnationCross,
122
+ variable,
123
+ channels,
124
+ activatedGates: Array.from(activatedGates).sort((a, b) => a - b),
125
+ definedCenters: defined,
126
+ undefinedCenters: undefined_,
127
+ centerDefinition: centerDef,
128
+ circuitries,
129
+ determination,
130
+ environment,
131
+ view,
132
+ motivation,
133
+ cognition,
134
+ sense,
135
+ };
136
+ }
137
+
138
+ module.exports = { calculateBodygraph };
@@ -0,0 +1,94 @@
1
+ const CENTER_NAMES = [
2
+ 'Head', 'Ajna', 'Throat', 'G', 'Ego', 'Sacral',
3
+ 'Solar Plexus', 'Spleen', 'Root'
4
+ ];
5
+
6
+ /** Which center each gate belongs to */
7
+ const CENTER_BY_GATE = {
8
+ 1: 'G', 2: 'G', 3: 'Sacral', 4: 'Ajna', 5: 'Sacral',
9
+ 6: 'Solar Plexus', 7: 'G', 8: 'Throat', 9: 'Sacral',
10
+ 10: 'G', 11: 'Ajna', 12: 'Throat', 13: 'G', 14: 'Sacral',
11
+ 15: 'G', 16: 'Throat', 17: 'Ajna', 18: 'Spleen', 19: 'Root',
12
+ 20: 'Throat', 21: 'Ego', 22: 'Solar Plexus', 23: 'Throat',
13
+ 24: 'Ajna', 25: 'G', 26: 'Ego', 27: 'Sacral', 28: 'Spleen',
14
+ 29: 'Sacral', 30: 'Solar Plexus', 31: 'Throat', 32: 'Spleen',
15
+ 33: 'Throat', 34: 'Sacral', 35: 'Throat', 36: 'Solar Plexus',
16
+ 37: 'Solar Plexus', 38: 'Root', 39: 'Root', 40: 'Ego',
17
+ 41: 'Root', 42: 'Sacral', 43: 'Ajna', 44: 'Spleen',
18
+ 45: 'Throat', 46: 'G', 47: 'Ajna', 48: 'Spleen',
19
+ 49: 'Solar Plexus', 50: 'Spleen', 51: 'Ego', 52: 'Root',
20
+ 53: 'Root', 54: 'Root', 55: 'Solar Plexus', 56: 'Throat',
21
+ 57: 'Spleen', 58: 'Root', 59: 'Sacral', 60: 'Root',
22
+ 61: 'Head', 62: 'Throat', 63: 'Head', 64: 'Head',
23
+ };
24
+
25
+ /** Adjacency graph between centers */
26
+ const ADJACENT_CENTERS = {
27
+ 'Head': ['Ajna'],
28
+ 'Ajna': ['Head', 'Throat'],
29
+ 'Throat': ['Ajna', 'G', 'Ego', 'Sacral', 'Spleen', 'Solar Plexus'],
30
+ 'G': ['Throat', 'Ego', 'Sacral', 'Spleen'],
31
+ 'Ego': ['Throat', 'G', 'Spleen', 'Solar Plexus'],
32
+ 'Sacral': ['Throat', 'G', 'Spleen', 'Solar Plexus', 'Root'],
33
+ 'Solar Plexus': ['Throat', 'Ego', 'Sacral', 'Root'],
34
+ 'Spleen': ['Throat', 'G', 'Ego', 'Sacral', 'Root'],
35
+ 'Root': ['Sacral', 'Spleen', 'Solar Plexus'],
36
+ };
37
+
38
+ /** Bridging gates between pairs of centers (used for Wide Split detection) */
39
+ const BRIDGING_GATES = {
40
+ 'Head': {
41
+ 'Ajna': [64, 61, 63, 47, 24, 4],
42
+ },
43
+ 'Ajna': {
44
+ 'Head': [64, 61, 63, 47, 24, 4],
45
+ 'Throat': [17, 43, 11, 62, 23, 56],
46
+ },
47
+ 'Throat': {
48
+ 'Ajna': [17, 43, 11, 62, 23, 56],
49
+ 'Solar Plexus': [35, 36, 12, 22],
50
+ 'Ego': [45, 21],
51
+ 'G': [31, 8, 33, 7, 1, 13, 10],
52
+ 'Sacral': [34, 20],
53
+ 'Spleen': [57, 20, 16, 48],
54
+ },
55
+ 'Solar Plexus': {
56
+ 'Throat': [35, 36, 12, 22],
57
+ 'Ego': [37, 40],
58
+ 'Sacral': [6, 59],
59
+ 'Root': [19, 49, 39, 55, 41, 30],
60
+ },
61
+ 'Ego': {
62
+ 'Throat': [45, 21],
63
+ 'Solar Plexus': [37, 40],
64
+ 'G': [25, 51],
65
+ 'Spleen': [26, 44],
66
+ },
67
+ 'G': {
68
+ 'Throat': [31, 8, 33, 7, 1, 13, 10],
69
+ 'Ego': [25, 51],
70
+ 'Sacral': [15, 2, 46, 10, 34],
71
+ 'Spleen': [57, 10],
72
+ },
73
+ 'Spleen': {
74
+ 'Throat': [57, 20, 16, 48],
75
+ 'G': [57, 10],
76
+ 'Ego': [26, 44],
77
+ 'Sacral': [50, 27, 34, 57],
78
+ 'Root': [32, 54, 28, 38, 18, 58],
79
+ },
80
+ 'Sacral': {
81
+ 'Throat': [34, 20],
82
+ 'G': [15, 2, 46, 10, 34],
83
+ 'Solar Plexus': [6, 59],
84
+ 'Spleen': [50, 27, 34, 57],
85
+ 'Root': [42, 3, 9, 53, 60, 52],
86
+ },
87
+ 'Root': {
88
+ 'Spleen': [32, 54, 28, 38, 18, 58],
89
+ 'Sacral': [42, 3, 9, 53, 60, 52],
90
+ 'Solar Plexus': [19, 49, 39, 55, 41, 30],
91
+ },
92
+ };
93
+
94
+ module.exports = { CENTER_NAMES, CENTER_BY_GATE, ADJACENT_CENTERS, BRIDGING_GATES };
@@ -0,0 +1,81 @@
1
+ /** Map channel string "low-high" to the two centers it connects */
2
+ const DEFINED_CENTERS_BY_CHANNEL = {
3
+ '1-8': ['G', 'Throat'],
4
+ '2-14': ['G', 'Sacral'],
5
+ '3-60': ['Sacral', 'Root'],
6
+ '4-63': ['Head', 'Ajna'],
7
+ '5-15': ['G', 'Sacral'],
8
+ '6-59': ['Solar Plexus', 'Sacral'],
9
+ '7-31': ['G', 'Throat'],
10
+ '9-52': ['Sacral', 'Root'],
11
+ '10-20': ['G', 'Throat'],
12
+ '10-34': ['G', 'Sacral'],
13
+ '10-57': ['G', 'Spleen'],
14
+ '11-56': ['Ajna', 'Throat'],
15
+ '12-22': ['Throat', 'Solar Plexus'],
16
+ '13-33': ['G', 'Throat'],
17
+ '16-48': ['Throat', 'Spleen'],
18
+ '17-62': ['Ajna', 'Throat'],
19
+ '18-58': ['Spleen', 'Root'],
20
+ '19-49': ['Solar Plexus', 'Root'],
21
+ '20-34': ['Throat', 'Sacral'],
22
+ '20-57': ['Throat', 'Spleen'],
23
+ '21-45': ['Ego', 'Throat'],
24
+ '23-43': ['Ajna', 'Throat'],
25
+ '24-61': ['Head', 'Ajna'],
26
+ '25-51': ['G', 'Ego'],
27
+ '26-44': ['Spleen', 'Ego'],
28
+ '27-50': ['Spleen', 'Sacral'],
29
+ '28-38': ['Spleen', 'Root'],
30
+ '29-46': ['G', 'Sacral'],
31
+ '30-41': ['Solar Plexus', 'Root'],
32
+ '32-54': ['Spleen', 'Root'],
33
+ '34-57': ['Sacral', 'Spleen'],
34
+ '35-36': ['Throat', 'Solar Plexus'],
35
+ '37-40': ['Ego', 'Solar Plexus'],
36
+ '39-55': ['Solar Plexus', 'Root'],
37
+ '42-53': ['Sacral', 'Root'],
38
+ '47-64': ['Head', 'Ajna'],
39
+ };
40
+
41
+ /** Map channel string to its circuitry */
42
+ const CIRCUITRY_BY_CHANNEL = {
43
+ '1-8': 'Individual',
44
+ '2-14': 'Individual',
45
+ '3-60': 'Individual',
46
+ '4-63': 'Collective Logic',
47
+ '5-15': 'Collective Logic',
48
+ '6-59': 'Tribal',
49
+ '7-31': 'Collective Logic',
50
+ '9-52': 'Collective Logic',
51
+ '10-20': 'Individual',
52
+ '10-34': 'Individual',
53
+ '10-57': 'Individual',
54
+ '11-56': 'Collective Abstract',
55
+ '12-22': 'Individual',
56
+ '13-33': 'Collective Abstract',
57
+ '16-48': 'Collective Logic',
58
+ '17-62': 'Collective Logic',
59
+ '18-58': 'Collective Logic',
60
+ '19-49': 'Tribal',
61
+ '20-34': 'Individual',
62
+ '20-57': 'Individual',
63
+ '21-45': 'Tribal',
64
+ '23-43': 'Individual',
65
+ '24-61': 'Individual',
66
+ '25-51': 'Individual',
67
+ '26-44': 'Tribal',
68
+ '27-50': 'Tribal',
69
+ '28-38': 'Individual',
70
+ '29-46': 'Collective Abstract',
71
+ '30-41': 'Collective Abstract',
72
+ '32-54': 'Tribal',
73
+ '34-57': 'Individual',
74
+ '35-36': 'Collective Abstract',
75
+ '37-40': 'Tribal',
76
+ '39-55': 'Individual',
77
+ '42-53': 'Collective Abstract',
78
+ '47-64': 'Collective Abstract',
79
+ };
80
+
81
+ module.exports = { DEFINED_CENTERS_BY_CHANNEL, CIRCUITRY_BY_CHANNEL };