@vue/language-core 3.0.0-beta.2 → 3.0.0-beta.4

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.
Files changed (51) hide show
  1. package/lib/codegen/codeFeatures.d.ts +5 -1
  2. package/lib/codegen/codeFeatures.js +3 -1
  3. package/lib/codegen/globalTypes.js +10 -9
  4. package/lib/codegen/localTypes.js +22 -8
  5. package/lib/codegen/script/component.js +2 -1
  6. package/lib/codegen/script/scriptSetup.js +53 -35
  7. package/lib/codegen/script/template.js +0 -1
  8. package/lib/codegen/style/classProperty.js +1 -1
  9. package/lib/codegen/style/imports.js +2 -2
  10. package/lib/codegen/style/scopedClasses.js +1 -1
  11. package/lib/codegen/template/context.d.ts +3 -2
  12. package/lib/codegen/template/context.js +4 -2
  13. package/lib/codegen/template/element.js +12 -12
  14. package/lib/codegen/template/elementDirectives.js +1 -1
  15. package/lib/codegen/template/elementEvents.js +9 -9
  16. package/lib/codegen/template/elementProps.js +4 -4
  17. package/lib/codegen/template/index.js +4 -4
  18. package/lib/codegen/template/interpolation.d.ts +3 -6
  19. package/lib/codegen/template/interpolation.js +11 -12
  20. package/lib/codegen/template/objectProperty.d.ts +1 -1
  21. package/lib/codegen/template/objectProperty.js +4 -4
  22. package/lib/codegen/template/propertyAccess.d.ts +1 -1
  23. package/lib/codegen/template/propertyAccess.js +2 -2
  24. package/lib/codegen/template/slotOutlet.js +4 -3
  25. package/lib/codegen/template/styleScopedClasses.js +4 -4
  26. package/lib/codegen/template/templateChild.js +3 -2
  27. package/lib/codegen/template/vFor.js +3 -3
  28. package/lib/codegen/template/vIf.js +1 -1
  29. package/lib/codegen/template/vSlot.js +2 -2
  30. package/lib/codegen/utils/escaped.d.ts +1 -1
  31. package/lib/codegen/utils/index.d.ts +1 -1
  32. package/lib/codegen/utils/index.js +7 -5
  33. package/lib/codegen/utils/wrapWith.d.ts +1 -1
  34. package/lib/languagePlugin.js +6 -3
  35. package/lib/parsers/scriptSetupRanges.js +14 -18
  36. package/lib/parsers/vueCompilerOptions.js +0 -1
  37. package/lib/plugins/file-html.js +6 -6
  38. package/lib/plugins/file-md.js +6 -5
  39. package/lib/plugins/file-vue.js +3 -4
  40. package/lib/plugins/vue-sfc-scripts.js +4 -2
  41. package/lib/plugins/vue-template-html.js +3 -4
  42. package/lib/plugins/vue-template-inline-ts.js +4 -2
  43. package/lib/plugins/vue-tsx.d.ts +2 -1
  44. package/lib/plugins/vue-tsx.js +2 -1
  45. package/lib/utils/parseCssImports.js +1 -1
  46. package/lib/utils/parseSfc.js +3 -3
  47. package/lib/utils/ts.js +9 -9
  48. package/lib/virtualFile/computedEmbeddedCodes.js +22 -11
  49. package/lib/virtualFile/computedSfc.d.ts +2 -0
  50. package/lib/virtualFile/computedSfc.js +114 -31
  51. package/package.json +4 -4
@@ -149,7 +149,6 @@ export declare const tsCodegen: WeakMap<Sfc, {
149
149
  };
