@bablr/agast-vm-helpers 0.1.1 → 0.1.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/lib/builders.js CHANGED
@@ -30,8 +30,8 @@ export const buildGap = () => {
30
30
  return t.node(l.CSTML, 'Gap', [t.ref`value`], { value: t.s_node(l.CSTML, 'Punctuator', '<//>') });
31
31
  };
32
32
 
33
- const buildFlags = (flags) => {
34
- const { token = null, escape = null, trivia = null, expression = null } = flags;
33
+ export const buildFlags = (flags) => {
34
+ const { intrinsic = null, token = null, escape = null, trivia = null, expression = null } = flags;
35
35
 
36
36
  if ((trivia && escape) || (expression && (trivia || escape))) {
37
37
  throw new Error('invalid flags');
@@ -39,16 +39,18 @@ const buildFlags = (flags) => {
39
39
 
40
40
  return {
41
41
  children: [
42
- ...when(trivia, [t.ref`triviaFlag`]),
43
- ...when(token, [t.ref`tokenFlag`]),
44
- ...when(escape, [t.ref`escapeFlag`]),
45
- ...when(expression, [t.ref`expressionFlag`]),
42
+ ...when(trivia, [t.ref`triviaToken`]),
43
+ ...when(intrinsic, [t.ref`intrinsicToken`]),
44
+ ...when(token, [t.ref`tokenToken`]),
45
+ ...when(escape, [t.ref`escapeToken`]),
46
+ ...when(expression, [t.ref`expressionToken`]),
46
47
  ],
47
48
  properties: {
48
- triviaFlag: trivia && t.s_node(l.CSTML, 'Punctuator', '#'),
49
- tokenFlag: token && t.s_node(l.CSTML, 'Punctuator', '*'),
50
- escapeFlag: escape && t.s_node(l.CSTML, 'Punctuator', '@'),
51
- expressionFlag: expression && t.s_node(l.CSTML, 'Punctuator', '+'),
49
+ triviaToken: trivia && t.s_node(l.CSTML, 'Punctuator', '#'),
50
+ intrinsicToken: intrinsic && t.s_node(l.CSTML, 'Punctuator', '~'),
51
+ tokenToken: token && t.s_node(l.CSTML, 'Punctuator', '*'),
52
+ escapeToken: escape && t.s_node(l.CSTML, 'Punctuator', '@'),
53
+ expressionToken: expression && t.s_node(l.CSTML, 'Punctuator', '+'),
52
54
  },
53
55
  };
54
56
  };
@@ -64,134 +66,102 @@ export const buildFullyQualifiedSpamMatcher = (
64
66
  intrinsicValue,
65
67
  attributes = {},
66
68
  ) => {
67
- const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
68
- buildAttribute(key, value),
69
- );
69
+ const attributes_ = buildAttributes(attributes);
70
70
 
71
71
  const lArr = language ? [...language] : [];
72
72
 
73
73
  let language_ = lArr.length === 0 ? null : lArr;
74
74
 
75
- const flags_ = buildFlags(flags);
76
75
  return t.node(
77
76
  l.Spamex,
78
77
  'NodeMatcher',
79
78
  [
80
- t.ref`open`,
81
- ...flags_.children,
79
+ t.ref`openToken`,
80
+ t.ref`flags`,
82
81
  ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
83
82
  t.ref`type`,
84
83
  ...when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
85
84
  ...when(attributes_.length, [t.embedded(buildSpace())]),
86
85
  ...interpolateArrayChildren(attributes, t.ref`attributes[]`, t.embedded(buildSpace())),
87
- t.ref`close`,
86
+ t.ref`closeToken`,
88
87
  ],
89
88
  {
90
- open: t.s_node(l.CSTML, 'Punctuator', '<'),
91
- ...flags_.properties,
89
+ openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
90
+ flags: buildFlags(flags),
92
91
  language: buildLanguage(language_),
93
92
  languageSeparator: language_ && type && t.s_node(l.CSTML, 'Punctuator', ':'),
94
93
  type: buildIdentifier(type),
95
94
  intrinsicValue: intrinsicValue && buildString(intrinsicValue),
96
95
  attributes: attributes_,
97
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
96
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
98
97
  },
99
98
  );
100
99
  };
101
100
 
102
101
  export const buildNodeOpenTag = (flags, language, type, intrinsicValue = null, attributes = {}) => {
103
- const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
104
- buildAttribute(key, value),
105
- );
102
+ const attributes_ = buildAttributes(attributes);
106
103
 
107
104
  let language_ = !language || language.length === 0 ? null : language;
108
105
 
109
- const flags_ = buildFlags(flags);
110
-
111
106
  return t.node(
112
107
  l.CSTML,
113
108
  'OpenNodeTag',
114
109
  [
115
- t.ref`open`,
116
- ...flags_.children,
110
+ t.ref`openToken`,
111
+ t.ref`flags`,
117
112
  ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
118
113
  t.ref`type`,
119
114
  ...when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
120
115
  ...when(attributes_.length, [t.embedded(buildSpace())]),
121
116
  ...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
122
117
  when(intrinsicValue, [t.embedded(buildSpace), t.ref`selfClosingToken`]),
123
- t.ref`close`,
118
+ t.ref`closeToken`,
124
119
  ],
125
120
  {
126
- open: t.s_node(l.CSTML, 'Punctuator', '<'),
127
- ...flags_.properties,
121
+ openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
122
+ flags: buildFlags(flags),
128
123
  language: buildLanguage(language_),
129
124
  languageSeparator: language_ && type && t.s_node(l.CSTML, 'Punctuator', ':'),
130
125
  type: buildIdentifier(type),
131
126
  intrinsicValue: intrinsicValue && buildString(intrinsicValue),
132
127
  attributes: attributes_,
133
128
  selfClosingToken: intrinsicValue && t.s_node(l.CSTML, 'Punctuator', '/'),
134
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
129
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
135
130
  },
136
131
  );
137
132
  };
138
133
 
139
134
  export const buildDoctypeTag = (attributes) => {
140
- const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
141
- buildAttribute(key, value),
142
- );
135
+ const attributes_ = buildAttributes(attributes);
143
136
 
144
137
  return t.node(
145
138
  l.CSTML,
146
139
  'DoctypeTag',
147
140
  [
148
- t.ref`open`,
141
+ t.ref`openToken`,
149
142
  t.ref`version`,
150
143
  t.ref`versionSeparator`,
151
144
  t.ref`doctype`,
152
145
  ...when(attributes_.length, [t.embedded(buildSpace())]),
153
146
  ...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
154
- t.ref`close`,
147
+ t.ref`closeToken`,
155
148
  ],
156
149
  {
157
- open: t.s_node(l.CSTML, 'Punctuator', '<!'),
150
+ openToken: t.s_node(l.CSTML, 'Punctuator', '<!'),
158
151
  version: t.s_node(l.CSTML, 'PositiveInteger', '0'),
159
152
  versionSeparator: t.s_node(l.CSTML, 'Punctuator', ':'),
160
153
  doctype: t.s_node(l.CSTML, 'Keyword', 'cstml'),
161
154
  attributes: attributes_,
162
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
155
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
163
156
  },
164
157
  );
165
158
  };
