@tricoteuses/assemblee 1.8.0 → 1.9.1

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 (101) hide show
  1. package/lib/bugs/acteur-00010/plugin.test.js +2 -2
  2. package/lib/bugs/acteur-00010.js +3 -3
  3. package/lib/bugs/agenda-00002/plugin.test.js +3 -3
  4. package/lib/bugs/agenda-00002.js +5 -5
  5. package/lib/bugs/agenda-00008/plugin.test.js +2 -2
  6. package/lib/bugs/agenda-00008.js +3 -3
  7. package/lib/bugs/agenda-00011/plugin.test.js +6 -6
  8. package/lib/bugs/agenda-00011.js +8 -8
  9. package/lib/bugs.js +11 -11
  10. package/lib/cleaners/index.d.ts +1 -0
  11. package/lib/cleaners/index.js +8 -1
  12. package/lib/cleaners/index.mjs +2 -1
  13. package/lib/cleaners/scrutins.js +2 -1
  14. package/lib/cleaners/scrutins.mjs +3 -2
  15. package/lib/cleaners/textes_loi.d.ts +1 -0
  16. package/lib/cleaners/textes_loi.js +12 -0
  17. package/lib/cleaners/textes_loi.mjs +5 -0
  18. package/lib/cleaners/xml.d.ts +3 -0
  19. package/lib/cleaners/xml.js +13 -1
  20. package/lib/cleaners/xml.mjs +11 -1
  21. package/lib/datasets.d.ts +9 -2
  22. package/lib/datasets.js +24 -3
  23. package/lib/datasets.mjs +24 -3
  24. package/lib/dates.js +3 -3
  25. package/lib/examples/PIONANR5L15B0020/input.d.ts +2 -0
  26. package/lib/examples/PIONANR5L15B0020/input.js +10 -0
  27. package/lib/examples/PIONANR5L15B0020/input.mjs +193 -0
  28. package/lib/examples/PRJLANR5L16B0914/input.d.ts +2 -0
  29. package/lib/examples/PRJLANR5L16B0914/input.js +10 -0
  30. package/lib/examples/PRJLANR5L16B0914/input.mjs +322 -0
  31. package/lib/examples/PRJLANR5L16B2014/input.d.ts +2 -0
  32. package/lib/examples/PRJLANR5L16B2014/input.js +10 -0
  33. package/lib/examples/PRJLANR5L16B2014/input.mjs +577 -0
  34. package/lib/examples/PRJLANR5L16B2424/input.d.ts +2 -0
  35. package/lib/examples/PRJLANR5L16B2424/input.js +10 -0
  36. package/lib/examples/PRJLANR5L16B2424/input.mjs +322 -0
  37. package/lib/examples/PRJLANR5L16B2462/input.d.ts +2 -0
  38. package/lib/examples/PRJLANR5L16B2462/input.js +10 -0
  39. package/lib/examples/PRJLANR5L16B2462/input.mjs +1308 -0
  40. package/lib/loaders.d.ts +5 -0
  41. package/lib/loaders.js +308 -262
  42. package/lib/loaders.mjs +16 -3
  43. package/lib/logger.d.ts +16 -0
  44. package/lib/logger.js +35 -0
  45. package/lib/logger.mjs +26 -0
  46. package/lib/parsers/documents.js +2 -2
  47. package/lib/parsers/textes_lois.d.ts +16 -1
  48. package/lib/parsers/textes_lois.js +733 -28
  49. package/lib/parsers/textes_lois.mjs +587 -22
  50. package/lib/raw_types/acteurs_et_organes.js +1 -1
  51. package/lib/raw_types/agendas.js +1 -1
  52. package/lib/raw_types/amendements.js +1 -1
  53. package/lib/raw_types/debats.js +1 -1
  54. package/lib/raw_types/dossiers_legislatifs.js +1 -1
  55. package/lib/raw_types/questions.js +1 -1
  56. package/lib/raw_types/scrutins.d.ts +18 -13
  57. package/lib/raw_types/scrutins.js +28 -14
  58. package/lib/raw_types/scrutins.mjs +28 -14
  59. package/lib/raw_types/textes_loi.d.ts +93 -0
  60. package/lib/raw_types/textes_loi.js +429 -0
  61. package/lib/raw_types/textes_loi.mjs +378 -0
  62. package/lib/scripts/bugs_helper.js +9 -9
  63. package/lib/scripts/document_dossiers_legislatifs.js +1 -1
  64. package/lib/scripts/process_open_dataset.d.ts +17 -0
  65. package/lib/scripts/process_open_dataset.js +302 -0
  66. package/lib/scripts/process_open_dataset.mjs +136 -0
  67. package/lib/scripts/process_textes_loi_dataset.d.ts +7 -0
  68. package/lib/scripts/process_textes_loi_dataset.js +374 -0
  69. package/lib/scripts/process_textes_loi_dataset.mjs +237 -0
  70. package/lib/scripts/raw_types_from_amendements.js +2 -2
  71. package/lib/scripts/reorganize_data.js +1 -1
  72. package/lib/scripts/reorganize_data.mjs +1 -1
  73. package/lib/scripts/retrieve_deputes_photos.js +3 -3
  74. package/lib/scripts/retrieve_documents.js +4 -4
  75. package/lib/scripts/retrieve_open_data.js +41 -279
  76. package/lib/scripts/retrieve_open_data.mjs +13 -126
  77. package/lib/scripts/retrieve_pending_amendments.js +2 -2
  78. package/lib/scripts/retrieve_senateurs_photos.js +2 -2
  79. package/lib/scripts/retrieve_textes_lois.js +2 -2
  80. package/lib/scripts/shared/cli_helpers.d.ts +5 -0
  81. package/lib/scripts/shared/cli_helpers.js +7 -2
  82. package/lib/scripts/shared/cli_helpers.mjs +6 -1
  83. package/lib/scripts/test_iter_load.js +25 -10
  84. package/lib/scripts/test_iter_load.mjs +19 -11
  85. package/lib/scripts/validate_json.js +3 -3
  86. package/lib/types/acteurs_et_organes.js +1 -1
  87. package/lib/types/agendas.js +1 -1
  88. package/lib/types/amendements.js +1 -1
  89. package/lib/types/debats.js +1 -1
  90. package/lib/types/dossiers_legislatifs.js +1 -1
  91. package/lib/types/questions.js +1 -1
  92. package/lib/types/scrutins.d.ts +6 -3
  93. package/lib/types/scrutins.js +13 -7
  94. package/lib/types/scrutins.mjs +13 -7
  95. package/lib/types/textes_loi.d.ts +94 -0
  96. package/lib/types/textes_loi.js +429 -0
  97. package/lib/types/textes_loi.mjs +378 -0
  98. package/package.json +13 -12
  99. package/lib/scripts/retrieve_textes_lois_llm.d.ts +0 -1
  100. package/lib/scripts/retrieve_textes_lois_llm.js +0 -188
  101. package/lib/scripts/retrieve_textes_lois_llm.mjs +0 -85
@@ -1,43 +1,608 @@
1
1
  import { ChatOpenAI } from "@langchain/openai";
2
2
  import { ChatPromptTemplate } from "@langchain/core/prompts";
3
3
  import Ajv from "ajv";