150
150
  codeFeatures: {
151
151
  all: import("../types").VueCodeInformation;
152
- none: import("../types").VueCodeInformation;
153
152
  verification: import("../types").VueCodeInformation;
154
153
  completion: import("../types").VueCodeInformation;
155
154
  additionalCompletion: import("../types").VueCodeInformation;
@@ -160,6 +159,7 @@ export declare const tsCodegen: WeakMap<Sfc, {
160
159
  navigationAndAdditionalCompletion: import("../types").VueCodeInformation;
161
160
  navigationAndVerification: import("../types").VueCodeInformation;
162
161
  withoutNavigation: import("../types").VueCodeInformation;
162
+ semanticWithoutHighlight: import("../types").VueCodeInformation;
163
163
  withoutHighlight: import("../types").VueCodeInformation;
164
164
  withoutHighlightAndNavigation: import("../types").VueCodeInformation;
165
165
  withoutHighlightAndCompletion: import("../types").VueCodeInformation;
@@ -167,6 +167,7 @@ export declare const tsCodegen: WeakMap<Sfc, {
167
167
  withoutSemantic: import("../types").VueCodeInformation;
168
168
  };
169
169
  resolveCodeFeatures: (features: import("../types").VueCodeInformation) => import("../types").VueCodeInformation;
170
+ inlineTsAsts: Map<string, import("typescript").SourceFile> | undefined;
170
171
  inVFor: boolean;
171
172
  slots: {
172
173
  name: string;
@@ -129,7 +129,8 @@ function createTsx(fileName, sfc, ctx, appendGlobalTypes) {
129
129
  const getSetupSlotsAssignName = (0, alien_signals_1.computed)(() => getScriptSetupRanges()?.defineSlots?.name);
130
130
  const getSetupPropsAssignName = (0, alien_signals_1.computed)(() => getScriptSetupRanges()?.defineProps?.name);
131
131
  const getSetupInheritAttrs = (0, alien_signals_1.computed)(() => {
132
- const value = getScriptSetupRanges()?.defineOptions?.inheritAttrs ?? getScriptRanges()?.exportDefault?.inheritAttrsOption;
132
+ const value = getScriptSetupRanges()?.defineOptions?.inheritAttrs
133
+ ?? getScriptRanges()?.exportDefault?.inheritAttrsOption;
133
134
  return value !== 'false';
134
135
  });
135
136
  const getComponentSelfName = (0, alien_signals_1.computed)(() => {
@@ -7,7 +7,7 @@ function* parseCssImports(css) {
7
7
  for (const match of matches) {
8
8
  let text = match[0];
9
9
  let offset = match.index;
10
- if (text.startsWith('\'') || text.startsWith('"')) {
10
+ if (text.startsWith("'") || text.startsWith('"')) {
11
11
  text = text.slice(1, -1);
12
12
  offset += 1;
13
13
  }
@@ -81,7 +81,7 @@ function createBlock(node, source) {
81
81
  start = {
82
82
  line: start.line,
83
83
  column: start.column + offset,
84
- offset: start.offset + offset
84
+ offset: start.offset + offset,
85
85
  };
86
86
  }
87
87
  end = Object.assign({}, start);
@@ -89,14 +89,14 @@ function createBlock(node, source) {
89
89
  const loc = {
90
90
  source: content,
91
91
  start,
92
- end
92
+ end,
93
93
  };
94
94
  const attrs = {};
95
95
  const block = {
96
96
  type,
97
97
  content,
98
98
  loc,
99
- attrs
99
+ attrs,
100
100
  };
101
101
  node.props.forEach(p => {
102
102
  if (p.type === CompilerDOM.NodeTypes.ATTRIBUTE) {
package/lib/utils/ts.js CHANGED
@@ -21,7 +21,7 @@ function createParsedCommandLineByJson(ts, parseConfigHost, rootDir, json, confi
21
21
  const rawOptions = obj?.vueCompilerOptions ?? {};
22
22
  resolver.addConfig(rawOptions, path_browserify_1.posix.dirname(configFile.fileName));
23
23
  }
24
- catch (err) { }
24
+ catch { }
25
25
  }
26
26
  const resolvedVueOptions = resolver.build();
27
27
  if (skipGlobalTypesSetup) {
@@ -58,7 +58,7 @@ function createParsedCommandLine(ts, parseConfigHost, tsConfigPath, skipGlobalTy
58
58
  const rawOptions = obj?.vueCompilerOptions ?? {};
59
59
  resolver.addConfig(rawOptions, path_browserify_1.posix.dirname(configFile.fileName));
60
60
  }
61
- catch (err) { }
61
+ catch { }
62
62
  }
63
63
  const resolvedVueOptions = resolver.build();
64
64
  if (skipGlobalTypesSetup) {
@@ -82,7 +82,7 @@ function createParsedCommandLine(ts, parseConfigHost, tsConfigPath, skipGlobalTy
82
82
  vueOptions: resolvedVueOptions,
83
83
  };
84
84
  }
85
- catch (err) {
85
+ catch {
86
86
  // console.warn('Failed to resolve tsconfig path:', tsConfigPath, err);
87
87
  return {
88
88
  fileNames: [],
@@ -105,7 +105,7 @@ function proxyParseConfigHostForExtendConfigPaths(parseConfigHost) {
105
105
  };
106
106
  }
107
107
  return target[key];
108
- }
108
+ },
109
109
  });
110
110
  return {
111
111
  host,
@@ -176,7 +176,7 @@ class CompilerOptionsResolver {
176
176
  },
177
177
  fallthroughComponentNames: [
178
178
  ...defaults.fallthroughComponentNames,
179
- ...this.options.fallthroughComponentNames ?? []
179
+ ...this.options.fallthroughComponentNames ?? [],
180
180
  ].map(shared_2.hyphenateTag),
181
181
  // https://github.com/vuejs/vue-next/blob/master/packages/compiler-dom/src/transforms/vModel.ts#L49-L51
182
182
  // https://vuejs.org/guide/essentials/forms.html#form-input-bindings
@@ -205,7 +205,7 @@ function resolvePath(scriptPath, root) {
205
205
  // console.warn('failed to resolve path:', scriptPath, 'require.resolve is not supported in web');
206
206
  }
207
207
  }
208
- catch (error) {
208
+ catch {
209
209
  // console.warn(error);
210
210
  }
211
211
  }
@@ -261,13 +261,13 @@ function getDefaultCompilerOptions(target = 99, lib = 'vue', strictTemplates = f
261
261
  plugins: [],
262
262
  experimentalModelPropName: {
263
263
  '': {
264
- input: true
264
+ input: true,
265
265
  },
266
266
  value: {
267
267
  input: { type: 'text' },
268
268
  textarea: true,
269
- select: true
270
- }
269
+ select: true,
270
+ },
271
271
  },
272
272
  };
273
273
  }
@@ -177,7 +177,8 @@ function computedPluginEmbeddedCodes(plugins, plugin, fileName, sfc, getBlockByN
177
177
  if (mapping.data.__combineOffset !== undefined) {
178
178
  const offsetMapping = mappings[i - mapping.data.__combineOffset];
179
179
  if (typeof offsetMapping === 'string' || !offsetMapping) {
180
- throw new Error('Invalid offset mapping, mappings: ' + mappings.length + ', i: ' + i + ', offset: ' + mapping.data.__combineOffset);
180
+ throw new Error('Invalid offset mapping, mappings: ' + mappings.length + ', i: ' + i + ', offset: '
181
+ + mapping.data.__combineOffset);
181
182
  }
182
183
  offsetMapping.sourceOffsets.push(...mapping.sourceOffsets);
183
184
  offsetMapping.generatedOffsets.push(...mapping.generatedOffsets);
@@ -235,16 +236,26 @@ function fullDiffTextChangeRange(oldText, newText) {
235
236
  }
236
237
  function resolveCommonLanguageId(lang) {
237
238
  switch (lang) {
238
- case 'js': return 'javascript';
239
- case 'cjs': return 'javascript';
240
- case 'mjs': return 'javascript';
241
- case 'ts': return 'typescript';
242
- case 'cts': return 'typescript';
243
- case 'mts': return 'typescript';
244
- case 'jsx': return 'javascriptreact';
245
- case 'tsx': return 'typescriptreact';
246
- case 'pug': return 'jade';
247
- case 'md': return 'markdown';
239
+ case 'js':
240
+ return 'javascript';
241
+ case 'cjs':
242
+ return 'javascript';
243
+ case 'mjs':
244
+ return 'javascript';
245
+ case 'ts':
246
+ return 'typescript';
247
+ case 'cts':
248
+ return 'typescript';
249
+ case 'mts':
250
+ return 'typescript';
251
+ case 'jsx':
252
+ return 'javascriptreact';
253
+ case 'tsx':
254
+ return 'typescriptreact';
255
+ case 'pug':
256
+ return 'jade';
257
+ case 'md':
258
+ return 'markdown';
248
259
  }
249
260
  return lang;
250
261
  }
@@ -1,4 +1,6 @@
1
+ import type * as CompilerDOM from '@vue/compiler-dom';
1
2
  import type { SFCParseResult } from '@vue/compiler-sfc';
2
3
  import type * as ts from 'typescript';
3
4
  import type { Sfc, VueLanguagePluginReturn } from '../types';
5
+ export declare const templateInlineTsAsts: WeakMap<CompilerDOM.RootNode, Map<string, ts.SourceFile>>;
4
6
  export declare function computedSfc(ts: typeof import('typescript'), plugins: VueLanguagePluginReturn[], fileName: string, getSnapshot: () => ts.IScriptSnapshot, getParseResult: () => SFCParseResult | undefined): Sfc;
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.templateInlineTsAsts = void 0;
3
4
  exports.computedSfc = computedSfc;
4
5
  const alien_signals_1 = require("alien-signals");
5
6
  const parseCssClassNames_1 = require("../utils/parseCssClassNames");
6
7
  const parseCssImports_1 = require("../utils/parseCssImports");
7
8
  const parseCssVars_1 = require("../utils/parseCssVars");
8
9
  const signals_1 = require("../utils/signals");
10
+ exports.templateInlineTsAsts = new WeakMap();
9
11
  function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
10
12
  const getUntrackedSnapshot = () => {
11
13
  const pausedSub = (0, alien_signals_1.setCurrentSub)(undefined);
@@ -27,9 +29,15 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
27
29
  const getTemplate = computedNullableSfcBlock('template', 'html', (0, alien_signals_1.computed)(() => getParseResult()?.descriptor.template ?? undefined), (_block, base) => {
28
30
  const compiledAst = computedTemplateAst(base);
29
31
  return mergeObject(base, {
30
- get ast() { return compiledAst()?.ast; },
31
- get errors() { return compiledAst()?.errors; },
32
- get warnings() { return compiledAst()?.warnings; },
32
+ get ast() {
33
+ return compiledAst()?.ast;
34
+ },
35
+ get errors() {
36
+ return compiledAst()?.errors;
37
+ },
38
+ get warnings() {
39
+ return compiledAst()?.warnings;
40
+ },
33
41
  });
34
42
  });
35
43
  const getScript = computedNullableSfcBlock('script', 'js', (0, alien_signals_1.computed)(() => getParseResult()?.descriptor.script ?? undefined), (block, base) => {
@@ -44,8 +52,12 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
44
52
  return ts.createSourceFile(fileName + '.' + base.lang, '', 99);
45
53
  });
46
54
  return mergeObject(base, {
47
- get src() { return getSrc(); },
48
- get ast() { return getAst(); },
55
+ get src() {
56
+ return getSrc();
57
+ },
58
+ get ast() {
59
+ return getAst();
60
+ },
49
61
  });
50
62
  });
51
63
  const getOriginalScriptSetup = computedNullableSfcBlock('scriptSetup', 'js', (0, alien_signals_1.computed)(() => getParseResult()?.descriptor.scriptSetup ?? undefined), (block, base) => {
@@ -60,15 +72,19 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
60
72
  return ts.createSourceFile(fileName + '.' + base.lang, '', 99);
61
73
  });
62
74
  return mergeObject(base, {
63
- get generic() { return getGeneric(); },
64
- get ast() { return getAst(); },
75
+ get generic() {
76
+ return getGeneric();
77
+ },
78
+ get ast() {
79
+ return getAst();
80
+ },
65
81
  });
66
82
  });
67
83
  const hasScript = (0, alien_signals_1.computed)(() => !!getParseResult()?.descriptor.script);
68
84
  const hasScriptSetup = (0, alien_signals_1.computed)(() => !!getParseResult()?.descriptor.scriptSetup);
69
85
  const getScriptSetup = (0, alien_signals_1.computed)(() => {
70
86
  if (!hasScript() && !hasScriptSetup()) {
71
- //#region monkey fix: https://github.com/vuejs/language-tools/pull/2113
87
+ // #region monkey fix: https://github.com/vuejs/language-tools/pull/2113
72
88
  return {
73
89
  content: '',
74
90
  lang: 'ts',
@@ -94,38 +110,86 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
94
110
  const getCssVars = (0, signals_1.computedItems)(() => [...(0, parseCssVars_1.parseCssVars)(base.content)], (oldItem, newItem) => oldItem.text === newItem.text && oldItem.offset === newItem.offset);
95
111
  const getClassNames = (0, signals_1.computedItems)(() => [...(0, parseCssClassNames_1.parseCssClassNames)(base.content)], (oldItem, newItem) => oldItem.text === newItem.text && oldItem.offset === newItem.offset);
96
112
  return () => mergeObject(base, {
97
- get src() { return getSrc(); },
98
- get module() { return getModule(); },
99
- get scoped() { return getScoped(); },
100
- get imports() { return getImports(); },
101
- get cssVars() { return getCssVars(); },
102
- get classNames() { return getClassNames(); },
113
+ get src() {
114
+ return getSrc();
115
+ },
116
+ get module() {
117
+ return getModule();
118
+ },
119
+ get scoped() {
120
+ return getScoped();
121
+ },
122
+ get imports() {
123
+ return getImports();
124
+ },
125
+ get cssVars() {
126
+ return getCssVars();
127
+ },
128
+ get classNames() {
129
+ return getClassNames();
130
+ },
103
131
  });
104
132
  });
105
133
  const customBlocks = (0, signals_1.computedArray)((0, alien_signals_1.computed)(() => getParseResult()?.descriptor.customBlocks ?? []), (getBlock, i) => {
106
134
  const base = computedSfcBlock('custom_block_' + i, 'txt', getBlock);
107
135
  const getType = (0, alien_signals_1.computed)(() => getBlock().type);
108
136
  return () => mergeObject(base, {
109
- get type() { return getType(); },
137
+ get type() {
138
+ return getType();
139
+ },
110
140
  });
111
141
  });
112
142
  return {
113
- get content() { return getContent(); },
114
- get comments() { return getComments(); },
115
- get template() { return getTemplate(); },
116
- get script() { return getScript(); },
117
- get scriptSetup() { return getScriptSetup(); },
118
- get styles() { return styles; },
119
- get customBlocks() { return customBlocks; },
143
+ get content() {
144
+ return getContent();
145
+ },
146
+ get comments() {
147
+ return getComments();
148
+ },
149
+ get template() {
150
+ return getTemplate();
151
+ },
152
+ get script() {
153
+ return getScript();
154
+ },
155
+ get scriptSetup() {
156
+ return getScriptSetup();
157
+ },
158
+ get styles() {
159
+ return styles;
160
+ },
161
+ get customBlocks() {
162
+ return customBlocks;
163
+ },
120
164
  };
121
165
  function computedTemplateAst(base) {
122
166
  let cache;
167
+ let inlineTsAsts;
168
+ function updateInlineTsAsts(newAst, oldAst) {
169
+ let newTsAsts = exports.templateInlineTsAsts.get(newAst);
170
+ if (!newTsAsts) {
171
+ exports.templateInlineTsAsts.set(newAst, newTsAsts = new Map());
172
+ }
173
+ const oldTsAsts = oldAst && exports.templateInlineTsAsts.get(oldAst) || inlineTsAsts;
174
+ if (oldTsAsts) {
175
+ for (const [text, ast] of oldTsAsts) {
176
+ if (!ast.__volar_used) {
177
+ oldTsAsts.delete(text);
178
+ }
179
+ else {
180
+ newTsAsts.set(text, ast);
181
+ ast.__volar_used = false;
182
+ }
183
+ }
184
+ }
185
+ inlineTsAsts = new Map(newTsAsts);
186
+ }
123
187
  return (0, alien_signals_1.computed)(() => {
124
188
  if (cache?.template === base.content) {
125
189
  return {
126
190
  errors: [],
127
191
  warnings: [],
128
- ast: cache?.result.ast,
192
+ ast: cache.result.ast,
129
193
  };
130
194
  }
131
195
  // incremental update
@@ -142,6 +206,7 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
142
206
  newText,
143
207
  });
144
208
  if (newResult) {
209
+ updateInlineTsAsts(newResult.ast, cache.result.ast);
145
210
  cache.template = base.content;
146
211
  cache.snapshot = getUntrackedSnapshot();
147
212
  cache.result = newResult;
@@ -169,6 +234,9 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
169
234
  let result;
170
235
  try {
171
236
  result = plugin.compileSFCTemplate?.(base.lang, base.content, options);
237
+ if (result) {
238
+ updateInlineTsAsts(result.ast, cache?.result.ast);
239
+ }
172
240
  }
173
241
  catch (e) {
174
242
  const err = e;
@@ -217,16 +285,31 @@ function computedSfc(ts, plugins, fileName, getSnapshot, getParseResult) {
217
285
  const getStartTagEnd = (0, alien_signals_1.computed)(() => getBlock().loc.start.offset);
218
286
  const getEndTagStart = (0, alien_signals_1.computed)(() => getBlock().loc.end.offset);
219
287
  const getStart = (0, alien_signals_1.computed)(() => getUntrackedSnapshot().getText(0, getStartTagEnd()).lastIndexOf('<' + getBlock().type));
220
- const getEnd = (0, alien_signals_1.computed)(() => getEndTagStart() + getUntrackedSnapshot().getText(getEndTagStart(), getUntrackedSnapshot().getLength()).indexOf('>') + 1);
288
+ const getEnd = (0, alien_signals_1.computed)(() => getEndTagStart()
289
+ + getUntrackedSnapshot().getText(getEndTagStart(), getUntrackedSnapshot().getLength()).indexOf('>') + 1);
221
290
  return {
222
291
  name,
223
- get lang() { return getLang(); },
224
- get attrs() { return getAttrs(); },
225
- get content() { return getContent(); },
226
- get startTagEnd() { return getStartTagEnd(); },
227
- get endTagStart() { return getEndTagStart(); },
228
- get start() { return getStart(); },
229
- get end() { return getEnd(); },
292
+ get lang() {
293
+ return getLang();
294
+ },
295
+ get attrs() {
296
+ return getAttrs();
297
+ },
298
+ get content() {
299
+ return getContent();
300
+ },
301
+ get startTagEnd() {
302
+ return getStartTagEnd();
303
+ },
304
+ get endTagStart() {
305
+ return getEndTagStart();
306
+ },
307
+ get start() {
308
+ return getStart();
309
+ },
310
+ get end() {
311
+ return getEnd();
312
+ },
230
313
  };
231
314
  }
232
315
  function computedAttrValue(key, base, getBlock) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue/language-core",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.4",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -13,7 +13,7 @@
13
13
  "directory": "packages/language-core"
14
14
  },
15
15
  "dependencies": {
16
- "@volar/language-core": "2.4.14",
16
+ "@volar/language-core": "2.4.15",
17
17
  "@vue/compiler-dom": "^3.5.0",
18
18
  "@vue/shared": "^3.5.0",
19
19
  "alien-signals": "^2.0.5",
@@ -24,7 +24,7 @@
24
24
  "devDependencies": {
25
25
  "@types/node": "^22.10.4",
26
26
  "@types/path-browserify": "^1.0.1",
27
- "@volar/typescript": "2.4.14",
27
+ "@volar/typescript": "2.4.15",
28
28
  "@vue/compiler-sfc": "^3.5.0"
29
29
  },
30
30
  "peerDependencies": {
@@ -35,5 +35,5 @@
35
35
  "optional": true
36
36
  }
37
37
  },
38
- "gitHead": "ea40288f6fceebb65346732b6de5859c300cf1ee"
38
+ "gitHead": "5cb41faacbfe2d9e2d64637c6c1ae8769d9cba3f"
39
39
  }