166
159
 
167
- export const buildFragmentFlags = (flags = {}) => {
168
- const { escape = null, trivia = null } = flags;
169
- if (!(escape || trivia)) {
170
- return null;
171
- }
172
-
173
- return t.node(
174
- l.CSTML,
175
- 'NodeFlags',
176
- [...when(trivia, [t.ref`trivia`]), ...when(escape, [t.ref`escape`])],
177
- {
178
- trivia: trivia && t.s_node(l.CSTML, 'Punctuator', '#'),
179
- escape: escape && t.s_node(l.CSTML, 'Punctuator', '@'),
180
- },
181
- );
182
- };
183
-
184
- export const buildFragmentOpenTag = (flags) => {
185
- return t.node(
186
- l.CSTML,
187
- 'OpenFragmentTag',
188
- [t.ref`open`, ...when(flags, [t.ref`flags`]), t.ref`close`],
189
- {
190
- open: t.s_node(l.CSTML, 'Punctuator', '<'),
191
- flags: buildFragmentFlags(flags),
192
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
193
- },
194
- );
160
+ export const buildFragmentOpenTag = () => {
161
+ return t.node(l.CSTML, 'OpenFragmentTag', [t.ref`openToken`, t.ref`closeToken`], {
162
+ openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
163
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
164
+ });
195
165
  };
196
166
 
197
167
  export const buildIdentifierPath = (path) => {
@@ -223,26 +193,26 @@ export const buildNodeCloseTag = (type, language) => {
223
193
  l.CSTML,
224
194
  'CloseNodeTag',
225
195
  [
226
- t.ref`open`,
196
+ t.ref`openToken`,
227
197
  ...when(language, [t.ref`language`]),
228
198
  ...when(type && language, [t.ref`languageSeparator`]),
229
199
  ...when(type, [t.ref`type`]),
230
- t.ref`close`,
200
+ t.ref`closeToken`,
231
201
  ],
232
202
  {
233
- open: t.s_node(l.CSTML, 'Punctuator', '</'),
203
+ openToken: t.s_node(l.CSTML, 'Punctuator', '</'),
234
204
  language: buildLanguage(language),
235
205
  languageSeparator: language && type ? t.s_node(l.CSTML, 'Punctuator', ':') : null,
236
206
  type: type && buildIdentifier(type),
237
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
207
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
238
208
  },
239
209
  );
240
210
  };
241
211
 
242
212
  export const buildFragmentCloseTag = () => {
243
- return t.node(l.CSTML, 'CloseFragmentTag', [t.ref`open`, t.ref`close`], {
244
- open: t.s_node(l.CSTML, 'Punctuator', '</'),
245
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
213
+ return t.node(l.CSTML, 'CloseFragmentTag', [t.ref`openToken`, t.ref`closeToken`], {
214
+ openToken: t.s_node(l.CSTML, 'Punctuator', '</'),
215
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
246
216
  });
247
217
  };
248
218
 
@@ -342,15 +312,15 @@ export const buildString = (value) => {
342
312
  let lit = '';
343
313
 
344
314
  if (pieces.length === 1 && pieces[0] === "'") {
345
- return t.node(l.CSTML, 'String', [t.ref`open`, t.ref`content`, t.ref`close`], {
346
- open: t.s_node(l.CSTML, 'Punctuator', '"'),
315
+ return t.node(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
316
+ openToken: t.s_node(l.CSTML, 'Punctuator', '"'),
347
317
  content: interpolateString(
348
318
  freeze({
349
319
  type: 'Literal',
350
320
  value,
351
321
  }),
352
322
  ),
353
- close: t.s_node(l.CSTML, 'Punctuator', '"'),
323
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '"'),
354
324
  });
355
325
  }
356
326
 
@@ -418,7 +388,7 @@ export const buildString = (value) => {
418
388
  lit = '';
419
389
 
420
390
  if (piece == null) {
421
- throw new Error('not impelemented');
391
+ throw new Error('not implemented');
422
392
  } else if (isString(piece.type)) {
423
393
  terminals.push(piece);
424
394
  } else {
@@ -430,22 +400,22 @@ export const buildString = (value) => {
430
400
  if (lit) terminals.push(buildLiteralTerminal(lit));
431
401
  lit = '';
432
402
 
433
- return t.node(l.CSTML, 'String', [t.ref`open`, t.ref`content`, t.ref`close`], {
434
- open: t.s_node(l.CSTML, 'Punctuator', "'"),
403
+ return t.node(l.CSTML, 'String', [t.ref`openToken`, t.ref`content`, t.ref`closeToken`], {
404
+ openToken: t.s_node(l.CSTML, 'Punctuator', "'"),
435
405
  content: interpolateString(terminals),
436
- close: t.s_node(l.CSTML, 'Punctuator', "'"),
406
+ closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
437
407
  });
438
408
  };
439
409
 
440
410
  export const buildBoolean = (value) => {
441
- return t.node(l.Instruction, 'Boolean', [t.ref`value`], {
442
- value: t.s_node(l.Instruction, 'Keyword', value ? 'true' : 'false'),
411
+ return t.node(l.Instruction, 'Boolean', [t.ref`sigilToken`], {
412
+ sigilToken: t.s_node(l.Instruction, 'Keyword', value ? 'true' : 'false'),
443
413
  });
444
414
  };
445
415
 
446
416
  export const buildNull = () => {
447
- return t.node(l.Instruction, 'Null', [t.ref`value`], {
448
- value: t.s_node(l.Instruction, 'Keyword', 'null'),
417
+ return t.node(l.Instruction, 'Null', [t.ref`sigilToken`], {
418
+ sigilToken: t.s_node(l.Instruction, 'Keyword', 'null'),
449
419
  });
450
420
  };
451
421
 
@@ -454,7 +424,7 @@ export const buildArray = (elements) => {
454
424
  l.Instruction,
455
425
  'Array',
456
426
  [
457
- t.ref`open`,
427
+ t.ref`openToken`,
458
428
  ...interpolateArrayChildren(
459
429
  elements,
460
430
  t.ref`elements[]`,
@@ -462,12 +432,12 @@ export const buildArray = (elements) => {
462
432
  t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
463
433
  ),
464
434
  ),
465
- t.ref`close`,
435
+ t.ref`closeToken`,
466
436
  ],
467
437
  {
468
- open: t.s_node(l.Instruction, 'Punctuator', '['),
438
+ openToken: t.s_node(l.Instruction, 'Punctuator', '['),
469
439
  elements: [...interpolateArray(elements)],
470
- close: t.s_node(l.Instruction, 'Punctuator', ']'),
440
+ closeToken: t.s_node(l.Instruction, 'Punctuator', ']'),
471
441
  },
472
442
  );
473
443
  };
@@ -477,7 +447,7 @@ export const buildTuple = (values) => {
477
447
  l.Instruction,
478
448
  'Tuple',
479
449
  [
480
- t.ref`open`,
450
+ t.ref`openToken`,
481
451
  ...interpolateArrayChildren(
482
452
  values,
483
453
  t.ref`values[]`,
@@ -485,12 +455,12 @@ export const buildTuple = (values) => {
485
455
  t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
486
456
  ),
487
457
  ),
488
- t.ref`close`,
458
+ t.ref`closeToken`,
489
459
  ],
490
460
  {
491
- open: t.s_node(l.Instruction, 'Punctuator', '('),
461
+ openToken: t.s_node(l.Instruction, 'Punctuator', '('),
492
462
  values: [...interpolateArray(values)],
493
- close: t.s_node(l.Instruction, 'Punctuator', ')'),
463
+ closeToken: t.s_node(l.Instruction, 'Punctuator', ')'),
494
464
  },
495
465
  );
496
466
  };
@@ -500,7 +470,7 @@ export const buildObject = (properties) => {
500
470
  l.Instruction,
501
471
  'Object',
502
472
  [
503
- t.ref`open`,
473
+ t.ref`openToken`,
504
474
  ...interpolateArrayChildren(
505
475
  Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
506
476
  t.ref`properties[]`,
@@ -508,16 +478,16 @@ export const buildObject = (properties) => {
508
478
  t.t_node(l.Comment, null, [t.embedded(t.t_node('Space', 'Space', [t.lit(' ')]))]),
509
479
  ),
510
480
  ),
511
- t.ref`close`,
481
+ t.ref`closeToken`,
512
482
  ],
513
483
  {
514
- open: t.s_node(l.Instruction, 'Punctuator', '{'),
484
+ openToken: t.s_node(l.Instruction, 'Punctuator', '{'),
515
485
  properties: [
516
486
  ...interpolateArray(
517
487
  Object.entries(properties).map(([key, value]) => buildProperty(key, value)),
518
488
  ),
519
489
  ],
520
- close: t.s_node(l.Instruction, 'Punctuator', '}'),
490
+ closeToken: t.s_node(l.Instruction, 'Punctuator', '}'),
521
491
  },
522
492
  {},
523
493
  );
@@ -532,8 +502,8 @@ export const buildMappingAttribute = (key, value) => {
532
502
  };
533
503
 
534
504
  export const buildBooleanAttribute = (key, value) => {
535
- return t.node(l.CSTML, 'BooleanAttribute', [...when(!value, [t.ref`negateSigil`]), t.ref`key`], {
536
- negateSigil: !value ? t.s_node(l.CSTML, 'Puncutator', '!') : null,
505
+ return t.node(l.CSTML, 'BooleanAttribute', [...when(!value, [t.ref`negateToken`]), t.ref`key`], {
506
+ negateToken: !value ? t.s_node(l.CSTML, 'Puncutator', '!') : null,
537
507
  key: buildIdentifier(key),
538
508
  });
539
509
  };
@@ -570,10 +540,12 @@ export const buildExpression = (expr) => {
570
540
  }
571
541
  };
572
542
 
543
+ export const buildAttributes = (attributes = {}) => {
544
+ return Object.entries(attributes).map(({ 0: key, 1: value }) => buildAttribute(key, value));
545
+ };
546
+
573
547
  export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
574
- const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
575
- buildAttribute(key, value),
576
- );
548
+ const attributes_ = buildAttributes(attributes);
577
549
 
578
550
  let language_ = !language || language.length === 0 ? null : language;
579
551
 
@@ -583,22 +555,22 @@ export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
583
555
  l.Spamex,
584
556
  'NodeMatcher',
585
557
  [
586
- t.ref`open`,
558
+ t.ref`openToken`,
587
559
  ...when(flags_, [t.ref`flags`]),
588
560
  ...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
589
561
  t.ref`type`,
590
562
  ...when(attributes_.length, [t.embedded(buildSpace())]),
591
563
  ...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
592
- t.ref`close`,
564
+ t.ref`closeToken`,
593
565
  ],
594
566
  {
595
- open: t.s_node(l.CSTML, 'Punctuator', '<'),
567
+ openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
596
568
  language: buildLanguage(language_),
597
569
  languageSeparator: language_ && type && t.s_node(l.CSTML, 'Punctuator', ':'),
598
570
  flags: flags_,
599
571
  type: buildIdentifier(type),
600
572
  attributes: attributes_,
601
- close: t.s_node(l.CSTML, 'Punctuator', '>'),
573
+ closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
602
574
  },
603
575
  );
604
576
  };
package/lib/index.js CHANGED
@@ -27,15 +27,15 @@ export const shouldBranch = (effects) => {
27
27
  return effects ? effects.success === 'none' || effects.failure === 'none' : false;
28
28
  };
29
29
 
30
- const reifyFlags = (node) => {
31
- let { triviaFlag, escapeFlag, tokenFlag, expressionFlag, intrinsicValue } = node.properties || {};
30
+ const reifyFlags = (flags) => {
31
+ let { triviaToken, escapeToken, tokenToken, expressionToken, intrinsicToken } = flags.properties;
32
32
 
33
33
  return {
34
- token: !!tokenFlag,
35
- escape: !!escapeFlag,
36
- trivia: !!triviaFlag,
37
- intrinsic: !!intrinsicValue,
38
- expression: !!expressionFlag,
34
+ token: !!tokenToken,
35
+ escape: !!escapeToken,
36
+ trivia: !!triviaToken,
37
+ intrinsic: !!intrinsicToken,
38
+ expression: !!expressionToken,
39
39
  };
40
40
  };
41
41
 
@@ -95,9 +95,9 @@ export const reifyExpression = (node) => {
95
95
  }
96
96
 
97
97
  case 'OpenNodeTag': {
98
- let { language, type, attributes, intrinsicValue } = node.properties;
98
+ let { flags, language, type, attributes, intrinsicValue } = node.properties;
99
99
 
100
- let flags = reifyFlags(node);
100
+ flags = reifyFlags(flags);
101
101
  language = reifyLanguage(language);
102
102
  type = reifyExpression(type);
103
103
  attributes = reifyAttributes(attributes);
@@ -150,9 +150,9 @@ export const reifyExpression = (node) => {
150
150
 
151
151
  switch (node.type) {
152
152
  case 'NodeMatcher':
153
- let { language, type, attributes, intrinsicValue } = node.properties;
153
+ let { flags, language, type, attributes, intrinsicValue } = node.properties;
154
154
 
155
- let flags = reifyFlags(node);
155
+ flags = reifyFlags(flags);
156
156
  language = reifyExpression(language);
157
157
  type = reifyExpression(type);
158
158
  attributes = reifyAttributes(attributes);
@@ -194,7 +194,7 @@ export const reifyExpression = (node) => {
194
194
 
195
195
  case 'Boolean': {
196
196
  // prettier-ignore
197
- switch (getCooked(node.properties.value)) {
197
+ switch (getCooked(node.properties.sigilToken)) {
198
198
  case 'true': return true;
199
199
  case 'false': return false;
200
200
  default: throw new Error();
@@ -249,7 +249,7 @@ export const reifyAttributes = (attributes) => {
249
249
  if (attr.type === 'MappingAttribute') {
250
250
  return [reifyExpression(attr.properties.key), reifyExpression(attr.properties.value)];
251
251
  } else if (attr.type === 'BooleanAttribute') {
252
- return [reifyExpression(attr.properties.key), !attr.properties.negateSigil];
252
+ return [reifyExpression(attr.properties.key), !attr.properties.negateToken];
253
253
  } else {
254
254
  throw new Error();
255
255
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bablr/agast-vm-helpers",
3
3
  "description": "Helper functions for working with the BABLR VM",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@bablr/agast-helpers": "0.1.1"
18
+ "@bablr/agast-helpers": "0.1.5"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",