4
- const texteLoiSchema = require("../schemas/texte_loi/TexteLoi.json");
4
+ import { delimiter, runLogFun } from "../logger.mjs";
5
+ const EXPOSE_MOTIFS_SCHEMA = require("../schemas/texte_loi/ExposeMotifs");
6
+ const META_DONNEES_SCHEMA = require("../schemas/texte_loi/MetaDonnees");
7
+ const PROJET_LOI_SCHEMA = require("../schemas/texte_loi/ProjetLoi");
8
+ const ALINEA_SCHEMA = require("../schemas/texte_loi/Alinea");
9
+ const SOMMAIRE_SCHEMA = require("../schemas/texte_loi/Sommaire");
10
+
11
+ /**
12
+ * Object containing input examples and their output schemas.
13
+ * Used to train the LLM.
14
+ * @type {Record<string, {motifs: any, input: any, loi: any, meta: any, sommaire: any}>}
15
+ */
16
+ const EXAMPLES = {
17
+ PRJLANR5L16B0914: {
18
+ motifs: require("../examples/PRJLANR5L16B0914/motifs"),
19
+ input: require("../examples/PRJLANR5L16B0914/input"),
20
+ loi: require("../examples/PRJLANR5L16B0914/loi"),
21
+ meta: require("../examples/PRJLANR5L16B0914/meta"),
22
+ sommaire: require("../examples/PRJLANR5L16B0914/sommaire")
23
+ },
24
+ PRJLANR5L16B2014: {
25
+ motifs: require("../examples/PRJLANR5L16B2014/motifs"),
26
+ input: require("../examples/PRJLANR5L16B2014/input"),
27
+ loi: require("../examples/PRJLANR5L16B2014/loi"),
28
+ meta: require("../examples/PRJLANR5L16B2014/meta"),
29
+ sommaire: require("../examples/PRJLANR5L16B2014/sommaire")
30
+ },
31
+ PRJLANR5L16B2424: {
32
+ alineas: require("../examples/PRJLANR5L16B2424/alineas"),
33
+ motifs: require("../examples/PRJLANR5L16B2424/motifs"),
34
+ input: require("../examples/PRJLANR5L16B2424/input"),
35
+ loi: require("../examples/PRJLANR5L16B2424/loi"),
36
+ meta: require("../examples/PRJLANR5L16B2424/meta"),
37
+ sommaire: require("../examples/PRJLANR5L16B2424/sommaire")
38
+ }
39
+ };
40
+ const FULL_TEXTE_SCHEMA = {
41
+ $schema: "http://json-schema.org/draft-07/schema#",
42
+ title: "Sommaire",
43
+ description: "Récupération d'un texte complet",
44
+ type: "object",
45
+ properties: {
46
+ texte: {
47
+ description: "Texte complet de la section indiquée.",
48
+ type: "string"
49
+ }
50
+ },
51
+ required: ["texte"]
52
+ };
53
+
54
+ /**
55
+ * LLM model.
56
+ */
57
+ let MODEL = null;
58
+ if (process.env.OPENAI_API_KEY) {
59
+ MODEL = new ChatOpenAI({
60
+ temperature: 0,
61
+ topP: 0.0,
62
+ model: "gpt-4o-mini",
63
+ apiKey: process.env.OPENAI_API_KEY,
64
+ maxTokens: -1
65
+ });
66
+ }
67
+
68
+ /**
69
+ * System input template for the LLM.
70
+ */
71
+ const SYSTEM_TEMPLATE = `
72
+ # Instructions :
73
+
74
+ Tu es un expert de la loi et de l'analyse de pages HTML.
75
+ Tu dois analyser un texte de loi afin de séparer et de structurer les éléments qui le composent. Le format d'entrée est HTML.
76
+
77
+ Le texte est divisé en deux parties :
78
+ A) un exposé des motifs qui indique les raisons pour lesquelles ce projet est soumis au Parlement. Il peut contenir 3 éléments : 1) une citation au début d'un document, 2) le texte principal qui développe les arguments de l'auteur à l'appui de la modification législative ou des dispositions nouvelles qu'il propose, 3) des paragraphes qui présentent les articles.
79
+ B) le dispositif qui est la partie normative et rédigée en articles. Il peut comporter des divisions nommées titres, chapitres, sections, sous-sections. Lorsqu'il y a un seul niveau de structure, on retrouvera le chapitre ; s’il y a deux niveaux de structure, on retrouvera des chapitres puis des sections. S’il y a trois niveaux de structure, on retrouvera des titres puis des chapitres puis des sections.
80
+
81
+ Si le texte de loi ne comporte pas de division, le sommaire doit rester vide.
82
+ Toutes les lignes qui débutent par un '«' ne sont pas à prendre en compte dans les divisions
83
+ Ta réponse doit être un JSON structuré avec les éléments du texte de loi en respectant le schéma JSON fourni.
84
+ `;
85
+ let SILENT_LOG = false;
86
+
87
+ /**
88
+ * Parses the given HTML string and returns the parsed textes loi.
89
+ *
90
+ * @param {string} html - The HTML string to parse.
91
+ * @return {Promise<{partial: {sommaire: any, loi: any, motifs: any, meta: any}, completed: {sommaire: any, loi: any, motifs: any, meta: any}}>} - The parsed textes loi, including the partial and completed versions.
92
+ */
93
+ export async function parseTexteLoi(html, options = {
94
+ silent: false
95
+ }) {
96
+ SILENT_LOG = options.silent;
97
+ runLogFun(console.info("Start extracting loi..."), options);
98
+ const meta = await extractMetaDonnees(html);
99
+ const sommaire = await extractSommaire(html);
100
+ const partialMotifs = await extractMotifs(html);
101
+ const partialLoi = await extractProjetLoi(html);
102
+ const exposeMotifs = await populateMotifs(partialMotifs, html);
103
+ const loi = await populateProjetLoi(partialLoi, html);
104
+ return {
105
+ sommaire,
106
+ loi,
107
+ exposeMotifs,
108
+ meta
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Cleans the given HTML string by removing unnecessary tags and content.
114
+ *
115
+ * @param {string} html - The HTML string to be cleaned.
116
+ * @return {string} The cleaned HTML string.
117
+ */
5
118
  function cleanHtml(html) {
6
119
  let cleanedHtml = html.replace(/(<style[\w\W]+style>)/g, "");
7
120
  cleanedHtml = cleanedHtml.replace(/(<head[\w\W]+head>)/g, "");
8
121
  cleanedHtml = cleanedHtml.replace(/<img[^>]*>/g, "");
9
122
  return cleanedHtml;
10
123
  }
11
- export async function parseTexteLoi(html) {
12
- const cleanedHtml = cleanHtml(html);
13
- const model = new ChatOpenAI({
14
- temperature: 0,
15
- model: "gpt-4o",
16
- apiKey: process.env.OPENAI_API_KEY
124
+
125
+ /**
126
+ * Removes all HTML tags from the given HTML string and returns the cleaned text.
127
+ *
128
+ * @param {string} html - The HTML string from which to remove tags.
129
+ * @return {string} The cleaned text without any HTML tags.
130
+ */
131
+ function removeHtmlTags(html) {
132
+ // Regular expression to match HTML tags
133
+ const htmlTagRegex = /<[^>]*>/g;
134
+
135
+ // Replace all HTML tags with an empty string
136
+ const textWithoutTags = html.replace(htmlTagRegex, "");
137
+ return textWithoutTags;
138
+ }
139
+
140
+ /**
141
+ * Populates the motifs object with the extracted text from the given HTML.
142
+ *
143
+ * @param {Record<string, any>} motifs - The motifs object to be populated.
144
+ * @param {string} html - The HTML string from which to extract the text.
145
+ * @return {Promise<Record<string, any>>} - The populated motifs object.
146
+ */
147
+ async function populateMotifs(motifs, html) {
148
+ runLogFun(console.info("Populating expose motifs..."));
149
+ let cleanedHtml = cleanHtml(html);
150
+ if (motifs.debut === motifs.fin || !motifs.fin) {
151
+ motifs.texte = motifs.debut;
152
+ } else {
153
+ const systemTemplate = `
154
+ # Instructions :
155
+
156
+ Tu es un expert de la loi et de l'analyse de pages HTML.
157
+ Tu dois analyser un texte de loi afin d'en extraire certaines parties.
158
+ Le format d'entrée est du HTML. Le format de sortie est du texte.
159
+ Récupère l'intégralité du texte commençant par :
160
+
161
+ """
162
+ {debut}
163
+ """
164
+
165
+ Et finissant par :
166
+
167
+ """
168
+ {fin}
169
+ """
170
+ `;
171
+ const prompt = ChatPromptTemplate.fromMessages([["system", systemTemplate], ["human", "{input}"]]);
172
+ const structuredModel = MODEL.withStructuredOutput(FULL_TEXTE_SCHEMA);
173
+ const chain = prompt.pipe(structuredModel);
174
+ const articlePromptResult = await chain.invoke({
175
+ input: cleanedHtml,
176
+ debut: motifs.debut,
177
+ fin: motifs.fin
178
+ });
179
+ motifs.texte = articlePromptResult.texte;
180
+ }
181
+ runLogFun(console.info("Opération de peuplement de l'exposé des motifs terminée ✅"), {
182
+ silent: SILENT_LOG
17
183
  });
18
- const structuredModel = model.withStructuredOutput(texteLoiSchema);
184
+ delimiter(SILENT_LOG);
185
+ delete motifs.debut;
186
+ delete motifs.fin;
187
+ return motifs;
188
+ }
189
+
190
+ /**
191
+ * Asynchronously populates a projet loi object with the full text of each article and alinea in the given HTML.
192
+ *
193
+ * @param {Record<string, any>} partial - The partial projet loi object to be populated.
194
+ * @param {string} html - The HTML containing the text of the articles and alineas.
195
+ * @return {Promise<Record<string, any>>} A Promise that resolves to the fully populated projet loi object.
196
+ */
197
+ async function populateProjetLoi(partial, html) {
198
+ runLogFun(console.group("Peuplement du projet loi..."), {
199
+ silent: SILENT_LOG
200
+ });
201
+ let cleanedHtml = cleanHtml(html);
202
+ const articles = partial.articles;
203
+ const fullArticles = [];
19
204
  const systemTemplate = `
20
- Tu es un expert de la loi et de l'analyse de pages HTML.
21
- Tu dois analyser un texte de loi afin de séparer et structurer les éléments qui le composent. Le format d'entrée est HTML.
205
+ # Instructions :
22
206
 
23
- Le texte est divisé en deux parties :
24
- A) un exposé des motifs qui indique les raisons pour lesquelles ce projet est soumis au Parlement. Il peut contenir 3 éléments : 1) une citation au début d'un document, 2) le texte principal qui développe les arguments de l'auteur à l'appui de la modification législative ou des dispositions nouvelles qu'il propose, 3) des paragraphes qui présentent les articles.
25
- B) le dispositif qui est la partie normative et rédigée en articles. Il peut comporter des divisions nommées titres, chapitres, sections, sous-sections. Lorsqu'il y a un seul niveau de structure, on retrouvera le chapitre ; s’il y a deux niveaux de structure, on retrouvera des chapitres puis des sections. S’il y a trois niveaux de structure, on retrouvera des titres puis des chapitres puis des sections.
207
+ Tu es un expert de la loi et de l'analyse de pages HTML.
208
+ Tu dois analyser un texte de loi afin d'en extraire certaines parties.
209
+ Le format d'entrée est du HTML. Le format de sortie est du texte.
210
+ Récupère l'intégralité du texte commençant par :
26
211
 
27
- Si le texte de loi ne comporte pas de division, le sommaire doit rester vide.
28
- Toutes les lignes qui débutent par un '«' ne sont pas à prendre en compte dans les divisions
29
- Lorsque les textes ont été modifiés, il n'y pas d'exposé des motifs.
30
- Ta réponse doit être un JSON structuré avec les éléments du texte de loi en respectant le schéma JSON fourni.
31
- `;
212
+ """
213
+ {debut}
214
+ """
215
+
216
+ Et finissant par :
217
+
218
+ """
219
+ {fin}
220
+ """
221
+ `;
32
222
  const prompt = ChatPromptTemplate.fromMessages([["system", systemTemplate], ["human", "{input}"]]);
223
+ const structuredModel = MODEL.withStructuredOutput(FULL_TEXTE_SCHEMA);
224
+ const chain = prompt.pipe(structuredModel);
225
+ for (const article of articles) {
226
+ if (article.debut === article.fin || !article.fin) {
227
+ article.texte = article.debut;
228
+ } else {
229
+ const articlePromptResult = await chain.invoke({
230
+ input: cleanedHtml,
231
+ debut: article.debut,
232
+ fin: article.fin
233
+ });
234
+ article.texte = articlePromptResult.texte;
235
+ }
236
+ for (const alinea of article.alineas) {
237
+ if (alinea.debut === alinea.fin || !alinea.fin) {
238
+ alinea.texte = alinea.debut;
239
+ continue;
240
+ }
241
+ const alineaPromptResult = await chain.invoke({
242
+ input: article.texte,
243
+ debut: alinea.debut,
244
+ fin: alinea.fin
245
+ });
246
+ delete alinea.debut;
247
+ delete alinea.fin;
248
+ alinea.texte = alineaPromptResult.texte;
249
+ }
250
+ runLogFun(console.info("Opération de peuplement du contenu du projet de loi terminée ✅"), {
251
+ silent: SILENT_LOG
252
+ });
253
+ delete article.debut;
254
+ delete article.fin;
255
+ fullArticles.push(article);
256
+ }
257
+ const projetLoi = {
258
+ ...partial,
259
+ articles: fullArticles
260
+ };
261
+ runLogFun(console.groupEnd(), {
262
+ silent: SILENT_LOG
263
+ });
264
+ delimiter();
265
+ return projetLoi;
266
+ }
267
+
268
+ /**
269
+ * Asynchronously extracts the "expose motifs" from the given HTML.
270
+ *
271
+ * @param {string} html - The HTML string from which to extract the "expose motifs".
272
+ * @return {Promise<Record<string, any>>} - A Promise that resolves to the extracted "expose motifs" object.
273
+ * The object contains the following properties:
274
+ * - `debut`: The beginning of the "expose motifs".
275
+ * - `fin`: The end of the "expose motifs".
276
+ * @throws {Error} - If the extracted "expose motifs" do not validate against the EXPOSE_MOTIFS_SCHEMA.
277
+ */
278
+ async function extractMotifs(html) {
279
+ runLogFun(console.group("Parsing expose motifs..."), {
280
+ silent: SILENT_LOG
281
+ });
282
+ let cleanedHtml = cleanHtml(html);
283
+ cleanedHtml = removeHtmlTags(cleanedHtml);
284
+ const structuredModel = MODEL.withStructuredOutput(EXPOSE_MOTIFS_SCHEMA);
285
+ const motifsSystemTemplate = `
286
+ ${SYSTEM_TEMPLATE}
287
+
288
+ # Examples:
289
+
290
+ ## Exemple 1 User Input :
291
+ """
292
+ {example1}
293
+ """
294
+
295
+ ## Exemple 1 JSON Output :
296
+ """
297
+ {output1}
298
+ """
299
+
300
+ ## Exemple 2 User Input :
301
+ """
302
+ {example2}
303
+ """
304
+
305
+ ## Exemple 2 JSON Output :
306
+ """
307
+ {output2}
308
+ """
309
+ `;
310
+ const prompt = ChatPromptTemplate.fromMessages([["system", motifsSystemTemplate], ["human", "{input}"]]);
311
+ const chain = prompt.pipe(structuredModel);
312
+ const motifsPromptResult = await chain.invoke({
313
+ input: cleanedHtml,
314
+ example1: EXAMPLES.PRJLANR5L16B0914.input,
315
+ example2: EXAMPLES.PRJLANR5L16B2424.input,
316
+ output1: EXAMPLES.PRJLANR5L16B0914.motifs,
317
+ output2: EXAMPLES.PRJLANR5L16B2424.motifs
318
+ });
319
+
320
+ // console.log(JSON.stringify(motifsPromptResult))
321
+ runLogFun(console.table([["Début", motifsPromptResult.debut.substring(0, 30)], ["Fin", motifsPromptResult.fin.substring(0, 30)]]), {
322
+ silent: SILENT_LOG
323
+ });
324
+ runLogFun(console.groupEnd(), {
325
+ silent: SILENT_LOG
326
+ });
327
+ delimiter();
328
+ const ajv = new Ajv();
329
+ if (ajv.validate(EXPOSE_MOTIFS_SCHEMA, motifsPromptResult)) {
330
+ runLogFun(console.info("Exposé des motifs OK 👌"), {
331
+ silent: SILENT_LOG
332
+ });
333
+ return motifsPromptResult;
334
+ }
335
+ runLogFun(console.warn("Exposé des motifs KO ❌"), {
336
+ silent: SILENT_LOG
337
+ });
338
+ return {};
339
+ }
340
+
341
+ /**
342
+ * Asynchronously extracts the metadata from the given HTML.
343
+ *
344
+ * @param {string} html - The HTML string from which to extract the metadata.
345
+ * @return {Promise<Record<string, any>>} - A Promise that resolves to the extracted metadata object.
346
+ * The object contains the following properties:
347
+ * - `documentRef`: The reference of the document.
348
+ * - `titre`: The title of the document.
349
+ * - `numeroTexte`: The number of the text.
350
+ * - `procedureAcceleree`: The accelerated procedure.
351
+ * @throws {Error} - If the extracted metadata do not validate against the META_DONNEES_SCHEMA.
352
+ */
353
+ async function extractMetaDonnees(html) {
354
+ delimiter();
355
+ let cleanedHtml = cleanHtml(html);
356
+ cleanedHtml = removeHtmlTags(cleanedHtml);
357
+ const structuredModel = MODEL.withStructuredOutput(META_DONNEES_SCHEMA);
358
+ const metaDonneesSystemTemplate = `
359
+ ${SYSTEM_TEMPLATE}
360
+ `;
361
+ const prompt = ChatPromptTemplate.fromMessages([["system", metaDonneesSystemTemplate], ["human", "{input}"]]);
33
362
  const chain = prompt.pipe(structuredModel);
34
363
  const result = await chain.invoke({
35
- input: cleanedHtml
364
+ input: cleanedHtml,
365
+ example1: EXAMPLES.PRJLANR5L16B0914.input,
366
+ example2: EXAMPLES.PRJLANR5L16B2424.input,
367
+ output1: EXAMPLES.PRJLANR5L16B0914.meta,
368
+ output2: EXAMPLES.PRJLANR5L16B2424.meta
36
369
  });
370
+ console.group("Meta-données");
371
+ console.table([["Référence", result.documentRef], ["Titre", result.titre], ["Numéro du texte", result.numeroTexte], ["Procédure accéléré", result.procedureAcceleree]]);
372
+ console.groupEnd();
373
+ delimiter();
37
374
  const ajv = new Ajv();
38
- if (ajv.validate(texteLoiSchema, result)) {
375
+ if (ajv.validate(META_DONNEES_SCHEMA, result)) {
376
+ runLogFun(console.warn("Meta-données OK 👌"), {
377
+ silent: SILENT_LOG
378
+ });
39
379
  return result;
40
380
  }
41
- return false;
381
+ runLogFun(console.warn("Meta-données non-conforme ❌"), {
382
+ silent: SILENT_LOG
383
+ });
384
+ return {};
385
+ }
386
+
387
+ /**
388
+ * Asynchronously extracts the "projet de loi" from the given HTML.
389
+ *
390
+ * @param {string} html - The HTML string from which to extract the "projet de loi".
391
+ * @return {Promise<Record<string, any>>} - A Promise that resolves to the extracted "projet de loi" object.
392
+ * The object contains the following properties:
393
+ * - `articles`: An array of article objects, each containing the following properties:
394
+ * - `numeroArticle`: The number of the article.
395
+ * - `cardinal`: The cardinal of the article.
396
+ * - `titre`: The title of the article.
397
+ * - `debut`: The beginning of the article.
398
+ * - `fin`: The end of the article.
399
+ * - `alineas`: An array of alineas.
400
+ * @throws {Error} - If the extracted "projet de loi" does not validate against the PROJET_LOI_SCHEMA.
401
+ */
402
+ async function extractProjetLoi(html) {
403
+ runLogFun(console.group("Parsing loi..."), {
404
+ silent: SILENT_LOG
405
+ });
406
+ let cleanedHtml = cleanHtml(html);
407
+ const structuredModel = MODEL.withStructuredOutput(PROJET_LOI_SCHEMA);
408
+ const projetLoiSystemTemplate = `
409
+ ${SYSTEM_TEMPLATE}
410
+
411
+ # Examples:
412
+
413
+ ## Exemple 1 User Input :
414
+ """
415
+ {example1}
416
+ """
417
+
418
+ ## Exemple 1 JSON Output :
419
+ """
420
+ {output1}
421
+ """
422
+
423
+ ## Exemple 2 User Input :
424
+ """
425
+ {example2}
426
+ """
427
+
428
+ ## Exemple 2 JSON Output :
429
+ """
430
+ {output2}
431
+ """
432
+ `;
433
+ const prompt = ChatPromptTemplate.fromMessages([["system", projetLoiSystemTemplate], ["human", "{input}"]]);
434
+ const chain = prompt.pipe(structuredModel);
435
+ const articlesPromptResult = await chain.invoke({
436
+ input: cleanedHtml,
437
+ example1: EXAMPLES.PRJLANR5L16B0914.input,
438
+ example2: EXAMPLES.PRJLANR5L16B2424.input,
439
+ output1: EXAMPLES.PRJLANR5L16B0914.loi,
440
+ output2: EXAMPLES.PRJLANR5L16B2424.loi
441
+ });
442
+ runLogFun(console.log("Found ", articlesPromptResult.articles.length, " articles."), {
443
+ silent: SILENT_LOG
444
+ });
445
+ for (const article of articlesPromptResult.articles) {
446
+ article.alineas = await extractAlineas(html, article);
447
+ }
448
+ runLogFun(console.table(articlesPromptResult.articles.map(article => [article.numeroArticle, article.titre, article.debut.substring(0, 10), article.fin.substring(0, 10), `Nombre d'alineas : ${article.alineas.length}`])), {
449
+ silent: SILENT_LOG
450
+ });
451
+ runLogFun(console.groupEnd(), {
452
+ silent: SILENT_LOG
453
+ });
454
+ const ajv = new Ajv();
455
+ if (ajv.validate(PROJET_LOI_SCHEMA, articlesPromptResult)) {
456
+ runLogFun(console.info("Projet de loi OK 👌"), {
457
+ silent: SILENT_LOG
458
+ });
459
+ delimiter();
460
+ return articlesPromptResult;
461
+ }
462
+ runLogFun(console.warn("Projet de loi KO ❌"), {
463
+ silent: SILENT_LOG
464
+ });
465
+ delimiter();
466
+ return {};
467
+ }
468
+ async function extractAlineas(html, article) {
469
+ runLogFun(console.group("Parsing alineas..."), {
470
+ silent: SILENT_LOG
471
+ });
472
+ let cleanedHtml = cleanHtml(html);
473
+ const structuredModel = MODEL.withStructuredOutput(ALINEA_SCHEMA);
474
+ const alineasSystemTemplate = `
475
+ ${SYSTEM_TEMPLATE}
476
+
477
+ Extrais tous les alineas de la portion de texte commençant par « {debut} » et finissant par « {fin} ».
478
+ Un alinéa contiennent toujours une balise « <img ».
479
+
480
+ # Examples:
481
+
482
+ ## Exemple 1 User Input :
483
+ """
484
+ {example1}
485
+ """
486
+
487
+ ## Exemple 1 JSON Output :
488
+ """
489
+ {output1}
490
+ """
491
+ `;
492
+ const prompt = ChatPromptTemplate.fromMessages([["system", alineasSystemTemplate], ["human", "{input}"]]);
493
+ const chain = prompt.pipe(structuredModel);
494
+ const alineasPromptResult = await chain.invoke({
495
+ input: cleanedHtml,
496
+ debut: article.debut,
497
+ fin: article.fin,
498
+ example1: EXAMPLES.PRJLANR5L16B2424.input,
499
+ output1: EXAMPLES.PRJLANR5L16B2424.alineas
500
+ });
501
+ const ajv = new Ajv();
502
+ if (ajv.validate(ALINEA_SCHEMA, alineasPromptResult)) {
503
+ runLogFun(console.info("Found ", alineasPromptResult.alineas.length, " alineas for Article ", article.numeroArticle, article.titre), {
504
+ silent: SILENT_LOG
505
+ });
506
+ runLogFun(console.groupEnd(), {
507
+ silent: SILENT_LOG
508
+ });
509
+ delimiter();
510
+ return alineasPromptResult.alineas;
511
+ }
512
+ runLogFun(console.warn("Alineas KO"), {
513
+ silent: SILENT_LOG
514
+ });
515
+ delimiter();
516
+ return {};
517
+ }
518
+
519
+ /**
520
+ * Asynchronously extracts the "sommaire" (outline) from the given HTML.
521
+ *
522
+ * @param {string} html - The HTML string from which to extract the "sommaire".
523
+ * @return {Promise<Record<string, any>>} - A Promise that resolves to the extracted "sommaire" object.
524
+ * The object contains the following properties:
525
+ * - `sommaire`: An array of main division objects, each containing the following properties:
526
+ * - `numeroDivision`: The number of the main division.
527
+ * - `titre`: The title of the main division.
528
+ * - `typeDivision`: The type of content in the main division.
529
+ * - `sequence`: The sequence of the main division.
530
+ * - `parent`: The parent of the main division.
531
+ * @throws {Error} - If the extracted "sommaire" does not validate against the SOMMAIRE_SCHEMA.
532
+ */
533
+ async function extractSommaire(html) {
534
+ let cleanedHtml = cleanHtml(html);
535
+ cleanedHtml = removeHtmlTags(cleanedHtml);
536
+ const structuredModel = MODEL.withStructuredOutput(SOMMAIRE_SCHEMA);
537
+ const sommaireSystemTemplate = `
538
+ ${SYSTEM_TEMPLATE}
539
+
540
+ # Examples:
541
+
542
+ ## Exemple 1 User Input :
543
+ """
544
+ {example1}
545
+ """
546
+
547
+ ## Exemple 1 JSON Output :
548
+ """
549
+ {output1}
550
+ """
551
+
552
+ ## Exemple 2 User Input :
553
+ """
554
+ {example2}
555
+ """
556
+
557
+ ## Exemple 2 JSON Output :
558
+ """
559
+ {output2}
560
+ """
561
+ `;
562
+ const prompt = ChatPromptTemplate.fromMessages([["system", sommaireSystemTemplate], ["human", "{input}"]]);
563
+ const chain = prompt.pipe(structuredModel);
564
+ const sommairePromptResult = await chain.invoke({
565
+ input: cleanedHtml,
566
+ example1: EXAMPLES.PRJLANR5L16B2014.input,
567
+ output1: EXAMPLES.PRJLANR5L16B2014.sommaire,
568
+ example2: EXAMPLES.PRJLANR5L16B0914.input,
569
+ output2: EXAMPLES.PRJLANR5L16B0914.sommaire
570
+ });
571
+ if (!sommairePromptResult.sommaire) {
572
+ runLogFun(console.warn("Aucun sommaire n'a été trouvé ❓"), {
573
+ silent: SILENT_LOG
574
+ });
575
+ delimiter();
576
+ return {
577
+ sommaire: []
578
+ };
579
+ }
580
+ runLogFun(console.group("Sommaire"), {
581
+ silent: SILENT_LOG
582
+ });
583
+ runLogFun(console.log("Found ", sommairePromptResult.sommaire.length, " main divisions (level 1)."), {
584
+ silent: SILENT_LOG
585
+ });
586
+ runLogFun(console.table(sommairePromptResult.sommaire.map(item => [item.sequence, item.titre, item.typeDivision, item.parent])), {
587
+ silent: SILENT_LOG
588
+ });
589
+ runLogFun(console.groupEnd(), {
590
+ silent: SILENT_LOG
591
+ });
592
+ const ajv = new Ajv();
593
+ if (ajv.validate(SOMMAIRE_SCHEMA, sommairePromptResult)) {
594
+ runLogFun(console.info("Sommaire OK 👌"), {
595
+ silent: SILENT_LOG
596
+ });
597
+ delimiter();
598
+ return sommairePromptResult.sommaire;
599
+ }
600
+ runLogFun(console.warn("La construction du sommaire est KO ❌"), {
601
+ silent: SILENT_LOG
602
+ });
603
+ delimiter();
604
+ return {
605
+ sommaire: []
606
+ };
42
607
  }
43
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDaGF0T3BlbkFJIiwiQ2hhdFByb21wdFRlbXBsYXRlIiwiQWp2IiwidGV4dGVMb2lTY2hlbWEiLCJyZXF1aXJlIiwiY2xlYW5IdG1sIiwiaHRtbCIsImNsZWFuZWRIdG1sIiwicmVwbGFjZSIsInBhcnNlVGV4dGVMb2kiLCJtb2RlbCIsInRlbXBlcmF0dXJlIiwiYXBpS2V5IiwicHJvY2VzcyIsImVudiIsIk9QRU5BSV9BUElfS0VZIiwic3RydWN0dXJlZE1vZGVsIiwid2l0aFN0cnVjdHVyZWRPdXRwdXQiLCJzeXN0ZW1UZW1wbGF0ZSIsInByb21wdCIsImZyb21NZXNzYWdlcyIsImNoYWluIiwicGlwZSIsInJlc3VsdCIsImludm9rZSIsImlucHV0IiwiYWp2IiwidmFsaWRhdGUiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvcGFyc2Vycy90ZXh0ZXNfbG9pcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGF0T3BlbkFJIH0gZnJvbSBcIkBsYW5nY2hhaW4vb3BlbmFpXCJcbmltcG9ydCB7IENoYXRQcm9tcHRUZW1wbGF0ZSB9IGZyb20gXCJAbGFuZ2NoYWluL2NvcmUvcHJvbXB0c1wiXG5pbXBvcnQgQWp2IGZyb20gXCJhanZcIlxuY29uc3QgdGV4dGVMb2lTY2hlbWEgPSByZXF1aXJlKFwiLi4vc2NoZW1hcy90ZXh0ZV9sb2kvVGV4dGVMb2kuanNvblwiKVxuXG5mdW5jdGlvbiBjbGVhbkh0bWwoaHRtbDogc3RyaW5nKSB7XG4gIGxldCBjbGVhbmVkSHRtbCA9IGh0bWwucmVwbGFjZSgvKDxzdHlsZVtcXHdcXFddK3N0eWxlPikvZywgXCJcIilcbiAgY2xlYW5lZEh0bWwgPSBjbGVhbmVkSHRtbC5yZXBsYWNlKC8oPGhlYWRbXFx3XFxXXStoZWFkPikvZywgXCJcIilcbiAgY2xlYW5lZEh0bWwgPSBjbGVhbmVkSHRtbC5yZXBsYWNlKC88aW1nW14+XSo+L2csIFwiXCIpXG5cbiAgcmV0dXJuIGNsZWFuZWRIdG1sXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwYXJzZVRleHRlTG9pKGh0bWw6IHN0cmluZykge1xuICBjb25zdCBjbGVhbmVkSHRtbCA9IGNsZWFuSHRtbChodG1sKVxuXG4gIGNvbnN0IG1vZGVsID0gbmV3IENoYXRPcGVuQUkoe1xuICAgIHRlbXBlcmF0dXJlOiAwLFxuICAgIG1vZGVsOiBcImdwdC00b1wiLFxuICAgIGFwaUtleTogcHJvY2Vzcy5lbnYuT1BFTkFJX0FQSV9LRVksXG4gIH0pXG5cbiAgY29uc3Qgc3RydWN0dXJlZE1vZGVsID0gbW9kZWwud2l0aFN0cnVjdHVyZWRPdXRwdXQodGV4dGVMb2lTY2hlbWEpXG5cbiAgY29uc3Qgc3lzdGVtVGVtcGxhdGUgPSBgXG4gICAgICAgIFR1IGVzIHVuIGV4cGVydCBkZSBsYSBsb2kgZXQgZGUgbCdhbmFseXNlIGRlIHBhZ2VzIEhUTUwuXG4gICAgICAgIFR1IGRvaXMgYW5hbHlzZXIgdW4gdGV4dGUgZGUgbG9pIGFmaW4gZGUgc8OpcGFyZXIgZXQgc3RydWN0dXJlciBsZXMgw6lsw6ltZW50cyBxdWkgbGUgY29tcG9zZW50LiBMZSBmb3JtYXQgZCdlbnRyw6llIGVzdCBIVE1MLlxuXG4gICAgICAgIExlIHRleHRlIGVzdCBkaXZpc8OpIGVuIGRldXggcGFydGllcyA6XG4gICAgICAgIEEpIHVuIGV4cG9zw6kgZGVzIG1vdGlmcyBxdWkgaW5kaXF1ZSBsZXMgcmFpc29ucyBwb3VyIGxlc3F1ZWxsZXMgY2UgcHJvamV0IGVzdCBzb3VtaXMgYXUgUGFybGVtZW50LiBJbCBwZXV0IGNvbnRlbmlyIDMgw6lsw6ltZW50cyA6IDEpIHVuZSBjaXRhdGlvbiBhdSBkw6lidXQgZCd1biBkb2N1bWVudCwgMikgbGUgdGV4dGUgcHJpbmNpcGFsIHF1aSBkw6l2ZWxvcHBlIGxlcyBhcmd1bWVudHMgZGUgbCdhdXRldXIgw6AgbCdhcHB1aSBkZSBsYSBtb2RpZmljYXRpb24gbMOpZ2lzbGF0aXZlIG91IGRlcyBkaXNwb3NpdGlvbnMgbm91dmVsbGVzIHF1J2lsIHByb3Bvc2UsIDMpIGRlcyBwYXJhZ3JhcGhlcyBxdWkgcHLDqXNlbnRlbnQgbGVzIGFydGljbGVzLlxuICAgICAgICBCKSBsZSBkaXNwb3NpdGlmIHF1aSBlc3QgbGEgcGFydGllIG5vcm1hdGl2ZSBldCByw6lkaWfDqWUgZW4gYXJ0aWNsZXMuIElsIHBldXQgY29tcG9ydGVyIGRlcyBkaXZpc2lvbnMgbm9tbcOpZXMgdGl0cmVzLCBjaGFwaXRyZXMsIHNlY3Rpb25zLCBzb3VzLXNlY3Rpb25zLiBMb3JzcXUnaWwgeSBhIHVuIHNldWwgbml2ZWF1IGRlIHN0cnVjdHVyZSwgb24gcmV0cm91dmVyYSBsZSBjaGFwaXRyZSA7IHPigJlpbCB5IGEgZGV1eCBuaXZlYXV4IGRlIHN0cnVjdHVyZSwgb24gcmV0cm91dmVyYSBkZXMgY2hhcGl0cmVzIHB1aXMgZGVzIHNlY3Rpb25zLiBT4oCZaWwgeSBhIHRyb2lzIG5pdmVhdXggZGUgc3RydWN0dXJlLCBvbiByZXRyb3V2ZXJhIGRlcyB0aXRyZXMgcHVpcyBkZXMgY2hhcGl0cmVzIHB1aXMgZGVzIHNlY3Rpb25zLlxuXG4gICAgICAgIFNpIGxlIHRleHRlIGRlIGxvaSBuZSBjb21wb3J0ZSBwYXMgZGUgZGl2aXNpb24sIGxlIHNvbW1haXJlIGRvaXQgcmVzdGVyIHZpZGUuXG4gICAgICAgIFRvdXRlcyBsZXMgbGlnbmVzIHF1aSBkw6lidXRlbnQgcGFyIHVuICfCqycgbmUgc29udCBwYXMgw6AgcHJlbmRyZSBlbiBjb21wdGUgZGFucyBsZXMgZGl2aXNpb25zXG4gICAgICAgIExvcnNxdWUgbGVzIHRleHRlcyBvbnQgw6l0w6kgbW9kaWZpw6lzLCBpbCBuJ3kgcGFzIGQnZXhwb3PDqSBkZXMgbW90aWZzLlxuICAgICAgICBUYSByw6lwb25zZSBkb2l0IMOqdHJlIHVuIEpTT04gc3RydWN0dXLDqSBhdmVjIGxlcyDDqWzDqW1lbnRzIGR1IHRleHRlIGRlIGxvaSBlbiByZXNwZWN0YW50IGxlIHNjaMOpbWEgSlNPTiBmb3VybmkuXG4gICAgYFxuXG4gIGNvbnN0IHByb21wdCA9IENoYXRQcm9tcHRUZW1wbGF0ZS5mcm9tTWVzc2FnZXMoW1xuICAgIFtcInN5c3RlbVwiLCBzeXN0ZW1UZW1wbGF0ZV0sXG4gICAgW1wiaHVtYW5cIiwgXCJ7aW5wdXR9XCJdLFxuICBdKVxuXG4gIGNvbnN0IGNoYWluID0gcHJvbXB0LnBpcGUoc3RydWN0dXJlZE1vZGVsKVxuICBjb25zdCByZXN1bHQgPSBhd2FpdCBjaGFpbi5pbnZva2UoeyBpbnB1dDogY2xlYW5lZEh0bWwgfSlcblxuICBjb25zdCBhanYgPSBuZXcgQWp2KClcbiAgaWYgKGFqdi52YWxpZGF0ZSh0ZXh0ZUxvaVNjaGVtYSwgcmVzdWx0KSkge1xuICAgIHJldHVybiByZXN1bHRcbiAgfVxuICByZXR1cm4gZmFsc2Vcbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsVUFBVSxRQUFRLG1CQUFtQjtBQUM5QyxTQUFTQyxrQkFBa0IsUUFBUSx5QkFBeUI7QUFDNUQsT0FBT0MsR0FBRyxNQUFNLEtBQUs7QUFDckIsTUFBTUMsY0FBYyxHQUFHQyxPQUFPLENBQUMsb0NBQW9DLENBQUM7QUFFcEUsU0FBU0MsU0FBU0EsQ0FBQ0MsSUFBWSxFQUFFO0VBQy9CLElBQUlDLFdBQVcsR0FBR0QsSUFBSSxDQUFDRSxPQUFPLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxDQUFDO0VBQzVERCxXQUFXLEdBQUdBLFdBQVcsQ0FBQ0MsT0FBTyxDQUFDLHNCQUFzQixFQUFFLEVBQUUsQ0FBQztFQUM3REQsV0FBVyxHQUFHQSxXQUFXLENBQUNDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO0VBRXBELE9BQU9ELFdBQVc7QUFDcEI7QUFFQSxPQUFPLGVBQWVFLGFBQWFBLENBQUNILElBQVksRUFBRTtFQUNoRCxNQUFNQyxXQUFXLEdBQUdGLFNBQVMsQ0FBQ0MsSUFBSSxDQUFDO0VBRW5DLE1BQU1JLEtBQUssR0FBRyxJQUFJVixVQUFVLENBQUM7SUFDM0JXLFdBQVcsRUFBRSxDQUFDO0lBQ2RELEtBQUssRUFBRSxRQUFRO0lBQ2ZFLE1BQU0sRUFBRUMsT0FBTyxDQUFDQyxHQUFHLENBQUNDO0VBQ3RCLENBQUMsQ0FBQztFQUVGLE1BQU1DLGVBQWUsR0FBR04sS0FBSyxDQUFDTyxvQkFBb0IsQ0FBQ2QsY0FBYyxDQUFDO0VBRWxFLE1BQU1lLGNBQWMsR0FBRztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztFQUVILE1BQU1DLE1BQU0sR0FBR2xCLGtCQUFrQixDQUFDbUIsWUFBWSxDQUFDLENBQzdDLENBQUMsUUFBUSxFQUFFRixjQUFjLENBQUMsRUFDMUIsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQ3JCLENBQUM7RUFFRixNQUFNRyxLQUFLLEdBQUdGLE1BQU0sQ0FBQ0csSUFBSSxDQUFDTixlQUFlLENBQUM7RUFDMUMsTUFBTU8sTUFBTSxHQUFHLE1BQU1GLEtBQUssQ0FBQ0csTUFBTSxDQUFDO0lBQUVDLEtBQUssRUFBRWxCO0VBQVksQ0FBQyxDQUFDO0VBRXpELE1BQU1tQixHQUFHLEdBQUcsSUFBSXhCLEdBQUcsQ0FBQyxDQUFDO0VBQ3JCLElBQUl3QixHQUFHLENBQUNDLFFBQVEsQ0FBQ3hCLGNBQWMsRUFBRW9CLE1BQU0sQ0FBQyxFQUFFO0lBQ3hDLE9BQU9BLE1BQU07RUFDZjtFQUNBLE9BQU8sS0FBSztBQUNkIiwiaWdub3JlTGlzdCI6W119
608
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDaGF0T3BlbkFJIiwiQ2hhdFByb21wdFRlbXBsYXRlIiwiQWp2IiwiZGVsaW1pdGVyIiwicnVuTG9nRnVuIiwiRVhQT1NFX01PVElGU19TQ0hFTUEiLCJyZXF1aXJlIiwiTUVUQV9ET05ORUVTX1NDSEVNQSIsIlBST0pFVF9MT0lfU0NIRU1BIiwiQUxJTkVBX1NDSEVNQSIsIlNPTU1BSVJFX1NDSEVNQSIsIkVYQU1QTEVTIiwiUFJKTEFOUjVMMTZCMDkxNCIsIm1vdGlmcyIsImlucHV0IiwibG9pIiwibWV0YSIsInNvbW1haXJlIiwiUFJKTEFOUjVMMTZCMjAxNCIsIlBSSkxBTlI1TDE2QjI0MjQiLCJhbGluZWFzIiwiRlVMTF9URVhURV9TQ0hFTUEiLCIkc2NoZW1hIiwidGl0bGUiLCJkZXNjcmlwdGlvbiIsInR5cGUiLCJwcm9wZXJ0aWVzIiwidGV4dGUiLCJyZXF1aXJlZCIsIk1PREVMIiwicHJvY2VzcyIsImVudiIsIk9QRU5BSV9BUElfS0VZIiwidGVtcGVyYXR1cmUiLCJ0b3BQIiwibW9kZWwiLCJhcGlLZXkiLCJtYXhUb2tlbnMiLCJTWVNURU1fVEVNUExBVEUiLCJTSUxFTlRfTE9HIiwicGFyc2VUZXh0ZUxvaSIsImh0bWwiLCJvcHRpb25zIiwic2lsZW50IiwiY29uc29sZSIsImluZm8iLCJleHRyYWN0TWV0YURvbm5lZXMiLCJleHRyYWN0U29tbWFpcmUiLCJwYXJ0aWFsTW90aWZzIiwiZXh0cmFjdE1vdGlmcyIsInBhcnRpYWxMb2kiLCJleHRyYWN0UHJvamV0TG9pIiwiZXhwb3NlTW90aWZzIiwicG9wdWxhdGVNb3RpZnMiLCJwb3B1bGF0ZVByb2pldExvaSIsImNsZWFuSHRtbCIsImNsZWFuZWRIdG1sIiwicmVwbGFjZSIsInJlbW92ZUh0bWxUYWdzIiwiaHRtbFRhZ1JlZ2V4IiwidGV4dFdpdGhvdXRUYWdzIiwiZGVidXQiLCJmaW4iLCJzeXN0ZW1UZW1wbGF0ZSIsInByb21wdCIsImZyb21NZXNzYWdlcyIsInN0cnVjdHVyZWRNb2RlbCIsIndpdGhTdHJ1Y3R1cmVkT3V0cHV0IiwiY2hhaW4iLCJwaXBlIiwiYXJ0aWNsZVByb21wdFJlc3VsdCIsImludm9rZSIsInBhcnRpYWwiLCJncm91cCIsImFydGljbGVzIiwiZnVsbEFydGljbGVzIiwiYXJ0aWNsZSIsImFsaW5lYSIsImFsaW5lYVByb21wdFJlc3VsdCIsInB1c2giLCJwcm9qZXRMb2kiLCJncm91cEVuZCIsIm1vdGlmc1N5c3RlbVRlbXBsYXRlIiwibW90aWZzUHJvbXB0UmVzdWx0IiwiZXhhbXBsZTEiLCJleGFtcGxlMiIsIm91dHB1dDEiLCJvdXRwdXQyIiwidGFibGUiLCJzdWJzdHJpbmciLCJhanYiLCJ2YWxpZGF0ZSIsIndhcm4iLCJtZXRhRG9ubmVlc1N5c3RlbVRlbXBsYXRlIiwicmVzdWx0IiwiZG9jdW1lbnRSZWYiLCJ0aXRyZSIsIm51bWVyb1RleHRlIiwicHJvY2VkdXJlQWNjZWxlcmVlIiwicHJvamV0TG9pU3lzdGVtVGVtcGxhdGUiLCJhcnRpY2xlc1Byb21wdFJlc3VsdCIsImxvZyIsImxlbmd0aCIsImV4dHJhY3RBbGluZWFzIiwibWFwIiwibnVtZXJvQXJ0aWNsZSIsImFsaW5lYXNTeXN0ZW1UZW1wbGF0ZSIsImFsaW5lYXNQcm9tcHRSZXN1bHQiLCJzb21tYWlyZVN5c3RlbVRlbXBsYXRlIiwic29tbWFpcmVQcm9tcHRSZXN1bHQiLCJpdGVtIiwic2VxdWVuY2UiLCJ0eXBlRGl2aXNpb24iLCJwYXJlbnQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvcGFyc2Vycy90ZXh0ZXNfbG9pcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGF0T3BlbkFJIH0gZnJvbSBcIkBsYW5nY2hhaW4vb3BlbmFpXCJcbmltcG9ydCB7IENoYXRQcm9tcHRUZW1wbGF0ZSB9IGZyb20gXCJAbGFuZ2NoYWluL2NvcmUvcHJvbXB0c1wiXG5pbXBvcnQgQWp2IGZyb20gXCJhanZcIlxuXG5pbXBvcnQgeyBkZWxpbWl0ZXIsIHJ1bkxvZ0Z1biB9IGZyb20gXCIuLi9sb2dnZXJcIlxuXG5jb25zdCBFWFBPU0VfTU9USUZTX1NDSEVNQSA9IHJlcXVpcmUoXCIuLi9zY2hlbWFzL3RleHRlX2xvaS9FeHBvc2VNb3RpZnNcIilcbmNvbnN0IE1FVEFfRE9OTkVFU19TQ0hFTUEgPSByZXF1aXJlKFwiLi4vc2NoZW1hcy90ZXh0ZV9sb2kvTWV0YURvbm5lZXNcIilcbmNvbnN0IFBST0pFVF9MT0lfU0NIRU1BID0gcmVxdWlyZShcIi4uL3NjaGVtYXMvdGV4dGVfbG9pL1Byb2pldExvaVwiKVxuY29uc3QgQUxJTkVBX1NDSEVNQSA9IHJlcXVpcmUoXCIuLi9zY2hlbWFzL3RleHRlX2xvaS9BbGluZWFcIilcbmNvbnN0IFNPTU1BSVJFX1NDSEVNQSA9IHJlcXVpcmUoXCIuLi9zY2hlbWFzL3RleHRlX2xvaS9Tb21tYWlyZVwiKVxuXG4vKipcbiAqIE9iamVjdCBjb250YWluaW5nIGlucHV0IGV4YW1wbGVzIGFuZCB0aGVpciBvdXRwdXQgc2NoZW1hcy5cbiAqIFVzZWQgdG8gdHJhaW4gdGhlIExMTS5cbiAqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCB7bW90aWZzOiBhbnksIGlucHV0OiBhbnksIGxvaTogYW55LCBtZXRhOiBhbnksIHNvbW1haXJlOiBhbnl9Pn1cbiAqL1xuY29uc3QgRVhBTVBMRVMgPSB7XG4gIFBSSkxBTlI1TDE2QjA5MTQ6IHtcbiAgICBtb3RpZnM6IHJlcXVpcmUoXCIuLi9leGFtcGxlcy9QUkpMQU5SNUwxNkIwOTE0L21vdGlmc1wiKSxcbiAgICBpbnB1dDogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjA5MTQvaW5wdXRcIiksXG4gICAgbG9pOiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMDkxNC9sb2lcIiksXG4gICAgbWV0YTogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjA5MTQvbWV0YVwiKSxcbiAgICBzb21tYWlyZTogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjA5MTQvc29tbWFpcmVcIiksXG4gIH0sXG4gIFBSSkxBTlI1TDE2QjIwMTQ6IHtcbiAgICBtb3RpZnM6IHJlcXVpcmUoXCIuLi9leGFtcGxlcy9QUkpMQU5SNUwxNkIyMDE0L21vdGlmc1wiKSxcbiAgICBpbnB1dDogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjIwMTQvaW5wdXRcIiksXG4gICAgbG9pOiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMjAxNC9sb2lcIiksXG4gICAgbWV0YTogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjIwMTQvbWV0YVwiKSxcbiAgICBzb21tYWlyZTogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjIwMTQvc29tbWFpcmVcIiksXG4gIH0sXG4gIFBSSkxBTlI1TDE2QjI0MjQ6IHtcbiAgICBhbGluZWFzOiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMjQyNC9hbGluZWFzXCIpLFxuICAgIG1vdGlmczogcmVxdWlyZShcIi4uL2V4YW1wbGVzL1BSSkxBTlI1TDE2QjI0MjQvbW90aWZzXCIpLFxuICAgIGlucHV0OiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMjQyNC9pbnB1dFwiKSxcbiAgICBsb2k6IHJlcXVpcmUoXCIuLi9leGFtcGxlcy9QUkpMQU5SNUwxNkIyNDI0L2xvaVwiKSxcbiAgICBtZXRhOiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMjQyNC9tZXRhXCIpLFxuICAgIHNvbW1haXJlOiByZXF1aXJlKFwiLi4vZXhhbXBsZXMvUFJKTEFOUjVMMTZCMjQyNC9zb21tYWlyZVwiKSxcbiAgfSxcbn1cblxuY29uc3QgRlVMTF9URVhURV9TQ0hFTUEgPSB7XG4gICRzY2hlbWE6IFwiaHR0cDovL2pzb24tc2NoZW1hLm9yZy9kcmFmdC0wNy9zY2hlbWEjXCIsXG4gIHRpdGxlOiBcIlNvbW1haXJlXCIsXG4gIGRlc2NyaXB0aW9uOiBcIlLDqWN1cMOpcmF0aW9uIGQndW4gdGV4dGUgY29tcGxldFwiLFxuICB0eXBlOiBcIm9iamVjdFwiLFxuICBwcm9wZXJ0aWVzOiB7XG4gICAgdGV4dGU6IHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlRleHRlIGNvbXBsZXQgZGUgbGEgc2VjdGlvbiBpbmRpcXXDqWUuXCIsXG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgIH0sXG4gIH0sXG4gIHJlcXVpcmVkOiBbXCJ0ZXh0ZVwiXSxcbn1cblxuLyoqXG4gKiBMTE0gbW9kZWwuXG4gKi9cbmxldCBNT0RFTDogYW55ID0gbnVsbFxuXG5pZiAocHJvY2Vzcy5lbnYuT1BFTkFJX0FQSV9LRVkpIHtcbiAgTU9ERUwgPSBuZXcgQ2hhdE9wZW5BSSh7XG4gICAgdGVtcGVyYXR1cmU6IDAsXG4gICAgdG9wUDogMC4wLFxuICAgIG1vZGVsOiBcImdwdC00by1taW5pXCIsXG4gICAgYXBpS2V5OiBwcm9jZXNzLmVudi5PUEVOQUlfQVBJX0tFWSxcbiAgICBtYXhUb2tlbnM6IC0xLFxuICB9KVxufVxuXG4vKipcbiAqIFN5c3RlbSBpbnB1dCB0ZW1wbGF0ZSBmb3IgdGhlIExMTS5cbiAqL1xuY29uc3QgU1lTVEVNX1RFTVBMQVRFOiBzdHJpbmcgPSBgXG4gICMgSW5zdHJ1Y3Rpb25zIDpcbiAgXG4gIFR1IGVzIHVuIGV4cGVydCBkZSBsYSBsb2kgZXQgZGUgbCdhbmFseXNlIGRlIHBhZ2VzIEhUTUwuXG4gIFR1IGRvaXMgYW5hbHlzZXIgdW4gdGV4dGUgZGUgbG9pIGFmaW4gZGUgc8OpcGFyZXIgZXQgZGUgc3RydWN0dXJlciBsZXMgw6lsw6ltZW50cyBxdWkgbGUgY29tcG9zZW50LiBMZSBmb3JtYXQgZCdlbnRyw6llIGVzdCBIVE1MLlxuXG4gIExlIHRleHRlIGVzdCBkaXZpc8OpIGVuIGRldXggcGFydGllcyA6XG4gIEEpIHVuIGV4cG9zw6kgZGVzIG1vdGlmcyBxdWkgaW5kaXF1ZSBsZXMgcmFpc29ucyBwb3VyIGxlc3F1ZWxsZXMgY2UgcHJvamV0IGVzdCBzb3VtaXMgYXUgUGFybGVtZW50LiBJbCBwZXV0IGNvbnRlbmlyIDMgw6lsw6ltZW50cyA6IDEpIHVuZSBjaXRhdGlvbiBhdSBkw6lidXQgZCd1biBkb2N1bWVudCwgMikgbGUgdGV4dGUgcHJpbmNpcGFsIHF1aSBkw6l2ZWxvcHBlIGxlcyBhcmd1bWVudHMgZGUgbCdhdXRldXIgw6AgbCdhcHB1aSBkZSBsYSBtb2RpZmljYXRpb24gbMOpZ2lzbGF0aXZlIG91IGRlcyBkaXNwb3NpdGlvbnMgbm91dmVsbGVzIHF1J2lsIHByb3Bvc2UsIDMpIGRlcyBwYXJhZ3JhcGhlcyBxdWkgcHLDqXNlbnRlbnQgbGVzIGFydGljbGVzLlxuICBCKSBsZSBkaXNwb3NpdGlmIHF1aSBlc3QgbGEgcGFydGllIG5vcm1hdGl2ZSBldCByw6lkaWfDqWUgZW4gYXJ0aWNsZXMuIElsIHBldXQgY29tcG9ydGVyIGRlcyBkaXZpc2lvbnMgbm9tbcOpZXMgdGl0cmVzLCBjaGFwaXRyZXMsIHNlY3Rpb25zLCBzb3VzLXNlY3Rpb25zLiBMb3JzcXUnaWwgeSBhIHVuIHNldWwgbml2ZWF1IGRlIHN0cnVjdHVyZSwgb24gcmV0cm91dmVyYSBsZSBjaGFwaXRyZSA7IHPigJlpbCB5IGEgZGV1eCBuaXZlYXV4IGRlIHN0cnVjdHVyZSwgb24gcmV0cm91dmVyYSBkZXMgY2hhcGl0cmVzIHB1aXMgZGVzIHNlY3Rpb25zLiBT4oCZaWwgeSBhIHRyb2lzIG5pdmVhdXggZGUgc3RydWN0dXJlLCBvbiByZXRyb3V2ZXJhIGRlcyB0aXRyZXMgcHVpcyBkZXMgY2hhcGl0cmVzIHB1aXMgZGVzIHNlY3Rpb25zLlxuXG4gIFNpIGxlIHRleHRlIGRlIGxvaSBuZSBjb21wb3J0ZSBwYXMgZGUgZGl2aXNpb24sIGxlIHNvbW1haXJlIGRvaXQgcmVzdGVyIHZpZGUuXG4gIFRvdXRlcyBsZXMgbGlnbmVzIHF1aSBkw6lidXRlbnQgcGFyIHVuICfCqycgbmUgc29udCBwYXMgw6AgcHJlbmRyZSBlbiBjb21wdGUgZGFucyBsZXMgZGl2aXNpb25zXG4gIFRhIHLDqXBvbnNlIGRvaXQgw6p0cmUgdW4gSlNPTiBzdHJ1Y3R1csOpIGF2ZWMgbGVzIMOpbMOpbWVudHMgZHUgdGV4dGUgZGUgbG9pIGVuIHJlc3BlY3RhbnQgbGUgc2Now6ltYSBKU09OIGZvdXJuaS5cbmBcblxubGV0IFNJTEVOVF9MT0cgPSBmYWxzZVxuXG4vKipcbiAqIFBhcnNlcyB0aGUgZ2l2ZW4gSFRNTCBzdHJpbmcgYW5kIHJldHVybnMgdGhlIHBhcnNlZCB0ZXh0ZXMgbG9pLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIC0gVGhlIEhUTUwgc3RyaW5nIHRvIHBhcnNlLlxuICogQHJldHVybiB7UHJvbWlzZTx7cGFydGlhbDoge3NvbW1haXJlOiBhbnksIGxvaTogYW55LCBtb3RpZnM6IGFueSwgbWV0YTogYW55fSwgY29tcGxldGVkOiB7c29tbWFpcmU6IGFueSwgbG9pOiBhbnksIG1vdGlmczogYW55LCBtZXRhOiBhbnl9fT59IC0gVGhlIHBhcnNlZCB0ZXh0ZXMgbG9pLCBpbmNsdWRpbmcgdGhlIHBhcnRpYWwgYW5kIGNvbXBsZXRlZCB2ZXJzaW9ucy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBhcnNlVGV4dGVMb2koaHRtbDogc3RyaW5nLCBvcHRpb25zID0geyBzaWxlbnQ6IGZhbHNlIH0pIHtcbiAgU0lMRU5UX0xPRyA9IG9wdGlvbnMuc2lsZW50XG5cbiAgcnVuTG9nRnVuKGNvbnNvbGUuaW5mbyhcIlN0YXJ0IGV4dHJhY3RpbmcgbG9pLi4uXCIpLCBvcHRpb25zKVxuICBjb25zdCBtZXRhID0gYXdhaXQgZXh0cmFjdE1ldGFEb25uZWVzKGh0bWwpXG4gIGNvbnN0IHNvbW1haXJlID0gYXdhaXQgZXh0cmFjdFNvbW1haXJlKGh0bWwpXG4gIGNvbnN0IHBhcnRpYWxNb3RpZnM6IGFueSA9IGF3YWl0IGV4dHJhY3RNb3RpZnMoaHRtbClcbiAgY29uc3QgcGFydGlhbExvaTogYW55ID0gYXdhaXQgZXh0cmFjdFByb2pldExvaShodG1sKVxuICBjb25zdCBleHBvc2VNb3RpZnMgPSBhd2FpdCBwb3B1bGF0ZU1vdGlmcyhwYXJ0aWFsTW90aWZzLCBodG1sKVxuICBjb25zdCBsb2kgPSBhd2FpdCBwb3B1bGF0ZVByb2pldExvaShwYXJ0aWFsTG9pLCBodG1sKVxuXG4gIHJldHVybiB7XG4gICAgc29tbWFpcmUsXG4gICAgbG9pLFxuICAgIGV4cG9zZU1vdGlmcyxcbiAgICBtZXRhLFxuICB9XG59XG5cbi8qKlxuICogQ2xlYW5zIHRoZSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyB1bm5lY2Vzc2FyeSB0YWdzIGFuZCBjb250ZW50LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIC0gVGhlIEhUTUwgc3RyaW5nIHRvIGJlIGNsZWFuZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBjbGVhbmVkIEhUTUwgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBjbGVhbkh0bWwoaHRtbDogc3RyaW5nKSB7XG4gIGxldCBjbGVhbmVkSHRtbCA9IGh0bWwucmVwbGFjZSgvKDxzdHlsZVtcXHdcXFddK3N0eWxlPikvZywgXCJcIilcbiAgY2xlYW5lZEh0bWwgPSBjbGVhbmVkSHRtbC5yZXBsYWNlKC8oPGhlYWRbXFx3XFxXXStoZWFkPikvZywgXCJcIilcbiAgY2xlYW5lZEh0bWwgPSBjbGVhbmVkSHRtbC5yZXBsYWNlKC88aW1nW14+XSo+L2csIFwiXCIpXG5cbiAgcmV0dXJuIGNsZWFuZWRIdG1sXG59XG5cbi8qKlxuICogUmVtb3ZlcyBhbGwgSFRNTCB0YWdzIGZyb20gdGhlIGdpdmVuIEhUTUwgc3RyaW5nIGFuZCByZXR1cm5zIHRoZSBjbGVhbmVkIHRleHQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGh0bWwgLSBUaGUgSFRNTCBzdHJpbmcgZnJvbSB3aGljaCB0byByZW1vdmUgdGFncy5cbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGNsZWFuZWQgdGV4dCB3aXRob3V0IGFueSBIVE1MIHRhZ3MuXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUh0bWxUYWdzKGh0bWw6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbiB0byBtYXRjaCBIVE1MIHRhZ3NcbiAgY29uc3QgaHRtbFRhZ1JlZ2V4ID0gLzxbXj5dKj4vZ1xuXG4gIC8vIFJlcGxhY2UgYWxsIEhUTUwgdGFncyB3aXRoIGFuIGVtcHR5IHN0cmluZ1xuICBjb25zdCB0ZXh0V2l0aG91dFRhZ3MgPSBodG1sLnJlcGxhY2UoaHRtbFRhZ1JlZ2V4LCBcIlwiKVxuICByZXR1cm4gdGV4dFdpdGhvdXRUYWdzXG59XG5cbi8qKlxuICogUG9wdWxhdGVzIHRoZSBtb3RpZnMgb2JqZWN0IHdpdGggdGhlIGV4dHJhY3RlZCB0ZXh0IGZyb20gdGhlIGdpdmVuIEhUTUwuXG4gKlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBtb3RpZnMgLSBUaGUgbW90aWZzIG9iamVjdCB0byBiZSBwb3B1bGF0ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gaHRtbCAtIFRoZSBIVE1MIHN0cmluZyBmcm9tIHdoaWNoIHRvIGV4dHJhY3QgdGhlIHRleHQuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSAtIFRoZSBwb3B1bGF0ZWQgbW90aWZzIG9iamVjdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcG9wdWxhdGVNb3RpZnMobW90aWZzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBodG1sOiBzdHJpbmcpIHtcbiAgcnVuTG9nRnVuKGNvbnNvbGUuaW5mbyhcIlBvcHVsYXRpbmcgZXhwb3NlIG1vdGlmcy4uLlwiKSlcbiAgbGV0IGNsZWFuZWRIdG1sID0gY2xlYW5IdG1sKGh0bWwpXG5cbiAgaWYgKG1vdGlmcy5kZWJ1dCA9PT0gbW90aWZzLmZpbiB8fCAhbW90aWZzLmZpbikge1xuICAgIG1vdGlmcy50ZXh0ZSA9IG1vdGlmcy5kZWJ1dFxuICB9IGVsc2Uge1xuICAgIGNvbnN0IHN5c3RlbVRlbXBsYXRlID0gYFxuICAgICAgIyBJbnN0cnVjdGlvbnMgOlxuXG4gICAgICBUdSBlcyB1biBleHBlcnQgZGUgbGEgbG9pIGV0IGRlIGwnYW5hbHlzZSBkZSBwYWdlcyBIVE1MLlxuICAgICAgVHUgZG9pcyBhbmFseXNlciB1biB0ZXh0ZSBkZSBsb2kgYWZpbiBkJ2VuIGV4dHJhaXJlIGNlcnRhaW5lcyBwYXJ0aWVzLiBcbiAgICAgIExlIGZvcm1hdCBkJ2VudHLDqWUgZXN0IGR1IEhUTUwuIExlIGZvcm1hdCBkZSBzb3J0aWUgZXN0IGR1IHRleHRlLlxuICAgICAgUsOpY3Vww6hyZSBsJ2ludMOpZ3JhbGl0w6kgZHUgdGV4dGUgY29tbWVuw6dhbnQgcGFyIDpcblxuICAgICAgXCJcIlwiXG4gICAgICB7ZGVidXR9XG4gICAgICBcIlwiXCJcblxuICAgICAgRXQgZmluaXNzYW50IHBhciA6XG5cbiAgICAgIFwiXCJcIlxuICAgICAge2Zpbn1cbiAgICAgIFwiXCJcIlxuICAgIGBcblxuICAgIGNvbnN0IHByb21wdCA9IENoYXRQcm9tcHRUZW1wbGF0ZS5mcm9tTWVzc2FnZXMoW1xuICAgICAgW1wic3lzdGVtXCIsIHN5c3RlbVRlbXBsYXRlXSxcbiAgICAgIFtcImh1bWFuXCIsIFwie2lucHV0fVwiXSxcbiAgICBdKVxuXG4gICAgY29uc3Qgc3RydWN0dXJlZE1vZGVsID0gTU9ERUwud2l0aFN0cnVjdHVyZWRPdXRwdXQoRlVMTF9URVhURV9TQ0hFTUEpXG4gICAgY29uc3QgY2hhaW4gPSBwcm9tcHQucGlwZShzdHJ1Y3R1cmVkTW9kZWwpXG5cbiAgICBjb25zdCBhcnRpY2xlUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgICAgaW5wdXQ6IGNsZWFuZWRIdG1sLFxuICAgICAgZGVidXQ6IG1vdGlmcy5kZWJ1dCxcbiAgICAgIGZpbjogbW90aWZzLmZpbixcbiAgICB9KVxuXG4gICAgbW90aWZzLnRleHRlID0gYXJ0aWNsZVByb21wdFJlc3VsdC50ZXh0ZVxuICB9XG5cbiAgcnVuTG9nRnVuKFxuICAgIGNvbnNvbGUuaW5mbyhcIk9ww6lyYXRpb24gZGUgcGV1cGxlbWVudCBkZSBsJ2V4cG9zw6kgZGVzIG1vdGlmcyB0ZXJtaW7DqWUg4pyFXCIpLFxuICAgIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0sXG4gIClcbiAgZGVsaW1pdGVyKFNJTEVOVF9MT0cpXG5cbiAgZGVsZXRlIG1vdGlmcy5kZWJ1dFxuICBkZWxldGUgbW90aWZzLmZpblxuICByZXR1cm4gbW90aWZzXG59XG5cbi8qKlxuICogQXN5bmNocm9ub3VzbHkgcG9wdWxhdGVzIGEgcHJvamV0IGxvaSBvYmplY3Qgd2l0aCB0aGUgZnVsbCB0ZXh0IG9mIGVhY2ggYXJ0aWNsZSBhbmQgYWxpbmVhIGluIHRoZSBnaXZlbiBIVE1MLlxuICpcbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gcGFydGlhbCAtIFRoZSBwYXJ0aWFsIHByb2pldCBsb2kgb2JqZWN0IHRvIGJlIHBvcHVsYXRlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIC0gVGhlIEhUTUwgY29udGFpbmluZyB0aGUgdGV4dCBvZiB0aGUgYXJ0aWNsZXMgYW5kIGFsaW5lYXMuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZnVsbHkgcG9wdWxhdGVkIHByb2pldCBsb2kgb2JqZWN0LlxuICovXG5hc3luYyBmdW5jdGlvbiBwb3B1bGF0ZVByb2pldExvaShwYXJ0aWFsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBodG1sOiBzdHJpbmcpIHtcbiAgcnVuTG9nRnVuKGNvbnNvbGUuZ3JvdXAoXCJQZXVwbGVtZW50IGR1IHByb2pldCBsb2kuLi5cIiksIHtcbiAgICBzaWxlbnQ6IFNJTEVOVF9MT0csXG4gIH0pXG4gIGxldCBjbGVhbmVkSHRtbCA9IGNsZWFuSHRtbChodG1sKVxuXG4gIGNvbnN0IGFydGljbGVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10gPSBwYXJ0aWFsLmFydGljbGVzXG4gIGNvbnN0IGZ1bGxBcnRpY2xlczogUmVjb3JkPHN0cmluZywgYW55PltdID0gW11cblxuICBjb25zdCBzeXN0ZW1UZW1wbGF0ZSA9IGBcbiAgICAjIEluc3RydWN0aW9ucyA6XG5cbiAgICBUdSBlcyB1biBleHBlcnQgZGUgbGEgbG9pIGV0IGRlIGwnYW5hbHlzZSBkZSBwYWdlcyBIVE1MLlxuICAgIFR1IGRvaXMgYW5hbHlzZXIgdW4gdGV4dGUgZGUgbG9pIGFmaW4gZCdlbiBleHRyYWlyZSBjZXJ0YWluZXMgcGFydGllcy4gXG4gICAgTGUgZm9ybWF0IGQnZW50csOpZSBlc3QgZHUgSFRNTC4gTGUgZm9ybWF0IGRlIHNvcnRpZSBlc3QgZHUgdGV4dGUuXG4gICAgUsOpY3Vww6hyZSBsJ2ludMOpZ3JhbGl0w6kgZHUgdGV4dGUgY29tbWVuw6dhbnQgcGFyIDpcblxuICAgIFwiXCJcIlxuICAgIHtkZWJ1dH1cbiAgICBcIlwiXCJcblxuICAgIEV0IGZpbmlzc2FudCBwYXIgOlxuXG4gICAgXCJcIlwiXG4gICAge2Zpbn1cbiAgICBcIlwiXCJcbiAgYFxuXG4gIGNvbnN0IHByb21wdCA9IENoYXRQcm9tcHRUZW1wbGF0ZS5mcm9tTWVzc2FnZXMoW1xuICAgIFtcInN5c3RlbVwiLCBzeXN0ZW1UZW1wbGF0ZV0sXG4gICAgW1wiaHVtYW5cIiwgXCJ7aW5wdXR9XCJdLFxuICBdKVxuXG4gIGNvbnN0IHN0cnVjdHVyZWRNb2RlbCA9IE1PREVMLndpdGhTdHJ1Y3R1cmVkT3V0cHV0KEZVTExfVEVYVEVfU0NIRU1BKVxuICBjb25zdCBjaGFpbiA9IHByb21wdC5waXBlKHN0cnVjdHVyZWRNb2RlbClcblxuICBmb3IgKGNvbnN0IGFydGljbGUgb2YgYXJ0aWNsZXMpIHtcbiAgICBpZiAoYXJ0aWNsZS5kZWJ1dCA9PT0gYXJ0aWNsZS5maW4gfHwgIWFydGljbGUuZmluKSB7XG4gICAgICBhcnRpY2xlLnRleHRlID0gYXJ0aWNsZS5kZWJ1dFxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBhcnRpY2xlUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgICAgICBpbnB1dDogY2xlYW5lZEh0bWwsXG4gICAgICAgIGRlYnV0OiBhcnRpY2xlLmRlYnV0LFxuICAgICAgICBmaW46IGFydGljbGUuZmluLFxuICAgICAgfSlcblxuICAgICAgYXJ0aWNsZS50ZXh0ZSA9IGFydGljbGVQcm9tcHRSZXN1bHQudGV4dGVcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGFsaW5lYSBvZiBhcnRpY2xlLmFsaW5lYXMpIHtcbiAgICAgIGlmIChhbGluZWEuZGVidXQgPT09IGFsaW5lYS5maW4gfHwgIWFsaW5lYS5maW4pIHtcbiAgICAgICAgYWxpbmVhLnRleHRlID0gYWxpbmVhLmRlYnV0XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFsaW5lYVByb21wdFJlc3VsdDogYW55ID0gYXdhaXQgY2hhaW4uaW52b2tlKHtcbiAgICAgICAgaW5wdXQ6IGFydGljbGUudGV4dGUsXG4gICAgICAgIGRlYnV0OiBhbGluZWEuZGVidXQsXG4gICAgICAgIGZpbjogYWxpbmVhLmZpbixcbiAgICAgIH0pXG5cbiAgICAgIGRlbGV0ZSBhbGluZWEuZGVidXRcbiAgICAgIGRlbGV0ZSBhbGluZWEuZmluXG4gICAgICBhbGluZWEudGV4dGUgPSBhbGluZWFQcm9tcHRSZXN1bHQudGV4dGVcbiAgICB9XG5cbiAgICBydW5Mb2dGdW4oXG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIFwiT3DDqXJhdGlvbiBkZSBwZXVwbGVtZW50IGR1IGNvbnRlbnUgZHUgcHJvamV0IGRlIGxvaSB0ZXJtaW7DqWUg4pyFXCIsXG4gICAgICApLFxuICAgICAgeyBzaWxlbnQ6IFNJTEVOVF9MT0cgfSxcbiAgICApXG4gICAgZGVsZXRlIGFydGljbGUuZGVidXRcbiAgICBkZWxldGUgYXJ0aWNsZS5maW5cbiAgICBmdWxsQXJ0aWNsZXMucHVzaChhcnRpY2xlKVxuICB9XG5cbiAgY29uc3QgcHJvamV0TG9pID0ge1xuICAgIC4uLnBhcnRpYWwsXG4gICAgYXJ0aWNsZXM6IGZ1bGxBcnRpY2xlcyxcbiAgfVxuXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwRW5kKCksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gIGRlbGltaXRlcigpXG4gIHJldHVybiBwcm9qZXRMb2lcbn1cblxuLyoqXG4gKiBBc3luY2hyb25vdXNseSBleHRyYWN0cyB0aGUgXCJleHBvc2UgbW90aWZzXCIgZnJvbSB0aGUgZ2l2ZW4gSFRNTC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaHRtbCAtIFRoZSBIVE1MIHN0cmluZyBmcm9tIHdoaWNoIHRvIGV4dHJhY3QgdGhlIFwiZXhwb3NlIG1vdGlmc1wiLlxuICogQHJldHVybiB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gLSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXh0cmFjdGVkIFwiZXhwb3NlIG1vdGlmc1wiIG9iamVjdC5cbiAqIFRoZSBvYmplY3QgY29udGFpbnMgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICogLSBgZGVidXRgOiBUaGUgYmVnaW5uaW5nIG9mIHRoZSBcImV4cG9zZSBtb3RpZnNcIi5cbiAqIC0gYGZpbmA6IFRoZSBlbmQgb2YgdGhlIFwiZXhwb3NlIG1vdGlmc1wiLlxuICogQHRocm93cyB7RXJyb3J9IC0gSWYgdGhlIGV4dHJhY3RlZCBcImV4cG9zZSBtb3RpZnNcIiBkbyBub3QgdmFsaWRhdGUgYWdhaW5zdCB0aGUgRVhQT1NFX01PVElGU19TQ0hFTUEuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RNb3RpZnMoaHRtbDogc3RyaW5nKSB7XG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwKFwiUGFyc2luZyBleHBvc2UgbW90aWZzLi4uXCIpLCB7IHNpbGVudDogU0lMRU5UX0xPRyB9KVxuICBsZXQgY2xlYW5lZEh0bWwgPSBjbGVhbkh0bWwoaHRtbClcbiAgY2xlYW5lZEh0bWwgPSByZW1vdmVIdG1sVGFncyhjbGVhbmVkSHRtbClcblxuICBjb25zdCBzdHJ1Y3R1cmVkTW9kZWwgPSBNT0RFTC53aXRoU3RydWN0dXJlZE91dHB1dChFWFBPU0VfTU9USUZTX1NDSEVNQSlcblxuICBjb25zdCBtb3RpZnNTeXN0ZW1UZW1wbGF0ZSA9IGBcbiAgICAke1NZU1RFTV9URU1QTEFURX1cblxuICAgICMgRXhhbXBsZXM6IFxuXG4gICAgIyMgRXhlbXBsZSAxIFVzZXIgSW5wdXQgOlxuICAgIFwiXCJcIlxuICAgIHtleGFtcGxlMX1cbiAgICBcIlwiXCJcbiAgICBcbiAgICAjIyBFeGVtcGxlIDEgSlNPTiBPdXRwdXQgOlxuICAgIFwiXCJcIlxuICAgIHtvdXRwdXQxfVxuICAgIFwiXCJcIlxuXG4gICAgIyMgRXhlbXBsZSAyIFVzZXIgSW5wdXQgOlxuICAgIFwiXCJcIlxuICAgIHtleGFtcGxlMn1cbiAgICBcIlwiXCJcbiAgICBcbiAgICAjIyBFeGVtcGxlIDIgSlNPTiBPdXRwdXQgOlxuICAgIFwiXCJcIlxuICAgIHtvdXRwdXQyfVxuICAgIFwiXCJcIlxuICAgIGBcblxuICBjb25zdCBwcm9tcHQgPSBDaGF0UHJvbXB0VGVtcGxhdGUuZnJvbU1lc3NhZ2VzKFtcbiAgICBbXCJzeXN0ZW1cIiwgbW90aWZzU3lzdGVtVGVtcGxhdGVdLFxuICAgIFtcImh1bWFuXCIsIFwie2lucHV0fVwiXSxcbiAgXSlcblxuICBjb25zdCBjaGFpbiA9IHByb21wdC5waXBlKHN0cnVjdHVyZWRNb2RlbClcbiAgY29uc3QgbW90aWZzUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgIGlucHV0OiBjbGVhbmVkSHRtbCxcbiAgICBleGFtcGxlMTogRVhBTVBMRVMuUFJKTEFOUjVMMTZCMDkxNC5pbnB1dCxcbiAgICBleGFtcGxlMjogRVhBTVBMRVMuUFJKTEFOUjVMMTZCMjQyNC5pbnB1dCxcbiAgICBvdXRwdXQxOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIwOTE0Lm1vdGlmcyxcbiAgICBvdXRwdXQyOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyNDI0Lm1vdGlmcyxcbiAgfSlcblxuICAvLyBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShtb3RpZnNQcm9tcHRSZXN1bHQpKVxuICBydW5Mb2dGdW4oXG4gICAgY29uc29sZS50YWJsZShbXG4gICAgICBbXCJEw6lidXRcIiwgbW90aWZzUHJvbXB0UmVzdWx0LmRlYnV0LnN1YnN0cmluZygwLCAzMCldLFxuICAgICAgW1wiRmluXCIsIG1vdGlmc1Byb21wdFJlc3VsdC5maW4uc3Vic3RyaW5nKDAsIDMwKV0sXG4gICAgXSksXG4gICAgeyBzaWxlbnQ6IFNJTEVOVF9MT0cgfSxcbiAgKVxuXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwRW5kKCksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gIGRlbGltaXRlcigpXG5cbiAgY29uc3QgYWp2ID0gbmV3IEFqdigpXG4gIGlmIChhanYudmFsaWRhdGUoRVhQT1NFX01PVElGU19TQ0hFTUEsIG1vdGlmc1Byb21wdFJlc3VsdCkpIHtcbiAgICBydW5Mb2dGdW4oY29uc29sZS5pbmZvKFwiRXhwb3PDqSBkZXMgbW90aWZzIE9LIPCfkYxcIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gICAgcmV0dXJuIG1vdGlmc1Byb21wdFJlc3VsdFxuICB9XG5cbiAgcnVuTG9nRnVuKGNvbnNvbGUud2FybihcIkV4cG9zw6kgZGVzIG1vdGlmcyBLTyDinYxcIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gIHJldHVybiB7fVxufVxuXG4vKipcbiAqIEFzeW5jaHJvbm91c2x5IGV4dHJhY3RzIHRoZSBtZXRhZGF0YSBmcm9tIHRoZSBnaXZlbiBIVE1MLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIC0gVGhlIEhUTUwgc3RyaW5nIGZyb20gd2hpY2ggdG8gZXh0cmFjdCB0aGUgbWV0YWRhdGEuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSAtIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBleHRyYWN0ZWQgbWV0YWRhdGEgb2JqZWN0LlxuICogVGhlIG9iamVjdCBjb250YWlucyB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKiAtIGBkb2N1bWVudFJlZmA6IFRoZSByZWZlcmVuY2Ugb2YgdGhlIGRvY3VtZW50LlxuICogLSBgdGl0cmVgOiBUaGUgdGl0bGUgb2YgdGhlIGRvY3VtZW50LlxuICogLSBgbnVtZXJvVGV4dGVgOiBUaGUgbnVtYmVyIG9mIHRoZSB0ZXh0LlxuICogLSBgcHJvY2VkdXJlQWNjZWxlcmVlYDogVGhlIGFjY2VsZXJhdGVkIHByb2NlZHVyZS5cbiAqIEB0aHJvd3Mge0Vycm9yfSAtIElmIHRoZSBleHRyYWN0ZWQgbWV0YWRhdGEgZG8gbm90IHZhbGlkYXRlIGFnYWluc3QgdGhlIE1FVEFfRE9OTkVFU19TQ0hFTUEuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RNZXRhRG9ubmVlcyhodG1sOiBzdHJpbmcpIHtcbiAgZGVsaW1pdGVyKClcbiAgbGV0IGNsZWFuZWRIdG1sID0gY2xlYW5IdG1sKGh0bWwpXG4gIGNsZWFuZWRIdG1sID0gcmVtb3ZlSHRtbFRhZ3MoY2xlYW5lZEh0bWwpXG5cbiAgY29uc3Qgc3RydWN0dXJlZE1vZGVsID0gTU9ERUwud2l0aFN0cnVjdHVyZWRPdXRwdXQoTUVUQV9ET05ORUVTX1NDSEVNQSlcblxuICBjb25zdCBtZXRhRG9ubmVlc1N5c3RlbVRlbXBsYXRlID0gYFxuICAgICR7U1lTVEVNX1RFTVBMQVRFfVxuICAgIGBcblxuICBjb25zdCBwcm9tcHQgPSBDaGF0UHJvbXB0VGVtcGxhdGUuZnJvbU1lc3NhZ2VzKFtcbiAgICBbXCJzeXN0ZW1cIiwgbWV0YURvbm5lZXNTeXN0ZW1UZW1wbGF0ZV0sXG4gICAgW1wiaHVtYW5cIiwgXCJ7aW5wdXR9XCJdLFxuICBdKVxuXG4gIGNvbnN0IGNoYWluID0gcHJvbXB0LnBpcGUoc3RydWN0dXJlZE1vZGVsKVxuICBjb25zdCByZXN1bHQ6IGFueSA9IGF3YWl0IGNoYWluLmludm9rZSh7XG4gICAgaW5wdXQ6IGNsZWFuZWRIdG1sLFxuICAgIGV4YW1wbGUxOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIwOTE0LmlucHV0LFxuICAgIGV4YW1wbGUyOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyNDI0LmlucHV0LFxuICAgIG91dHB1dDE6IEVYQU1QTEVTLlBSSkxBTlI1TDE2QjA5MTQubWV0YSxcbiAgICBvdXRwdXQyOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyNDI0Lm1ldGEsXG4gIH0pXG5cbiAgY29uc29sZS5ncm91cChcIk1ldGEtZG9ubsOpZXNcIilcbiAgY29uc29sZS50YWJsZShbXG4gICAgW1wiUsOpZsOpcmVuY2VcIiwgcmVzdWx0LmRvY3VtZW50UmVmXSxcbiAgICBbXCJUaXRyZVwiLCByZXN1bHQudGl0cmVdLFxuICAgIFtcIk51bcOpcm8gZHUgdGV4dGVcIiwgcmVzdWx0Lm51bWVyb1RleHRlXSxcbiAgICBbXCJQcm9jw6lkdXJlIGFjY8OpbMOpcsOpXCIsIHJlc3VsdC5wcm9jZWR1cmVBY2NlbGVyZWVdLFxuICBdKVxuICBjb25zb2xlLmdyb3VwRW5kKClcbiAgZGVsaW1pdGVyKClcblxuICBjb25zdCBhanYgPSBuZXcgQWp2KClcbiAgaWYgKGFqdi52YWxpZGF0ZShNRVRBX0RPTk5FRVNfU0NIRU1BLCByZXN1bHQpKSB7XG4gICAgcnVuTG9nRnVuKGNvbnNvbGUud2FybihcIk1ldGEtZG9ubsOpZXMgT0sg8J+RjFwiKSwgeyBzaWxlbnQ6IFNJTEVOVF9MT0cgfSlcbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICBydW5Mb2dGdW4oY29uc29sZS53YXJuKFwiTWV0YS1kb25uw6llcyBub24tY29uZm9ybWUg4p2MXCIpLCB7XG4gICAgc2lsZW50OiBTSUxFTlRfTE9HLFxuICB9KVxuICByZXR1cm4ge31cbn1cblxuLyoqXG4gKiBBc3luY2hyb25vdXNseSBleHRyYWN0cyB0aGUgXCJwcm9qZXQgZGUgbG9pXCIgZnJvbSB0aGUgZ2l2ZW4gSFRNTC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaHRtbCAtIFRoZSBIVE1MIHN0cmluZyBmcm9tIHdoaWNoIHRvIGV4dHJhY3QgdGhlIFwicHJvamV0IGRlIGxvaVwiLlxuICogQHJldHVybiB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gLSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXh0cmFjdGVkIFwicHJvamV0IGRlIGxvaVwiIG9iamVjdC5cbiAqIFRoZSBvYmplY3QgY29udGFpbnMgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICogLSBgYXJ0aWNsZXNgOiBBbiBhcnJheSBvZiBhcnRpY2xlIG9iamVjdHMsIGVhY2ggY29udGFpbmluZyB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKiAgIC0gYG51bWVyb0FydGljbGVgOiBUaGUgbnVtYmVyIG9mIHRoZSBhcnRpY2xlLlxuICogICAtIGBjYXJkaW5hbGA6IFRoZSBjYXJkaW5hbCBvZiB0aGUgYXJ0aWNsZS5cbiAqICAgLSBgdGl0cmVgOiBUaGUgdGl0bGUgb2YgdGhlIGFydGljbGUuXG4gKiAgIC0gYGRlYnV0YDogVGhlIGJlZ2lubmluZyBvZiB0aGUgYXJ0aWNsZS5cbiAqICAgLSBgZmluYDogVGhlIGVuZCBvZiB0aGUgYXJ0aWNsZS5cbiAqICAgLSBgYWxpbmVhc2A6IEFuIGFycmF5IG9mIGFsaW5lYXMuXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBJZiB0aGUgZXh0cmFjdGVkIFwicHJvamV0IGRlIGxvaVwiIGRvZXMgbm90IHZhbGlkYXRlIGFnYWluc3QgdGhlIFBST0pFVF9MT0lfU0NIRU1BLlxuICovXG5hc3luYyBmdW5jdGlvbiBleHRyYWN0UHJvamV0TG9pKGh0bWw6IHN0cmluZykge1xuICBydW5Mb2dGdW4oY29uc29sZS5ncm91cChcIlBhcnNpbmcgbG9pLi4uXCIpLCB7IHNpbGVudDogU0lMRU5UX0xPRyB9KVxuICBsZXQgY2xlYW5lZEh0bWwgPSBjbGVhbkh0bWwoaHRtbClcbiAgY29uc3Qgc3RydWN0dXJlZE1vZGVsID0gTU9ERUwud2l0aFN0cnVjdHVyZWRPdXRwdXQoUFJPSkVUX0xPSV9TQ0hFTUEpXG5cbiAgY29uc3QgcHJvamV0TG9pU3lzdGVtVGVtcGxhdGUgPSBgXG4gICAgJHtTWVNURU1fVEVNUExBVEV9XG5cbiAgICAjIEV4YW1wbGVzOiBcblxuICAgICMjIEV4ZW1wbGUgMSBVc2VyIElucHV0IDpcbiAgICBcIlwiXCJcbiAgICB7ZXhhbXBsZTF9XG4gICAgXCJcIlwiXG4gICAgXG4gICAgIyMgRXhlbXBsZSAxIEpTT04gT3V0cHV0IDpcbiAgICBcIlwiXCJcbiAgICB7b3V0cHV0MX1cbiAgICBcIlwiXCJcblxuICAgICMjIEV4ZW1wbGUgMiBVc2VyIElucHV0IDpcbiAgICBcIlwiXCJcbiAgICB7ZXhhbXBsZTJ9XG4gICAgXCJcIlwiXG4gICAgXG4gICAgIyMgRXhlbXBsZSAyIEpTT04gT3V0cHV0IDpcbiAgICBcIlwiXCJcbiAgICB7b3V0cHV0Mn1cbiAgICBcIlwiXCJcbiAgICBgXG5cbiAgY29uc3QgcHJvbXB0ID0gQ2hhdFByb21wdFRlbXBsYXRlLmZyb21NZXNzYWdlcyhbXG4gICAgW1wic3lzdGVtXCIsIHByb2pldExvaVN5c3RlbVRlbXBsYXRlXSxcbiAgICBbXCJodW1hblwiLCBcIntpbnB1dH1cIl0sXG4gIF0pXG5cbiAgY29uc3QgY2hhaW4gPSBwcm9tcHQucGlwZShzdHJ1Y3R1cmVkTW9kZWwpXG4gIGNvbnN0IGFydGljbGVzUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgIGlucHV0OiBjbGVhbmVkSHRtbCxcbiAgICBleGFtcGxlMTogRVhBTVBMRVMuUFJKTEFOUjVMMTZCMDkxNC5pbnB1dCxcbiAgICBleGFtcGxlMjogRVhBTVBMRVMuUFJKTEFOUjVMMTZCMjQyNC5pbnB1dCxcbiAgICBvdXRwdXQxOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIwOTE0LmxvaSxcbiAgICBvdXRwdXQyOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyNDI0LmxvaSxcbiAgfSlcblxuICBydW5Mb2dGdW4oXG4gICAgY29uc29sZS5sb2coXCJGb3VuZCBcIiwgYXJ0aWNsZXNQcm9tcHRSZXN1bHQuYXJ0aWNsZXMubGVuZ3RoLCBcIiBhcnRpY2xlcy5cIiksXG4gICAgeyBzaWxlbnQ6IFNJTEVOVF9MT0cgfSxcbiAgKVxuXG4gIGZvciAoY29uc3QgYXJ0aWNsZSBvZiBhcnRpY2xlc1Byb21wdFJlc3VsdC5hcnRpY2xlcykge1xuICAgIGFydGljbGUuYWxpbmVhcyA9IGF3YWl0IGV4dHJhY3RBbGluZWFzKGh0bWwsIGFydGljbGUpXG4gIH1cblxuICBydW5Mb2dGdW4oXG4gICAgY29uc29sZS50YWJsZShcbiAgICAgIGFydGljbGVzUHJvbXB0UmVzdWx0LmFydGljbGVzLm1hcCgoYXJ0aWNsZTogYW55KSA9PiBbXG4gICAgICAgIGFydGljbGUubnVtZXJvQXJ0aWNsZSxcbiAgICAgICAgYXJ0aWNsZS50aXRyZSxcbiAgICAgICAgYXJ0aWNsZS5kZWJ1dC5zdWJzdHJpbmcoMCwgMTApLFxuICAgICAgICBhcnRpY2xlLmZpbi5zdWJzdHJpbmcoMCwgMTApLFxuICAgICAgICBgTm9tYnJlIGQnYWxpbmVhcyA6ICR7YXJ0aWNsZS5hbGluZWFzLmxlbmd0aH1gLFxuICAgICAgXSksXG4gICAgKSxcbiAgICB7IHNpbGVudDogU0lMRU5UX0xPRyB9LFxuICApXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwRW5kKCksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG5cbiAgY29uc3QgYWp2ID0gbmV3IEFqdigpXG4gIGlmIChhanYudmFsaWRhdGUoUFJPSkVUX0xPSV9TQ0hFTUEsIGFydGljbGVzUHJvbXB0UmVzdWx0KSkge1xuICAgIHJ1bkxvZ0Z1bihjb25zb2xlLmluZm8oXCJQcm9qZXQgZGUgbG9pIE9LIPCfkYxcIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gICAgZGVsaW1pdGVyKClcbiAgICByZXR1cm4gYXJ0aWNsZXNQcm9tcHRSZXN1bHRcbiAgfVxuXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLndhcm4oXCJQcm9qZXQgZGUgbG9pIEtPIOKdjFwiKSwgeyBzaWxlbnQ6IFNJTEVOVF9MT0cgfSlcbiAgZGVsaW1pdGVyKClcbiAgcmV0dXJuIHt9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RBbGluZWFzKGh0bWw6IHN0cmluZywgYXJ0aWNsZTogYW55KSB7XG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwKFwiUGFyc2luZyBhbGluZWFzLi4uXCIpLCB7IHNpbGVudDogU0lMRU5UX0xPRyB9KVxuICBsZXQgY2xlYW5lZEh0bWwgPSBjbGVhbkh0bWwoaHRtbClcblxuICBjb25zdCBzdHJ1Y3R1cmVkTW9kZWwgPSBNT0RFTC53aXRoU3RydWN0dXJlZE91dHB1dChBTElORUFfU0NIRU1BKVxuXG4gIGNvbnN0IGFsaW5lYXNTeXN0ZW1UZW1wbGF0ZSA9IGBcbiAgICAke1NZU1RFTV9URU1QTEFURX1cblxuICAgIEV4dHJhaXMgdG91cyBsZXMgYWxpbmVhcyBkZSBsYSBwb3J0aW9uIGRlIHRleHRlIGNvbW1lbsOnYW50IHBhciDCqyB7ZGVidXR9IMK7IGV0IGZpbmlzc2FudCBwYXIgwqsge2Zpbn0gwrsuXG4gICAgVW4gYWxpbsOpYSBjb250aWVubmVudCB0b3Vqb3VycyB1bmUgYmFsaXNlIMKrIDxpbWcgwrsuXG5cbiAgICAjIEV4YW1wbGVzOiBcblxuICAgICMjIEV4ZW1wbGUgMSBVc2VyIElucHV0IDpcbiAgICBcIlwiXCJcbiAgICB7ZXhhbXBsZTF9XG4gICAgXCJcIlwiXG4gICAgXG4gICAgIyMgRXhlbXBsZSAxIEpTT04gT3V0cHV0IDpcbiAgICBcIlwiXCJcbiAgICB7b3V0cHV0MX1cbiAgICBcIlwiXCJcbiAgICBgXG5cbiAgY29uc3QgcHJvbXB0ID0gQ2hhdFByb21wdFRlbXBsYXRlLmZyb21NZXNzYWdlcyhbXG4gICAgW1wic3lzdGVtXCIsIGFsaW5lYXNTeXN0ZW1UZW1wbGF0ZV0sXG4gICAgW1wiaHVtYW5cIiwgXCJ7aW5wdXR9XCJdLFxuICBdKVxuXG4gIGNvbnN0IGNoYWluID0gcHJvbXB0LnBpcGUoc3RydWN0dXJlZE1vZGVsKVxuICBjb25zdCBhbGluZWFzUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgIGlucHV0OiBjbGVhbmVkSHRtbCxcbiAgICBkZWJ1dDogYXJ0aWNsZS5kZWJ1dCxcbiAgICBmaW46IGFydGljbGUuZmluLFxuICAgIGV4YW1wbGUxOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyNDI0LmlucHV0LFxuICAgIG91dHB1dDE6IEVYQU1QTEVTLlBSSkxBTlI1TDE2QjI0MjQuYWxpbmVhcyxcbiAgfSlcblxuICBjb25zdCBhanYgPSBuZXcgQWp2KClcbiAgaWYgKGFqdi52YWxpZGF0ZShBTElORUFfU0NIRU1BLCBhbGluZWFzUHJvbXB0UmVzdWx0IGFzIGFueSkpIHtcbiAgICBydW5Mb2dGdW4oXG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIFwiRm91bmQgXCIsXG4gICAgICAgIGFsaW5lYXNQcm9tcHRSZXN1bHQuYWxpbmVhcy5sZW5ndGgsXG4gICAgICAgIFwiIGFsaW5lYXMgZm9yIEFydGljbGUgXCIsXG4gICAgICAgIGFydGljbGUubnVtZXJvQXJ0aWNsZSxcbiAgICAgICAgYXJ0aWNsZS50aXRyZSxcbiAgICAgICksXG4gICAgICB7IHNpbGVudDogU0lMRU5UX0xPRyB9LFxuICAgIClcbiAgICBydW5Mb2dGdW4oY29uc29sZS5ncm91cEVuZCgpLCB7IHNpbGVudDogU0lMRU5UX0xPRyB9KVxuICAgIGRlbGltaXRlcigpXG4gICAgcmV0dXJuIGFsaW5lYXNQcm9tcHRSZXN1bHQuYWxpbmVhc1xuICB9XG5cbiAgcnVuTG9nRnVuKGNvbnNvbGUud2FybihcIkFsaW5lYXMgS09cIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gIGRlbGltaXRlcigpXG4gIHJldHVybiB7fVxufVxuXG4vKipcbiAqIEFzeW5jaHJvbm91c2x5IGV4dHJhY3RzIHRoZSBcInNvbW1haXJlXCIgKG91dGxpbmUpIGZyb20gdGhlIGdpdmVuIEhUTUwuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGh0bWwgLSBUaGUgSFRNTCBzdHJpbmcgZnJvbSB3aGljaCB0byBleHRyYWN0IHRoZSBcInNvbW1haXJlXCIuXG4gKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSAtIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBleHRyYWN0ZWQgXCJzb21tYWlyZVwiIG9iamVjdC5cbiAqIFRoZSBvYmplY3QgY29udGFpbnMgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICogLSBgc29tbWFpcmVgOiBBbiBhcnJheSBvZiBtYWluIGRpdmlzaW9uIG9iamVjdHMsIGVhY2ggY29udGFpbmluZyB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKiAgIC0gYG51bWVyb0RpdmlzaW9uYDogVGhlIG51bWJlciBvZiB0aGUgbWFpbiBkaXZpc2lvbi5cbiAqICAgLSBgdGl0cmVgOiBUaGUgdGl0bGUgb2YgdGhlIG1haW4gZGl2aXNpb24uXG4gKiAgIC0gYHR5cGVEaXZpc2lvbmA6IFRoZSB0eXBlIG9mIGNvbnRlbnQgaW4gdGhlIG1haW4gZGl2aXNpb24uXG4gKiAgIC0gYHNlcXVlbmNlYDogVGhlIHNlcXVlbmNlIG9mIHRoZSBtYWluIGRpdmlzaW9uLlxuICogICAtIGBwYXJlbnRgOiBUaGUgcGFyZW50IG9mIHRoZSBtYWluIGRpdmlzaW9uLlxuICogQHRocm93cyB7RXJyb3J9IC0gSWYgdGhlIGV4dHJhY3RlZCBcInNvbW1haXJlXCIgZG9lcyBub3QgdmFsaWRhdGUgYWdhaW5zdCB0aGUgU09NTUFJUkVfU0NIRU1BLlxuICovXG5hc3luYyBmdW5jdGlvbiBleHRyYWN0U29tbWFpcmUoaHRtbDogc3RyaW5nKSB7XG4gIGxldCBjbGVhbmVkSHRtbCA9IGNsZWFuSHRtbChodG1sKVxuICBjbGVhbmVkSHRtbCA9IHJlbW92ZUh0bWxUYWdzKGNsZWFuZWRIdG1sKVxuXG4gIGNvbnN0IHN0cnVjdHVyZWRNb2RlbCA9IE1PREVMLndpdGhTdHJ1Y3R1cmVkT3V0cHV0KFNPTU1BSVJFX1NDSEVNQSlcblxuICBjb25zdCBzb21tYWlyZVN5c3RlbVRlbXBsYXRlID0gYFxuICAgICR7U1lTVEVNX1RFTVBMQVRFfVxuXG4gICAgIyBFeGFtcGxlczogXG5cbiAgICAjIyBFeGVtcGxlIDEgVXNlciBJbnB1dCA6XG4gICAgXCJcIlwiXG4gICAge2V4YW1wbGUxfVxuICAgIFwiXCJcIlxuICAgIFxuICAgICMjIEV4ZW1wbGUgMSBKU09OIE91dHB1dCA6XG4gICAgXCJcIlwiXG4gICAge291dHB1dDF9XG4gICAgXCJcIlwiXG5cbiAgICAjIyBFeGVtcGxlIDIgVXNlciBJbnB1dCA6XG4gICAgXCJcIlwiXG4gICAge2V4YW1wbGUyfVxuICAgIFwiXCJcIlxuICAgIFxuICAgICMjIEV4ZW1wbGUgMiBKU09OIE91dHB1dCA6XG4gICAgXCJcIlwiXG4gICAge291dHB1dDJ9XG4gICAgXCJcIlwiXG4gICAgYFxuXG4gIGNvbnN0IHByb21wdCA9IENoYXRQcm9tcHRUZW1wbGF0ZS5mcm9tTWVzc2FnZXMoW1xuICAgIFtcInN5c3RlbVwiLCBzb21tYWlyZVN5c3RlbVRlbXBsYXRlXSxcbiAgICBbXCJodW1hblwiLCBcIntpbnB1dH1cIl0sXG4gIF0pXG5cbiAgY29uc3QgY2hhaW4gPSBwcm9tcHQucGlwZShzdHJ1Y3R1cmVkTW9kZWwpXG4gIGNvbnN0IHNvbW1haXJlUHJvbXB0UmVzdWx0OiBhbnkgPSBhd2FpdCBjaGFpbi5pbnZva2Uoe1xuICAgIGlucHV0OiBjbGVhbmVkSHRtbCxcbiAgICBleGFtcGxlMTogRVhBTVBMRVMuUFJKTEFOUjVMMTZCMjAxNC5pbnB1dCxcbiAgICBvdXRwdXQxOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIyMDE0LnNvbW1haXJlLFxuICAgIGV4YW1wbGUyOiBFWEFNUExFUy5QUkpMQU5SNUwxNkIwOTE0LmlucHV0LFxuICAgIG91dHB1dDI6IEVYQU1QTEVTLlBSSkxBTlI1TDE2QjA5MTQuc29tbWFpcmUsXG4gIH0pXG5cbiAgaWYgKCFzb21tYWlyZVByb21wdFJlc3VsdC5zb21tYWlyZSkge1xuICAgIHJ1bkxvZ0Z1bihjb25zb2xlLndhcm4oXCJBdWN1biBzb21tYWlyZSBuJ2Egw6l0w6kgdHJvdXbDqSDinZNcIiksIHtcbiAgICAgIHNpbGVudDogU0lMRU5UX0xPRyxcbiAgICB9KVxuICAgIGRlbGltaXRlcigpXG4gICAgcmV0dXJuIHsgc29tbWFpcmU6IFtdIH1cbiAgfVxuXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwKFwiU29tbWFpcmVcIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gIHJ1bkxvZ0Z1bihcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIFwiRm91bmQgXCIsXG4gICAgICBzb21tYWlyZVByb21wdFJlc3VsdC5zb21tYWlyZS5sZW5ndGgsXG4gICAgICBcIiBtYWluIGRpdmlzaW9ucyAobGV2ZWwgMSkuXCIsXG4gICAgKSxcbiAgICB7IHNpbGVudDogU0lMRU5UX0xPRyB9LFxuICApXG4gIHJ1bkxvZ0Z1bihcbiAgICBjb25zb2xlLnRhYmxlKFxuICAgICAgc29tbWFpcmVQcm9tcHRSZXN1bHQuc29tbWFpcmUubWFwKChpdGVtOiBhbnkpID0+IFtcbiAgICAgICAgaXRlbS5zZXF1ZW5jZSxcbiAgICAgICAgaXRlbS50aXRyZSxcbiAgICAgICAgaXRlbS50eXBlRGl2aXNpb24sXG4gICAgICAgIGl0ZW0ucGFyZW50LFxuICAgICAgXSksXG4gICAgKSxcbiAgICB7IHNpbGVudDogU0lMRU5UX0xPRyB9LFxuICApXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLmdyb3VwRW5kKCksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG5cbiAgY29uc3QgYWp2ID0gbmV3IEFqdigpXG4gIGlmIChhanYudmFsaWRhdGUoU09NTUFJUkVfU0NIRU1BLCBzb21tYWlyZVByb21wdFJlc3VsdCBhcyBhbnkpKSB7XG4gICAgcnVuTG9nRnVuKGNvbnNvbGUuaW5mbyhcIlNvbW1haXJlIE9LIPCfkYxcIiksIHsgc2lsZW50OiBTSUxFTlRfTE9HIH0pXG4gICAgZGVsaW1pdGVyKClcbiAgICByZXR1cm4gc29tbWFpcmVQcm9tcHRSZXN1bHQuc29tbWFpcmVcbiAgfVxuXG4gIHJ1bkxvZ0Z1bihjb25zb2xlLndhcm4oXCJMYSBjb25zdHJ1Y3Rpb24gZHUgc29tbWFpcmUgZXN0IEtPIOKdjFwiKSwge1xuICAgIHNpbGVudDogU0lMRU5UX0xPRyxcbiAgfSlcbiAgZGVsaW1pdGVyKClcbiAgcmV0dXJuIHsgc29tbWFpcmU6IFtdIH1cbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsVUFBVSxRQUFRLG1CQUFtQjtBQUM5QyxTQUFTQyxrQkFBa0IsUUFBUSx5QkFBeUI7QUFDNUQsT0FBT0MsR0FBRyxNQUFNLEtBQUs7QUFBQSxTQUVaQyxTQUFTLEVBQUVDLFNBQVM7QUFFN0IsTUFBTUMsb0JBQW9CLEdBQUdDLE9BQU8sQ0FBQyxtQ0FBbUMsQ0FBQztBQUN6RSxNQUFNQyxtQkFBbUIsR0FBR0QsT0FBTyxDQUFDLGtDQUFrQyxDQUFDO0FBQ3ZFLE1BQU1FLGlCQUFpQixHQUFHRixPQUFPLENBQUMsZ0NBQWdDLENBQUM7QUFDbkUsTUFBTUcsYUFBYSxHQUFHSCxPQUFPLENBQUMsNkJBQTZCLENBQUM7QUFDNUQsTUFBTUksZUFBZSxHQUFHSixPQUFPLENBQUMsK0JBQStCLENBQUM7O0FBRWhFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNSyxRQUFRLEdBQUc7RUFDZkMsZ0JBQWdCLEVBQUU7SUFDaEJDLE1BQU0sRUFBRVAsT0FBTyxDQUFDLHFDQUFxQyxDQUFDO0lBQ3REUSxLQUFLLEVBQUVSLE9BQU8sQ0FBQyxvQ0FBb0MsQ0FBQztJQUNwRFMsR0FBRyxFQUFFVCxPQUFPLENBQUMsa0NBQWtDLENBQUM7SUFDaERVLElBQUksRUFBRVYsT0FBTyxDQUFDLG1DQUFtQyxDQUFDO0lBQ2xEVyxRQUFRLEVBQUVYLE9BQU8sQ0FBQyx1Q0FBdUM7RUFDM0QsQ0FBQztFQUNEWSxnQkFBZ0IsRUFBRTtJQUNoQkwsTUFBTSxFQUFFUCxPQUFPLENBQUMscUNBQXFDLENBQUM7SUFDdERRLEtBQUssRUFBRVIsT0FBTyxDQUFDLG9DQUFvQyxDQUFDO0lBQ3BEUyxHQUFHLEVBQUVULE9B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QUFFO01BQ3pEakQsTUFBTSxFQUFFSjtJQUNWLENBQUMsQ0FBQztJQUNGcEMsU0FBUyxDQUFDLENBQUM7SUFDWCxPQUFPO01BQUVjLFFBQVEsRUFBRTtJQUFHLENBQUM7RUFDekI7RUFFQWIsU0FBUyxDQUFDd0MsT0FBTyxDQUFDNkIsS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFO0lBQUU5QixNQUFNLEVBQUVKO0VBQVcsQ0FBQyxDQUFDO0VBQzVEbkMsU0FBUyxDQUNQd0MsT0FBTyxDQUFDeUQsR0FBRyxDQUNULFFBQVEsRUFDUlEsb0JBQW9CLENBQUM1RixRQUFRLENBQUNxRixNQUFNLEVBQ3BDLDRCQUNGLENBQUMsRUFDRDtJQUFFM0QsTUFBTSxFQUFFSjtFQUFXLENBQ3ZCLENBQUM7RUFDRG5DLFNBQVMsQ0FDUHdDLE9BQU8sQ0FBQzRDLEtBQUssQ0FDWHFCLG9CQUFvQixDQUFDNUYsUUFBUSxDQUFDdUYsR0FBRyxDQUFFTSxJQUFTLElBQUssQ0FDL0NBLElBQUksQ0FBQ0MsUUFBUSxFQUNiRCxJQUFJLENBQUNkLEtBQUssRUFDVmMsSUFBSSxDQUFDRSxZQUFZLEVBQ2pCRixJQUFJLENBQUNHLE1BQU0sQ0FDWixDQUNILENBQUMsRUFDRDtJQUFFdEUsTUFBTSxFQUFFSjtFQUFXLENBQ3ZCLENBQUM7RUFDRG5DLFNBQVMsQ0FBQ3dDLE9BQU8sQ0FBQ3FDLFFBQVEsQ0FBQyxDQUFDLEVBQUU7SUFBRXRDLE1BQU0sRUFBRUo7RUFBVyxDQUFDLENBQUM7RUFFckQsTUFBTW1ELEdBQUcsR0FBRyxJQUFJeEYsR0FBRyxDQUFDLENBQUM7RUFDckIsSUFBSXdGLEdBQUcsQ0FBQ0MsUUFBUSxDQUFDakYsZUFBZSxFQUFFbUcsb0JBQTJCLENBQUMsRUFBRTtJQUM5RHpHLFNBQVMsQ0FBQ3dDLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUU7TUFBRUYsTUFBTSxFQUFFSjtJQUFXLENBQUMsQ0FBQztJQUNqRXBDLFNBQVMsQ0FBQyxDQUFDO0lBQ1gsT0FBTzBHLG9CQUFvQixDQUFDNUYsUUFBUTtFQUN0QztFQUVBYixTQUFTLENBQUN3QyxPQUFPLENBQUNnRCxJQUFJLENBQUMsc0NBQXNDLENBQUMsRUFBRTtJQUM5RGpELE1BQU0sRUFBRUo7RUFDVixDQUFDLENBQUM7RUFDRnBDLFNBQVMsQ0FBQyxDQUFDO0VBQ1gsT0FBTztJQUFFYyxRQUFRLEVBQUU7RUFBRyxDQUFDO0FBQ3pCIiwiaWdub3JlTGlzdCI6W119