@learnpack/learnpack 5.0.211 → 5.0.215

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @learnpack/learnpack
21
21
  $ learnpack COMMAND
22
22
  running command...
23
23
  $ learnpack (-v|--version|version)
24
- @learnpack/learnpack/5.0.211 win32-x64 node-v22.15.0
24
+ @learnpack/learnpack/5.0.215 win32-x64 node-v22.15.0
25
25
  $ learnpack --help [COMMAND]
26
26
  USAGE
27
27
  $ learnpack COMMAND
@@ -80,7 +80,7 @@ DESCRIPTION
80
80
  12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
81
81
  ```
82
82
 
83
- _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\audit.ts)_
83
+ _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\audit.ts)_
84
84
 
85
85
  ## `learnpack breakToken`
86
86
 
@@ -95,7 +95,7 @@ OPTIONS
95
95
  -y, --yes Skip all prompts and initialize an empty project
96
96
  ```
97
97
 
98
- _See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\breakToken.ts)_
98
+ _See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\breakToken.ts)_
99
99
 
100
100
  ## `learnpack clean`
101
101
 
@@ -110,7 +110,7 @@ DESCRIPTION
110
110
  Extra documentation goes here
111
111
  ```
112
112
 
113
- _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\clean.ts)_
113
+ _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\clean.ts)_
114
114
 
115
115
  ## `learnpack download [PACKAGE]`
116
116
 
@@ -128,7 +128,7 @@ DESCRIPTION
128
128
  Extra documentation goes here
129
129
  ```
130
130
 
131
- _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\download.ts)_
131
+ _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\download.ts)_
132
132
 
133
133
  ## `learnpack help [COMMAND]`
134
134
 
@@ -160,7 +160,7 @@ OPTIONS
160
160
  -y, --yes Skip all prompts and initialize an empty project
161
161
  ```
162
162
 
163
- _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\init.ts)_
163
+ _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\init.ts)_
164
164
 
165
165
  ## `learnpack login [PACKAGE]`
166
166
 
@@ -178,7 +178,7 @@ DESCRIPTION
178
178
  Extra documentation goes here
179
179
  ```
180
180
 
181
- _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\login.ts)_
181
+ _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\login.ts)_
182
182
 
183
183
  ## `learnpack logout [PACKAGE]`
184
184
 
@@ -196,7 +196,7 @@ DESCRIPTION
196
196
  Extra documentation goes here
197
197
  ```
198
198
 
199
- _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\logout.ts)_
199
+ _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\logout.ts)_
200
200
 
201
201
  ## `learnpack plugins`
202
202
 
@@ -328,7 +328,7 @@ OPTIONS
328
328
  -s, --strict strict mode
329
329
  ```
330
330
 
331
- _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\publish.ts)_
331
+ _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\publish.ts)_
332
332
 
333
333
  ## `learnpack serve`
334
334
 
@@ -345,7 +345,7 @@ OPTIONS
345
345
  -y, --yes Skip all prompts and initialize an empty project
346
346
  ```
347
347
 
348
- _See code: [src\commands\serve.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\serve.ts)_
348
+ _See code: [src\commands\serve.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\serve.ts)_
349
349
 
350
350
  ## `learnpack start`
351
351
 
@@ -367,7 +367,7 @@ OPTIONS
367
367
  -y, --yes Skip all prompts and initialize an empty project
368
368
  ```
369
369
 
370
- _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\start.ts)_
370
+ _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\start.ts)_
371
371
 
372
372
  ## `learnpack test [EXERCISESLUG]`
373
373
 
@@ -384,7 +384,7 @@ OPTIONS
384
384
  -y, --yes Skip all prompts and initialize an empty project
385
385
  ```
386
386
 
387
- _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\test.ts)_
387
+ _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\test.ts)_
388
388
 
389
389
  ## `learnpack translate`
390
390
 
@@ -398,7 +398,7 @@ OPTIONS
398
398
  -y, --yes Skip all prompts and initialize an empty project
399
399
  ```
400
400
 
401
- _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.211/src\commands\translate.ts)_
401
+ _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.215/src\commands\translate.ts)_
402
402
  <!-- commandsstop -->
403
403
 
404
404
  > > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
@@ -12,7 +12,7 @@ export declare const createLearnJson: (courseInfo: FormState) => {
12
12
  technologies: string[];
13
13
  difficulty: string;
14
14
  description: {
15
- us: string;
15
+ [x: string]: string;
16
16
  };
17
17
  grading: string;
18
18
  telemetry: {
@@ -48,18 +48,17 @@ const createLearnJson = (courseInfo) => {
48
48
  const language = courseInfo.language || "en";
49
49
  const learnJson = {
50
50
  slug: (0, creatorUtilities_2.slugify)(courseInfo.title),
51
- title: language === "en" ?
51
+ title: language === "en" || language === "us" ?
52
52
  {
53
53
  us: courseInfo.title,
54
54
  } :
55
55
  {
56
56
  [language]: courseInfo.title,
57
- // us: courseInfo.title,
58
57
  },
59
58
  technologies: courseInfo.technologies || [],
60
59
  difficulty: "beginner",
61
60
  description: {
62
- us: courseInfo.description,
61
+ [language === "en" || language === "us" ? "us" : language]: courseInfo.description,
63
62
  },
64
63
  grading: "isolated",
65
64
  telemetry: {
@@ -136,14 +135,10 @@ const cleanFormState = (formState) => {
136
135
  return rest;
137
136
  };
138
137
  async function startExerciseGeneration(bucket, rigoToken, steps, packageContext, exercise, tutorialDir, courseSlug, purposeSlug, lastLesson = "") {
139
- const exercisesDir = `${tutorialDir}/exercises`;
140
138
  const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
141
- console.log("exSlug", exSlug);
142
- const readmeFilename = `README.${packageContext.language && packageContext.language !== "en" ?
143
- `${packageContext.language}.` :
144
- ""}md`;
139
+ console.log("Starting generation of", exSlug);
145
140
  const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/exercise-processor/${exercise.id}/${rigoToken}`;
146
- const res = await (0, rigoActions_1.readmeCreator)(rigoToken, {
141
+ await (0, rigoActions_1.readmeCreator)(rigoToken, {
147
142
  title: `${exercise.id} - ${exercise.title}`,
148
143
  output_lang: packageContext.language || "en",
149
144
  list_of_exercises: JSON.stringify(steps.map(step => step.id + "-" + step.title)),
@@ -320,35 +315,6 @@ class ServeCommand extends SessionCommand_1.default {
320
315
  });
321
316
  stream.end(buffer);
322
317
  });
323
- app.post("/upload-image", express.json({ limit: "10mb" }), async (req, res) => {
324
- const { image_url, destination } = req.body;
325
- if (!image_url || !destination) {
326
- return res
327
- .status(400)
328
- .json({ error: "image_url and destination are required" });
329
- }
330
- try {
331
- const response = await fetch(image_url);
332
- if (!response.ok) {
333
- return res.status(400).json({
334
- error: `Failed to download image: ${response.statusText}`,
335
- });
336
- }
337
- const contentType = response.headers.get("content-type") || "application/octet-stream";
338
- const buffer = await response.arrayBuffer();
339
- const file = bucket.file(destination);
340
- await file.save(Buffer.from(buffer), {
341
- resumable: false,
342
- contentType,
343
- });
344
- console.log(`✅ Image uploaded to ${file.name}`);
345
- res.json({ message: "Image uploaded successfully", path: file.name });
346
- }
347
- catch (error) {
348
- console.error("❌ upload-image error:", error);
349
- res.status(500).json({ error: error.message });
350
- }
351
- });
352
318
  const upload = (0, misc_1.createUploadMiddleware)();
353
319
  app.post("/upload-image-file", upload.single("file"), async (req, res) => {
354
320
  console.log("UPLOADING IMAGE FILE");
@@ -546,25 +512,38 @@ class ServeCommand extends SessionCommand_1.default {
546
512
  const { slug } = req.params;
547
513
  const courseSlug = req.query.slug;
548
514
  const lang = req.query.lang || "us";
515
+ if (!courseSlug) {
516
+ return res.status(400).json({ error: "Missing courseSlug" });
517
+ }
549
518
  const basePath = `courses/${courseSlug}/exercises/${slug}/`;
550
- const filename = lang === "us" ? "README.md" : `README.${lang}.md`;
551
- const file = bucket.file(basePath + filename);
552
- let contentBuffer;
519
+ const prefix = basePath + "README";
553
520
  try {
554
- contentBuffer = await file.download();
555
- }
556
- catch (_a) {
557
- if (lang !== "us") {
558
- console.warn(`No README for lang '${lang}', falling back to 'us'`);
559
- const fallbackFile = bucket.file(basePath + "README.md");
560
- contentBuffer = await fallbackFile.download();
521
+ const [files] = await bucket.getFiles({ prefix });
522
+ const readmeFiles = files.map(f => f.name);
523
+ if (readmeFiles.length === 0) {
524
+ return res.status(404).json({ error: "No README files found" });
561
525
  }
562
- else {
563
- return res.status(404).json({ error: "README not found" });
526
+ const requestedFilename = lang === "us" || lang === "en" ?
527
+ `${basePath}README.md` :
528
+ `${basePath}README.${lang}.md`;
529
+ let selectedFile = readmeFiles.find(f => f === requestedFilename);
530
+ if (!selectedFile) {
531
+ selectedFile = readmeFiles[0];
532
+ console.warn(`Requested README not found for lang '${lang}', using '${selectedFile}'`);
533
+ }
534
+ let foundLang = "us";
535
+ const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i);
536
+ if (match && match[1]) {
537
+ foundLang = match[1].toLowerCase();
564
538
  }
539
+ const [contentBuffer] = await bucket.file(selectedFile).download();
540
+ const { attributes, body } = frontMatter(contentBuffer.toString());
541
+ res.send({ attributes, body, lang: foundLang });
542
+ }
543
+ catch (error) {
544
+ console.error(error);
545
+ res.status(500).json({ error: "Internal server error" });
565
546
  }
566
- const { attributes, body } = frontMatter(contentBuffer[0].toString());
567
- res.send({ attributes, body });
568
547
  });
569
548
  app.get("/.learn/assets/:file", async (req, res) => {
570
549
  console.log("GET /.learn/assets/:file", req.params.file);
@@ -589,12 +568,12 @@ class ServeCommand extends SessionCommand_1.default {
589
568
  const query = req.query;
590
569
  console.log(`PUT /exercise/${slug}/file/${fileName}`);
591
570
  const courseSlug = query.slug;
592
- console.log("COURSE SLUG", courseSlug);
571
+ // console.log("COURSE SLUG", courseSlug)
593
572
  // Update the file in the bucket
594
573
  const file = await bucket.file(`courses/${courseSlug}/exercises/${slug}/${fileName}`);
595
574
  await file.save(req.body);
596
575
  const created = await file.exists();
597
- console.log("File updated", created);
576
+ // console.log("File updated", created)
598
577
  res.send({
599
578
  message: "File updated",
600
579
  created,
@@ -920,12 +899,27 @@ class ServeCommand extends SessionCommand_1.default {
920
899
  }
921
900
  };
922
901
  copyDir(uiSrc, buildRoot);
902
+ const availableLangs = Object.keys(config.title);
903
+ let selectedLang = "us";
904
+ let title = "";
905
+ if (availableLangs.includes("us")) {
906
+ title = config.title.us;
907
+ }
908
+ else {
909
+ // Select the first available lang
910
+ title = config.title[availableLangs[0]];
911
+ selectedLang = availableLangs[0];
912
+ }
913
+ console.log(config.description, "CONFIG DESCRIPTION");
914
+ // console.log(availableLangs, "AVAILABLE LANGs")
915
+ // console.log(selectedLang, "SELECTED LANG")
916
+ // console.log(title, "TITLE")
923
917
  // 5) Inyectar placeholders en index.html
924
918
  const idxTpl = fs.readFileSync(path.join(uiSrc, "index.html"), "utf-8");
925
919
  const idxHtml = idxTpl
926
- .replace(/{{title}}/g, config.title.us)
927
- .replace(/<title>.*<\/title>/, `<title>${config.title.us}</title>`)
928
- .replace(/{{description}}/g, config.description.us)
920
+ .replace(/{{title}}/g, title)
921
+ .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
922
+ .replace(/{{description}}/g, config.description[selectedLang])
929
923
  .replace(/{{preview}}/g, fixPreviewUrl(slug, "") ||
930
924
  "https://raw.githubusercontent.com/learnpack/ide/master/public/learnpack.svg")
931
925
  .replace(/{{slug}}/g, slug)
@@ -1 +1 @@
1
- {"version":"5.0.211","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
1
+ {"version":"5.0.215","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@learnpack/learnpack",
3
3
  "description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
4
- "version": "5.0.211",
4
+ "version": "5.0.215",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -74,18 +74,18 @@ export const createLearnJson = (courseInfo: FormState) => {
74
74
  const learnJson = {
75
75
  slug: slugify(courseInfo.title as string),
76
76
  title:
77
- language === "en" ?
77
+ language === "en" || language === "us" ?
78
78
  {
79
79
  us: courseInfo.title,
80
80
  } :
81
81
  {
82
82
  [language]: courseInfo.title,
83
- // us: courseInfo.title,
84
83
  },
85
84
  technologies: courseInfo.technologies || [],
86
85
  difficulty: "beginner",
87
86
  description: {
88
- us: courseInfo.description,
87
+ [language === "en" || language === "us" ? "us" : language]:
88
+ courseInfo.description,
89
89
  },
90
90
  grading: "isolated",
91
91
  telemetry: {
@@ -226,20 +226,12 @@ async function startExerciseGeneration(
226
226
  purposeSlug: string,
227
227
  lastLesson = ""
228
228
  ): Promise<void> {
229
- const exercisesDir = `${tutorialDir}/exercises`
230
-
231
229
  const exSlug = slugify(exercise.id + "-" + exercise.title)
232
- console.log("exSlug", exSlug)
233
-
234
- const readmeFilename = `README.${
235
- packageContext.language && packageContext.language !== "en" ?
236
- `${packageContext.language}.` :
237
- ""
238
- }md`
230
+ console.log("Starting generation of", exSlug)
239
231
 
240
232
  const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/exercise-processor/${exercise.id}/${rigoToken}`
241
233
 
242
- const res = await readmeCreator(
234
+ await readmeCreator(
243
235
  rigoToken,
244
236
  {
245
237
  title: `${exercise.id} - ${exercise.title}`,
@@ -517,44 +509,6 @@ export default class ServeCommand extends SessionCommand {
517
509
  stream.end(buffer)
518
510
  })
519
511
 
520
- app.post(
521
- "/upload-image",
522
- express.json({ limit: "10mb" }),
523
- async (req, res) => {
524
- const { image_url, destination } = req.body
525
- if (!image_url || !destination) {
526
- return res
527
- .status(400)
528
- .json({ error: "image_url and destination are required" })
529
- }
530
-
531
- try {
532
- const response = await fetch(image_url)
533
- if (!response.ok) {
534
- return res.status(400).json({
535
- error: `Failed to download image: ${response.statusText}`,
536
- })
537
- }
538
-
539
- const contentType =
540
- response.headers.get("content-type") || "application/octet-stream"
541
- const buffer = await response.arrayBuffer()
542
-
543
- const file = bucket.file(destination)
544
- await file.save(Buffer.from(buffer), {
545
- resumable: false,
546
- contentType,
547
- })
548
-
549
- console.log(`✅ Image uploaded to ${file.name}`)
550
- res.json({ message: "Image uploaded successfully", path: file.name })
551
- } catch (error) {
552
- console.error("❌ upload-image error:", error)
553
- res.status(500).json({ error: (error as Error).message })
554
- }
555
- }
556
- )
557
-
558
512
  const upload = createUploadMiddleware()
559
513
 
560
514
  app.post("/upload-image-file", upload.single("file"), async (req, res) => {
@@ -859,28 +813,50 @@ export default class ServeCommand extends SessionCommand {
859
813
  const courseSlug = req.query.slug
860
814
  const lang = req.query.lang || "us"
861
815
 
816
+ if (!courseSlug) {
817
+ return res.status(400).json({ error: "Missing courseSlug" })
818
+ }
819
+
862
820
  const basePath = `courses/${courseSlug}/exercises/${slug}/`
863
- const filename = lang === "us" ? "README.md" : `README.${lang}.md`
821
+ const prefix = basePath + "README"
864
822
 
865
- const file = bucket.file(basePath + filename)
823
+ try {
824
+ const [files] = await bucket.getFiles({ prefix })
866
825
 
867
- let contentBuffer
826
+ const readmeFiles = files.map(f => f.name)
868
827
 
869
- try {
870
- contentBuffer = await file.download()
871
- } catch {
872
- if (lang !== "us") {
873
- console.warn(`No README for lang '${lang}', falling back to 'us'`)
874
- const fallbackFile = bucket.file(basePath + "README.md")
875
- contentBuffer = await fallbackFile.download()
876
- } else {
877
- return res.status(404).json({ error: "README not found" })
828
+ if (readmeFiles.length === 0) {
829
+ return res.status(404).json({ error: "No README files found" })
878
830
  }
879
- }
880
831
 
881
- const { attributes, body } = frontMatter(contentBuffer[0].toString())
832
+ const requestedFilename =
833
+ lang === "us" || lang === "en" ?
834
+ `${basePath}README.md` :
835
+ `${basePath}README.${lang}.md`
836
+
837
+ let selectedFile = readmeFiles.find(f => f === requestedFilename)
838
+
839
+ if (!selectedFile) {
840
+ selectedFile = readmeFiles[0]
841
+ console.warn(
842
+ `Requested README not found for lang '${lang}', using '${selectedFile}'`
843
+ )
844
+ }
882
845
 
883
- res.send({ attributes, body })
846
+ let foundLang = "us"
847
+ const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i)
848
+ if (match && match[1]) {
849
+ foundLang = match[1].toLowerCase()
850
+ }
851
+
852
+ const [contentBuffer] = await bucket.file(selectedFile).download()
853
+ const { attributes, body } = frontMatter(contentBuffer.toString())
854
+
855
+ res.send({ attributes, body, lang: foundLang })
856
+ } catch (error) {
857
+ console.error(error)
858
+ res.status(500).json({ error: "Internal server error" })
859
+ }
884
860
  })
885
861
 
886
862
  app.get("/.learn/assets/:file", async (req, res) => {
@@ -914,7 +890,7 @@ export default class ServeCommand extends SessionCommand {
914
890
  console.log(`PUT /exercise/${slug}/file/${fileName}`)
915
891
 
916
892
  const courseSlug = query.slug
917
- console.log("COURSE SLUG", courseSlug)
893
+ // console.log("COURSE SLUG", courseSlug)
918
894
 
919
895
  // Update the file in the bucket
920
896
  const file = await bucket.file(
@@ -922,7 +898,7 @@ export default class ServeCommand extends SessionCommand {
922
898
  )
923
899
  await file.save(req.body)
924
900
  const created = await file.exists()
925
- console.log("File updated", created)
901
+ // console.log("File updated", created)
926
902
  res.send({
927
903
  message: "File updated",
928
904
  created,
@@ -1420,12 +1396,30 @@ export default class ServeCommand extends SessionCommand {
1420
1396
 
1421
1397
  copyDir(uiSrc, buildRoot)
1422
1398
 
1399
+ const availableLangs = Object.keys(config.title)
1400
+
1401
+ let selectedLang = "us"
1402
+ let title = ""
1403
+ if (availableLangs.includes("us")) {
1404
+ title = config.title.us
1405
+ } else {
1406
+ // Select the first available lang
1407
+ title = config.title[availableLangs[0]]
1408
+
1409
+ selectedLang = availableLangs[0]
1410
+ }
1411
+
1412
+ console.log(config.description, "CONFIG DESCRIPTION")
1413
+ // console.log(availableLangs, "AVAILABLE LANGs")
1414
+ // console.log(selectedLang, "SELECTED LANG")
1415
+ // console.log(title, "TITLE")
1416
+
1423
1417
  // 5) Inyectar placeholders en index.html
1424
1418
  const idxTpl = fs.readFileSync(path.join(uiSrc, "index.html"), "utf-8")
1425
1419
  const idxHtml = idxTpl
1426
- .replace(/{{title}}/g, config.title.us)
1427
- .replace(/<title>.*<\/title>/, `<title>${config.title.us}</title>`)
1428
- .replace(/{{description}}/g, config.description.us)
1420
+ .replace(/{{title}}/g, title)
1421
+ .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
1422
+ .replace(/{{description}}/g, config.description[selectedLang])
1429
1423
  .replace(
1430
1424
  /{{preview}}/g,
1431
1425
  fixPreviewUrl(slug, "") ||
@@ -1 +1 @@
1
- .lesson-container-component{max-width:1145px;margin:0 auto;padding:0 15px;overflow-y:scroll;color:var(--read-font-color);display:flex;flex-direction:column;gap:10px;line-height:1.5rem}.simple-button-svg{max-height:100%!important;display:flex;align-items:center;gap:10px;font-size:var(--font-size-medium);opacity:1;transition:opacity .1s ease-in-out;border:1px solid transparent}.simple-button-svg:hover{opacity:1}.simple-button-svg.big{padding:10px 20px!important}.simple-button-svg.bg-success svg path{stroke:#fff!important}.simple-button-svg.bg-blue svg path{stroke:#fff!important}.simple-button-svg.small{padding:5px 15px}.simple-button-svg.mini{padding:0}.simple-button-svg.mini svg{max-height:20px!important;max-width:20px!important}.simple-button-svg:disabled{opacity:.5;cursor:not-allowed}.simple-button-svg svg{max-height:30px!important;max-width:30px!important}.simple-button-svg img{max-height:18px!important;max-width:18px!important;filter:saturate(90%)}.feedback-container{background-color:#1f1f1fd1;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);position:absolute;z-index:2;width:100%!important;min-height:100%!important}.feedback-component{width:min(99%,600px);background-color:#fff;padding:10px;border-radius:10px;position:absolute;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);top:10%;display:flex;flex-direction:column;gap:13px;left:50%;transform:translate(-50%)}.feedback-component>.-header{font-weight:700;padding:5px;display:flex;align-items:center;justify-content:space-between}.feedback-component>.-header>button{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600}.feedback-component>p{font-size:16px}.feedback-component>.-content{padding:10px;background-color:#f9f9f9}.feedback-component>.-footer{padding:10px;display:flex;flex-direction:column;text-align:center}.feedback-component>.-footer>div{display:flex;justify-content:space-around}#socket-disconnected{display:none}.test-button{background-color:red;display:flex;align-items:center;padding:10px;border-radius:10px;color:#ff0;font-weight:700}.button{background-color:var(--color-active);border-radius:7px;color:#fff;padding:10px}.button:hover{color:#fff}.text-center{text-align:center}.centered{margin-inline:auto}.on-hover-active:hover{background-color:var(--color-active);color:#fff}.rounded{border-radius:var(--standard-border-radius)}.rounded-medium{border-radius:10px!important}.rounded-big{border-radius:15px!important}.rigo-thumbnail{position:fixed;bottom:20px;cursor:pointer;right:10px;background-color:var(--color-blue-rigo);border-radius:50%;width:50px;height:50px;display:flex;justify-content:center;align-items:center;z-index:2;border:var(--read-font-color) 2px solid}.quiz-button{padding:10px;border-radius:10px;border:1px solid var(--color-active);width:fit-content;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;gap:10px}.rigo-toggle{cursor:pointer;width:40px;height:40px;display:flex;justify-content:center;align-items:center;border-radius:var(--standard-border-radius)}@media only screen and (min-width: 768px){.rigo-toggle{border-radius:0;border-top-left-radius:var(--standard-border-radius);border-top-right-radius:var(--standard-border-radius)}}.quiz-container{display:flex;flex-direction:column;gap:10px;padding:10px;border-radius:10px}.quiz-container .button-wrapper{margin-top:10px;position:sticky;bottom:50px;padding:10px;display:flex;justify-content:right}.quiz-answer{padding:10px;border-radius:50vh;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;gap:10px}.quiz-answer-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:22px;min-width:22px;height:22px;min-height:22px;border-radius:50%;position:relative;box-sizing:border-box;display:flex;justify-content:center;align-items:center}.quiz-answer-checkbox:empty{background-color:transparent;border:1px solid var(--color-active)}.quiz-answer-checkbox.selected:empty{background-color:var(--bg-color);border:1px solid var(--color-active)}.quiz-answer-checkbox.selected:empty:after{content:"";position:absolute;width:11px;height:11px;background-color:var(--color-active);border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box}.language-component{width:fit-content!important;border:1px solid var(--bg-color);padding:7px;border-radius:10px;background-color:transparent;position:relative}.language-dropdown{display:flex;position:absolute;top:101%;left:50%;transform:translate(-50%);border:1px solid var(--color-hovered);padding:6px;gap:5px;border-radius:9px;flex-direction:column;z-index:3;background-color:var(--bg-color)}.language-dropdown>button{display:flex;padding:2px;gap:7px;align-items:center}.language-dropdown>button img{width:21px;height:16px;border-radius:3px}.language-component>button{display:flex;gap:6px;align-items:center}.z-index-2{z-index:2}.w-min-content{width:fit-content}.nowrap{white-space:nowrap}:root{--bg-color-dark-gray: #a1a1a1;--bg-color: #f9f9f9;--app-bg-color: white;--color-active: #02a9ea;--header-height: 90px;--4geeks-yellow: #ffd900;--color-warning: #ffd900;--opaque-blue-editor: #a5d9f8;--color-blue-opaque: #eef9fe;--heavy-blue: #9fbdf0;--color-blue: #c1dfed;--soft-blue: #eef9fe;--color-blue-rigo: #0084ff;--tabs-bg-color: #f4faff;--color-hovered: rgba(224, 224, 224, .665);--light-grey: #dadada;--color-success: #21b761;--color-fail: #eb5757;--bg-color-code: #f1fcffd5;--link-inactive-color: #c1c1c1;--backdrop-background: rgba(0, 0, 0, .7);--soft-green: #a4ffbd;--soft-red: #ffbebe;--modals-bg-color: var(--bg-color);--font-color-secondary: #9c9c9c;--font-size-small: 16px;--font-size-mini: 12px;--font-size-medium: 18px;--app-width: min(100%, 1111px);--read-font-color: black;--font-color-secondary: #4c648f;--gray-blue-color: #9fbdf0;--dropdown-bg-color: white;--standard-border-radius: 8px;--bg-1: #fafdff;--bg-2: #f3fafe;--white: #ffffff;--sidebar-bg-color: #e4e8ee;font-size:16px}:root:has(main.dark){font-size:16px;--bg-color-dark-gray: #a1a1a1;--bg-color: #111f39;--app-bg-color: #111f39;--app-bg-color-opaque: #00041a38;--color-active: #02a9ea;--4geeks-yellow: #ffd900;--opaque-blue-editor: #a5d9f8;--soft-blue: #dff5ff;--color-blue-opaque: #012c57;--color-hovered: rgba(95, 95, 95, .311);--color-success: #21b761;--color-fail: #eb5757;--bg-color-code: #2d3748;--link-inactive-color: #a9a9a9;--backdrop-background: rgba(0, 0, 0, .7);--tabs-bg-color: #1e1e1e;--font-color-secondary: #9c9c9c;--font-size-small: 16px;--font-size-medium: 18px;--dropdown-bg-color: var(--bg-color);--read-font-color: white;--font-color-secondary: #6e90d1;--gray-blue-color: #9fbdf0;--white: #000000;--bg-1: #111f39;--bg-2: #1a2d50;--sidebar-bg-color: #131b25}*{margin:0;padding:0;box-sizing:border-box;font-family:Inter,sans-serif}html{font-size:14px;font-family:Inter,sans-serif;overflow-x:hidden;overflow-y:hidden}html:has(main.dark){color-scheme:dark light}body{background-color:var(--bg-color);overflow-x:hidden}img{width:100%}button{border:0;background:transparent}h1{font-size:26px;font-weight:700}hr{margin-top:15px}pre{border-left:2px solid var(--color-active);overflow:auto;padding:10px!important;margin:0!important;border-radius:0!important}code:not(pre code){padding:2px 6px;border-radius:5px;background-color:#cff3ff;color:#001926}li{padding-left:0!important;margin-left:20px!important}ul>li{list-style-type:disc}ol>li{list-style-type:decimal}blockquote{border-left:2px solid var(--color-active);padding:1px 10px;border-radius:5px;background-color:var(--bg-2)}button{cursor:pointer}table{border-collapse:collapse;width:100%}th{background-color:var(--bg-color-code);padding:6px;color:var(--read-font-color);border:1px solid rgb(130,130,130)}td{border:1px solid rgb(130,130,130);text-align:center;padding:4px}h1,h2,h3,h4,h5,h6,p{margin-block:15px;line-height:1.7}form button{width:fit-content;padding:7px;cursor:pointer;border-radius:6px}form input{border:1px solid gray;border-radius:8px;padding:10px;width:100%}a{word-break:break-all}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-thumb{background:rgba(0,0,0,.433)}::-webkit-scrollbar-thumb:hover{background:var(--color-active)}.pill{border-radius:7px;padding:5px;display:flex;align-items:center}.bg-blue{background-color:var(--color-active)!important;color:#fff}.border-blue{border:1px solid var(--color-blue-rigo)}.border-none{border:none!important}.color-blue{color:var(--color-active)}.bg-blue-rigo{background-color:var(--color-blue-rigo)!important}.bg-secondary{background-color:#e7e7e7c2}.scrolleable{overflow-y:auto!important}.blue-circle{background-color:var(--color-active);border-radius:50%;padding:10px;margin-left:10px;width:40px;height:40px;position:relative}.blue-circle>*{position:absolute;left:50%;font-size:10px;color:#fff;top:50%;transform:translate(-50%,-50%)}.pos-relative{position:relative}.pos-absolute{position:absolute}.bg-fail{background-color:var(--color-fail)!important}.bg-fail .set-path-fill path{fill:#fff}.bg-success{background-color:var(--color-success)!important}.dropdown{display:flex;flex-direction:column;position:relative}.dropdown-content{display:none;position:absolute;min-width:230px}.dropdown:hover .dropdown-content{display:flex;flex-direction:column;background-color:var(--dropdown-bg-color);padding:5px;width:fit-content;border-radius:var(--standard-border-radius)}.dropdown.up .dropdown-content{bottom:100%;left:0}.dropdown.down .dropdown-content{top:100%;left:0}.modal-container{width:100%;height:100vh!important;position:absolute;z-index:10;background-color:var(--backdrop-background);display:flex;flex-direction:column;padding:10px}.modal-container>div{display:flex;flex-direction:column;gap:8px;background-color:#fff;padding:10px;position:absolute;top:50%;width:min(99%,750px);left:50%;transform:translate(-50%,-50%);border-radius:10px}.modal-container>div .modal-header{font-weight:bolder;font-size:16px}.modal-container>div .modal-content{background-color:#ece8e8;padding:inherit;border-radius:inherit;position:relative}.float-right{position:absolute;top:10px;right:10px}.text-white{border:white;color:#fff!important;--read-font-color: white}.d-flex{display:flex}.space-between{justify-content:space-between}.justify-center{justify-content:center}.align-center{align-items:center}.palpitate{animation:palpitate 1s ease-in infinite;animation-play-state:running}@keyframes palpitate{0%{opacity:1}0%{opacity:.5}to{opacity:1}}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.separator{justify-content:center;display:flex;color:var(--font-color-secondary);align-items:center;gap:20px}.separator>div{width:100%;height:1px;background-color:var(--font-color-secondary)}.btn-dark{border:1px solid var(--bg-color-dark-gray)}.w-100{width:100%!important}.btn-dark:hover{background-color:var(--color-hovered)}#main-container{width:var(--app-width);margin-inline:auto;height:99dvh}#main-container.iframe-mode{width:100vw!important}@media only screen and (min-width: 1111px){#main-container.iframe-mode{margin-top:0}}.badge{width:100%;text-align:center;padding:10px;border-radius:4px;cursor:pointer}.clickeable:hover{background-color:var(--color-hovered)}.min-width{width:var(--app-width)}.gap-small{gap:5px}.gap-medium{gap:10px}.gap-big{gap:20px}.my-2{margin-block:20px}.my-small{margin-block:10px}.d-none{display:none}@media only screen and (min-width: 769px){.hide-continue-button{display:none!important}}.browser{height:max-content!important;background-color:var(--opaque-blue-editor);padding:3px}.browser-tab{padding:4px 20px;border-radius:5px;background-color:var(--soft-blue);color:var(--color-active);max-width:100%;text-overflow:ellipsis;overflow-x:hidden;white-space:nowrap}.browser-header{background-color:#8585852f;border-radius:5px;width:100%;padding:2px}.browser-body{background-color:var(--app-bg-color);overflow-y:auto;min-height:200px;border-radius:5px;margin-top:3px}.danger-on-hover:hover{background-color:var(--soft-red);color:#fff}.danger-on-hover:hover svg.set-path-fill path{fill:#fff!important}.success-on-hover:hover{background-color:var(--soft-green);color:#000}.success-on-hover:hover svg{--read-font-color: black}.svg-success svg path{stroke:var(--color-success)!important}.svg-danger svg path{stroke:var(--color-fail)!important}.hover:hover{background-color:#a39e9e53!important}.preview-iframe{border-radius:var(--standard-border-radius);color:var(--read-font-color)!important}.padding-medium{padding:10px}.padding-small{padding:5px}.bg-secondary{background-color:var(--color-hovered)}.bg-danger{background-color:var(--color-fail)}.bg-selected{background-color:var(--opaque-blue-editor)}.input{padding:10px;border-radius:8px;border:1px solid var(--color-hovered)}.text-blue{color:var(--color-blue-rigo)}.text-danger{color:var(--color-fail)}.circle-small{width:30px;height:30px;border-radius:50%}.vh100{height:100vh}.overflow-y-hidden{overflow-y:hidden}.justify-end{justify-content:flex-end}.flex-x{display:flex}.font-size-m{font-size:var(--font-size-medium)}.pos-fixed{position:fixed}.hiddenOnMobile{display:none}.active-hr{border-bottom:2px solid var(--color-active)}.inline-auto{margin-inline:auto}.d-block{display:block}.padding-big{padding:20px}.m-0{margin:0}.bg-rigo{background-color:var(--color-blue-rigo)}.bg-gray{background-color:var(--color-hovered)}.conector-blue{position:relative}@media only screen and (min-width: 768px){.hiddenOnMobile{display:block;text-align:center}.conector-blue:after{content:"";position:absolute;width:100%;height:100%;background-color:var(--color-blue-rigo);left:50%;transform:translate(-50%);top:95%}}.svg-white .set-stroke>path{stroke:#fff}.continue-button{animation:show-continue-button 1s ease-in-out forwards}@keyframes show-continue-button{0%{visibility:hidden}to{visibility:visible;display:block}}.opaque-blue-on-hover:hover{background-color:var(--color-blue-opaque)}.info-bubble-container{position:relative;width:fit-content;overflow:visible}.info-bubble-message{display:none;position:absolute;bottom:100%;right:0;background-color:var(--color-blue-rigo);color:#fff;padding:10px;border-radius:5px}.info-bubble-opener:hover+.info-bubble-message{display:block}.info-bubble-message:hover{display:block}.pointer{cursor:pointer}.text-small{font-size:12px}.text-medium{font-size:16px}.text-big{font-size:20px}.text-large{font-size:24px}.margin-children-none>*{margin:0!important}.padding-mini{padding:3px}.circle{border-radius:50%;width:20px;height:20px}.big-circle{border-radius:50%;width:40px;height:40px}.hidden{display:none}.margin-0{margin:0}.bg-warning{background-color:var(--color-warning)}.text-black{color:#000!important}.svg-black svg{--read-font-color: black}.stdout-prefix{color:var(--color-active);margin:0;font-weight:700;font-size:12px}.stdout{background-color:#000;padding:10px;color:#fff}.stdin{background-color:var(--bg-2);padding:10px;color:var(--read-font-color)}.stderr{background-color:#000;padding:10px;color:var(--color-fail)}.flex-y{display:flex;flex-direction:column}.bg-soft-green{color:#000;background-color:var(--soft-green)!important}.bg-soft-red{color:#000;background-color:var(--soft-red)!important}.bg-soft-blue{background-color:var(--soft-blue)!important}.fit-content{width:fit-content}.text-bold{font-weight:700}.border-gray{border:1px solid var(--color-hovered)}.scale-on-hover{transition:scale .3s ease}.scale-on-hover:hover{scale:1.05}.bg-transparent{background-color:transparent}.gray-on-hover{transition:background-color .3s ease}.gray-on-hover:hover{background-color:var(--color-hovered)}.text-dark{color:#181818}.mr-10{margin-right:40px}.wrap-wrap{flex-wrap:wrap}.h-100{height:100%}.z-index-1{z-index:1}.text-secondary{color:var(--font-color-secondary)}.svg-blue svg{--read-font-color: var(--color-blue-rigo)}.blank-input{background:transparent;border:0;padding:8px;font-size:16px}.blank-input::placeholder{color:var(--gray-blue-color)}.active-on-hover{transition:all .3s ease;cursor:pointer}.active-on-hover:hover{background-color:var(--color-blue-rigo);color:#fff;scale:1.01}.active-on-hover:hover svg{--read-font-color: white}.active-on-hover:active{scale:.99}.border-bottom-blue{border-bottom:1px solid var(--opaque-blue-editor)}.bg-1{background-color:var(--bg-1)!important}.bg-2{background-color:var(--bg-2)!important}.bg-white{background-color:var(--white)!important}.margin-left-small{margin-left:10px}.svg-blue{--read-font-color: var(--color-blue-rigo)}.textarea{border:1px solid var(--color-hovered);border-radius:5px;padding:5px;font-size:16px;resize:none}.border-warning{border:1px solid var(--color-warning)}.mermaid{display:flex;justify-content:center}.right-bottom-corner{position:absolute;bottom:10px;right:10px}.text-dark-red{color:var(--color-fail)}.text-dark-red svg{--read-font-color: var(--color-fail)}.text-dark-green{color:var(--color-success)!important}.text-dark-green svg{--read-font-color: var(--color-success)}.margin-left-medium{margin-left:20px}.top-centered{position:absolute;top:-10px;left:50%;transform:translate(-50%)}.bottom-centered{position:absolute;bottom:-10px;left:50%;transform:translate(-50%)}.align-self-end{align-self:flex-end}.row-reverse{flex-direction:row-reverse}.vertical-line{height:20px;width:1px;background-color:#0060ba;display:inline-block}.big-svg svg{width:50px!important;height:50px!important}.padding-x-small{padding-inline:10px}.d-inline-flex{display:inline-flex}.bg-lesson{background-color:var(--app-bg-color)}.above-all{z-index:1000}.border-heavy-blue{border:1px solid var(--heavy-blue)}.text-trimmed{white-space:nowrap;word-break:break-all;overflow:hidden;text-overflow:ellipsis}.w-150px{width:150px}.w-200px{width:200px}.w-250px{width:min(250px,100%)}@media only screen and (max-width: 768px){.hidden-mobile{display:none!important}}.rounded-full{border-radius:50%}.text-7xl{font-size:4rem;font-weight:900;font-family:Inter,sans-serif;line-height:1.4;letter-spacing:-.01em}.px-big{padding-inline:60px}.mt-50px{margin-top:50px}.h-fit-content{height:fit-content}.h-full{height:70vh}.preview-card{max-width:560px;position:relative}.preview-card .click{margin-inline:auto;display:block;background-color:transparent!important;display:flex;justify-content:center;height:100%;position:absolute;top:0;left:0;width:100%;align-items:center;cursor:pointer;font-size:100px;animation-fill-mode:backwards}.preview-card .click:hover{background-color:#00000080;animation:scaleOnHover .5s ease 1 both}@keyframes scaleOnHover{0%{scale:1}to{scale:1.05}}.video-modal{display:flex;justify-content:center;align-items:center;position:fixed;top:0;left:0;width:100%;height:100%;background-color:var(--backdrop-background);z-index:1}.video-modal .modal-content{position:relative;background-color:transparent;display:flex;flex-direction:column;border-radius:8px;box-shadow:0 0 20px #9999994d;width:fit-content}.video-modal .click svg{width:150px}.video-modal .close{background-color:var(--color-active);margin-top:10px;border-radius:10px;font-size:21px;cursor:pointer;text-align:center;padding:10px;width:100%;opacity:.8;color:#fff;font-weight:600}.video-modal .close:hover{opacity:1;background-color:var(--color-active)}.chat-modal{overflow-y:hidden;position:fixed;z-index:2;bottom:10px;right:50%;transform:translate(50%)}.chat-tab{background-color:#fff;overflow-y:auto;display:flex;flex-direction:column;justify-content:space-between;width:min(100vw - 5px,460px)!important;margin-inline:auto}.chat-messages{overflow-y:scroll;min-height:min(450px,50vh);padding:10px;max-height:calc(100dvh - 200px)!important}@media (max-width: 768px){.chat-tab{width:calc(100vw - 20px)!important;border-radius:0}.chat-messages{min-height:unset;max-height:calc(100dvh - 100px)}}.chat-tab-header{display:flex;background-color:var(--color-blue-rigo);justify-content:space-between;align-items:center;height:50px;border-radius:10px 10px 0 0;padding:10px}.chat-header{position:relative;align-items:center;justify-content:center;text-align:center}.chat-header button{color:var(--background-color-code);position:absolute;top:50%;right:0;transform:translateY(-50%)}.chat-input{display:flex;position:relative;width:100%;align-items:center;background-color:#d8e2f0;padding:10px;gap:10px}.chat-input input{width:100%;padding:10px 40px 10px 10px;border-radius:8px;border:0;outline:none;background-color:#fff;color:#000}.chat-input button{display:flex;border-radius:50%;right:10px;border:1px solid var(--font-color-secondary);background-color:var(--color-blue-rigo)}.chat-input button svg path{stroke:var(--font-color-secondary)}.chat-input button:hover{background-color:#02a8ea;color:var(--read-font-color)}.chat-input :hover svg path{stroke:var(--read-font-color)}.chat-footer{font-size:16px;color:var(--read-font-color);position:relative;display:flex;justify-content:end}.chat-footer:has(.informative-opener:hover) .informative-message{display:block}.informative-opener{bottom:calc(100% + 10px);right:10px;opacity:.4}.chat-footer .informative-message{display:none;position:absolute;bottom:calc(100% + 50px);background-color:var(--app-bg-color);border:1px solid var(--font-color-secondary);border-radius:10px;padding:10px}.next-button{background-color:#9f9f9f;margin-top:5px;border-radius:7px;font-weight:600;color:#000;padding:10px}.message{background-color:var(--soft-blue);padding:10px;color:var(--color-blue-rigo);border-radius:9px;margin-top:5px;line-height:25px;word-break:break-word}.message.user{background-color:#f5f5f57b;color:#000}.message p:not(:first-child){margin-top:15px}.alert{background-color:var(--4geeks-yellow);padding:3px 10px;border-radius:10px;color:#000;font-weight:700;text-align:center}.self-closing-modal{position:fixed;top:0;left:0;background-color:var(--backdrop-background);width:100vw!important;height:100%!important;display:grid;place-content:center;z-index:2}.self-closing-modal>div.modal-content{display:block;border-radius:20px;flex-direction:column;background-color:var(--modals-bg-color);padding:20px;width:min(600px,98vw);gap:10px;margin-inline:auto;overflow:auto;max-height:95vh;position:relative}.self-closing-modal .modal-closer{position:absolute;right:20px;top:25px;z-index:2;cursor:pointer}.icon-component{background-color:red}.loader{display:flex;align-items:center;gap:10px;justify-content:center;animation:glowing 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.loader-icon{width:40px;height:40px;border:2px solid var(--loader-color);border-top-color:transparent;position:relative;display:flex;align-items:center;justify-content:center}.loader-icon:after{content:"";display:block;width:100%;top:0;left:0;position:absolute;height:100%;border:2px solid var(--color-hovered);border-top:2px solid var(--color-active);border-radius:50%;animation:spin 2s linear infinite}@keyframes glowing{0%{opacity:.6}to{opacity:1}}.input-modal{text-align:center;background-color:var(--modals-bg-color);color:var(--read-font-color);padding:20px;display:flex;flex-direction:column;gap:10px}.presentator{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(141,141,141,.402);z-index:0;cursor:initial}._badge{position:fixed;width:min(90%,330px);border-radius:5px;text-align:left;background-color:#fff;border:1px solid rgba(127,127,127,.3);padding:15px;top:50vh;left:50%;z-index:2;box-shadow:0 4px 8px #0000001a}._badge>h2{color:#000;margin-bottom:10px;font-size:25px}._badge>div._content>*{margin-top:5px;line-height:1.5rem}._badge>._footer{display:flex;justify-content:space-between;flex-direction:row}._badge>p{color:#000;font-size:1rem;font-weight:400;margin-top:0}._container_1cky8_1{width:100%;background-color:#e0e0e0;border-radius:4px;overflow:hidden}._filler_1cky8_15{height:100%;background-color:var(--color-blue-rigo);border-radius:4px 0 0 4px;transition:width .3s ease}.reset-modal{text-align:center}.reset-modal>section{display:flex;justify-content:center;width:100%;gap:20px}.login-modal{font-size:16px}.login-modal h2{text-align:center}.login-modal>div div:has(button){display:flex;align-items:center;justify-content:center;gap:5px}.login-modal button,.login-modal input{font-size:16px}._header_1u10v_1{display:flex;justify-content:space-between;padding-inline:10px;padding-block:10px;align-items:center;background-color:var(--app-bg-color);border-top-left-radius:10px;border-top-right-radius:10px}._header_1u10v_1>section{display:flex;gap:8px}._header_1u10v_1>section:last-child{display:flex;gap:15px}._header_1u10v_1>section>button:disabled{cursor:not-allowed;opacity:.5}._container_ezryg_1{display:flex;gap:8px;background-color:var(--bg-color);flex-wrap:nowrap;min-height:calc(100dvh - 200px);max-height:calc(100dvh - var(--header-height))}._container_ezryg_1>div{width:65%}._container_ezryg_1>div:only-child{width:100%}._content_ezryg_31{display:flex;position:relative}._content_ezryg_31>section{padding:8px;width:100%;max-height:90vh;overflow:auto}._appTabs_ezryg_55{display:flex;background-color:var(--tabs-bg-color);justify-content:space-between;position:absolute;top:0;left:0;width:100%}._appTabs_ezryg_55>div{width:100%;text-align:center;padding:10px;color:#728ec0;border-bottom:1px solid transparent;cursor:pointer}._appTabs_ezryg_55>div[data-visible=true]{background-color:var(--bg-color);color:var(--color-active);border-bottom:3px solid var(--color-active)}._hiddenOnMobile_ezryg_103{display:none}@media only screen and (min-width: 768px){._container_ezryg_1{gap:8px}._content_ezryg_31>section{padding:8px;width:100%}._appTabs_ezryg_55{display:none}._hiddenOnMobile_ezryg_103{display:block;text-align:center}}.tabs{display:flex;align-items:center;gap:2px}.tab{display:flex;background-color:var(--bg-color);border-top-right-radius:6px;border-top-left-radius:6px;cursor:pointer;transition:background-color .3s ease;padding:5px 6px}.tab.active{background-color:var(--opaque-blue-editor)}.tab.active button{color:var(--color-active)}.editor{border:7px solid var(--opaque-blue-editor);border-radius:0 5px 0 0;position:relative}.editor-monaco .view-lines,.editor-monaco .margin-view-overlays{height:min(400px,fit-content)!important}.terminal{border:3px solid var(--opaque-blue-editor);border-top:0;overflow-y:auto;position:relative;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.terminal.html{height:min(400px,fit-content);overflow-y:auto;border:none}.terminal.only{margin-top:0;border:0;max-height:70vh;border-radius:5px}.terminal.only .editor-footer{margin-top:20px;display:block;position:relative}.terminal.hidden{display:none}.terminal>h5{border-bottom:1px solid #dadada;display:flex;justify-content:space-between;align-items:center;margin:0;font-size:16px}.terminal>pre{background-color:var(--bg-color);border:none;max-width:100%;height:fit-content F;word-break:break-word!important;white-space:pre-wrap}.terminal>pre>code{word-wrap:break-word}.editor-footer{background-color:var(--app-bg-color);position:absolute;bottom:8px;width:calc(100% - 16px);left:8px;border-radius:8px;font-size:12px}.editor-footer .compiler{background-color:var(--color-active);color:#fff!important}.editor-footer .compiler .set-stroke path{stroke:#fff}.editor-footer.UNMODIFIED,.editor-footer.MODIFIED{background-color:var(--modals-bg-color)}.editor .editor-footer.success{background-color:var(--soft-green)}.editor .editor-footer.error{color:#fff!important;background-color:var(--soft-red)}.editor-footer .not-started{display:flex;align-items:center;gap:9px;color:var(--color-active);padding:4px;justify-content:space-between;font-size:12px}.editor-footer .not-started span{font-size:12px}.editor-footer .not-started>div:first-child{display:flex;align-items:center;gap:5px}.editor-footer .footer-actions{display:flex;align-items:center;justify-content:space-between;gap:4px;padding:4px}.editor-footer .footer-actions>div>button,.editor-footer .footer-actions>button,.editor-footer .footer-actions>div{width:100%;border-radius:4px;display:flex;font-size:12px;justify-content:center;align-items:center;gap:5px;color:var(--color-active)}.editor-footer.success{background-color:var(--soft-green)}.editor-footer.success .footer-actions>button svg path{stroke:var(--color-success)}.editor-footer.success .footer-actions>div>button>svg path{stroke:var(--color-success)}.editor-footer.success .footer-actions>div{color:var(--color-success)}.editor-footer.success .footer-actions>button{color:#000}.editor-footer.success .footer-actions>div>button{color:#000}.editor-footer.success .editor-footer-child .set-path-fill path{fill:var(--color-success)}.editor-footer.success .compiler{background-color:var(--color-success);color:#fff!important}.editor-footer.success .compiler .set-path-fill path{stroke:#fff}.editor-footer.error{background-color:var(--soft-red)}.editor-footer.error .footer-actions>button svg path{stroke:var(--color-fail)}.editor-footer.error .footer-actions>div>button>svg path{stroke:var(--color-fail)}.editor-footer.error .footer-actions>div>button{color:var(--color-fail)}.editor-footer.error .footer-actions>button{color:var(--color-fail)}.editor-footer.error .footer-actions>div{color:var(--color-fail)}.editor-footer.error .editor-footer-child .set-path-fill path{fill:var(--color-fail)}.editor-footer.error .compiler{background-color:var(--color-fail);color:#fff!important}.editor-footer.error .compiler .set-path-fill path{stroke:#fff}.footer-actions button{font-size:15px!important}.app-header{animation:scale-navbar auto linear both;animation-timeline:scroll();animation-range:10px 150px;position:sticky;top:0}.app-header:hover{opacity:1!important}.navbar-component{padding:10px;background-color:var(--bg-color);display:flex;width:100%;transition:all 2s;margin:0 auto;max-width:1145px;justify-content:space-between}.navbar-component>section{display:flex;gap:3px;align-items:center}.navbar-component>section>button,.navbar-component>section>div{border:1px solid var(--color-active);border-radius:5px}.lesson-options{display:flex;align-items:center;background-color:var(--bg-color);margin:0 auto;max-width:1145px;padding:8px;justify-content:space-between}.lesson-options>div{display:flex;gap:10px;align-items:center}.lesson-options button:disabled{opacity:.5;cursor:not-allowed}@keyframes scale-navbar{to{opacity:0}}.feedback-dropdown{position:absolute;width:250px!important;padding:2px;border:1px solid var(--color-active);background-color:var(--modals-bg-color);border-radius:7px;max-width:300px;font-size:var(--font-size-small);display:flex;gap:5px;align-items:baseline!important;z-index:4;flex-direction:column}.feedback-dropdown.up{bottom:103%;right:0}.feedback-dropdown.down{top:103%;left:-75%}.feedback-dropdown>*{width:fit-content}.feedback-dropdown>button{color:var(--color-active);width:100%;padding:7px;text-align:left;display:flex;justify-content:left;align-items:center}.feedback-dropdown>button:hover{background-color:var(--color-blue-opaque)}.feedback-dropdown>p{padding:3px;background-color:var(--bg-color);margin:0;font-size:var(--font-size-mini);color:var(--read-font-color)}.feedback-dropdown>p>a{font-weight:600;color:var(--color-active);cursor:pointer}#feedback-button{min-width:fit-content}.sidebar-component{position:absolute;left:0%;font-size:17px;z-index:2;background-color:var(--sidebar-bg-color);display:flex;flex-direction:column;align-items:center;width:100%}@media (min-width: 768px){.sidebar-component{width:min(100vw - 5px,460px)!important;position:relative;height:calc(100vh - var(--header-height))}.sidebar-component .footer{width:100%;position:fixed;bottom:0}}.sidebar-component section h2{text-align:center;padding:10px;margin-block:0;width:100%}.sidebar-component>section:not(:last-child){display:flex;justify-content:space-between;padding:2px 14px}.sidebar-component .footer{background-color:transparent;position:relative;width:100%;padding:15px;display:flex;align-items:center;justify-content:space-between}.sidebar-component .footer>a{padding:10px;text-decoration:none;color:var(--read-font-color);display:block;border-radius:8px}.sidebar-component .footer>a:hover{background-color:var(--color-hovered)}.sidebar-component .exercise-list{display:flex;flex-direction:column;width:100%;gap:5px;padding:5px;max-height:83vh!important;overflow-y:scroll;width:var(--app-width);margin-inline:auto}.exercise-list .exercise-card{background-color:var(--bg-1);display:flex;padding:3px 5px;cursor:pointer;width:100%;justify-content:space-between;font-size:18px;border-radius:10px;align-items:center;position:relative}.exercise-circle{background-color:var(--bg-1);border-radius:50%;width:40px;height:40px;display:flex;align-items:center;justify-content:center;color:#0097cf;padding:10px}.exercise-circle.done{background-color:#0097cf;color:#fff}.sidebar-component .exercise-list .exercise-card:hover{background-color:var(--bg-2)}.sidebar-component .exercise-list .exercise-card:active{background-color:var(--color-blue-opaque);transition:all .3s ease}.sidebar-disappear{animation:disappear-4-right .4s ease 1 forwards}@keyframes appear-4-right{0%{left:101%}to{left:0}}@keyframes disappear-4-right{0%{left:0}to{left:101%}}.bg-blue-opaque{background-color:var(--color-blue-opaque)}.lesson-content{padding-bottom:70px;font-size:20px;padding-inline:16px;line-height:2rem;max-height:100vh!important}.lesson-content img{margin:5px auto;max-width:750px;display:block}.lesson-content h1{font-size:32px}.lesson-content h2{font-size:25px}.lesson-content h3{font-size:20px}.creator-wrapper{position:relative}.creator-wrapper .display-on-hover{display:none}.creator-wrapper:hover .display-on-hover{display:block}.inverted{transform:scaleY(-1)}.inverted>*{transform:scaleY(-1)}.creator-options{display:flex;border-radius:5px;gap:3px;position:absolute;top:0;left:0;flex-direction:column;z-index:1000}.creator-options-buttons{background-color:var(--color-blue-opaque);width:fit-content;padding:5px;border-radius:5px}.text-in-editor{position:relative}.creator-options-opener{display:none;position:absolute;right:100%;top:5px;z-index:1000;padding:2px;border-radius:5px;background-color:var(--app-bg-color)}.creator-wrapper:hover>.text-in-editor>.creator-options-opener{display:block}.creator-wrapper:hover{background-color:var(--color-blue-opaque);border-radius:2px}.creator-target-content{color:var(--color-success)}.creator-target{border-radius:5px}.code-buttons{background-color:var(--color-blue-opaque);border-top-left-radius:5px;border-top-right-radius:5px;padding-left:10px;padding-right:10px;font-size:12px;color:var(--color-blue-rigo)}.custom-code-block{position:relative}.execution-result{background-color:var(--color-blue-opaque);padding:10px;border-bottom-left-radius:5px;border-bottom-right-radius:5px;font-size:12px;color:var(--color-success)}.katex{font-size:1.2rem;line-height:2rem}.rigo-input{border-radius:5px;font-size:16px;padding:5px;width:min(600px,90vw)!important;display:flex;align-items:center;gap:5px}.rigo-button{background:linear-gradient(132deg,#0fb0fc,#022cc2);border:2px solid white;color:var(--white);opacity:1;border-radius:50%;padding:5px;display:flex;justify-content:center;align-items:center;width:50px;height:50px;margin-right:-12px;z-index:1}.rigo-textarea{border:0;background:#c8dbfc;font-size:16px;padding:7px;outline:none;width:100%;border-radius:10px;color:#000}.rigo-textarea::placeholder{color:var(--color-blue-rigo)}._button_1y12h_5{background-color:var(--color-blue-rigo);color:#fff;border:none;padding:.5rem 1rem;border-radius:.25rem;cursor:pointer;display:flex;align-items:center}._icon_1y12h_27{margin-left:.5rem;color:currentColor}._menu_1y12h_37{position:absolute;right:0;margin-top:.25rem;width:15rem;background-color:#dce9ff;border-radius:.25rem;box-shadow:0 2px 8px #0000001a;z-index:100;padding:.5rem 10px}
1
+ .lesson-container-component{max-width:1145px;margin:0 auto;padding:0 15px;overflow-y:scroll;color:var(--read-font-color);display:flex;flex-direction:column;gap:10px;line-height:1.5rem}.simple-button-svg{max-height:100%!important;display:flex;align-items:center;gap:10px;font-size:var(--font-size-medium);opacity:1;transition:opacity .1s ease-in-out;border:1px solid transparent}.simple-button-svg:hover{opacity:1}.simple-button-svg.big{padding:10px 20px!important}.simple-button-svg.bg-success svg path{stroke:#fff!important}.simple-button-svg.bg-blue svg path{stroke:#fff!important}.simple-button-svg.small{padding:5px 15px}.simple-button-svg.mini{padding:0}.simple-button-svg.mini svg{max-height:20px!important;max-width:20px!important}.simple-button-svg:disabled{opacity:.5;cursor:not-allowed}.simple-button-svg svg{max-height:30px!important;max-width:30px!important}.simple-button-svg img{max-height:18px!important;max-width:18px!important;filter:saturate(90%)}.feedback-container{background-color:#1f1f1fd1;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);position:absolute;z-index:2;width:100%!important;min-height:100%!important}.feedback-component{width:min(99%,600px);background-color:#fff;padding:10px;border-radius:10px;position:absolute;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);top:10%;display:flex;flex-direction:column;gap:13px;left:50%;transform:translate(-50%)}.feedback-component>.-header{font-weight:700;padding:5px;display:flex;align-items:center;justify-content:space-between}.feedback-component>.-header>button{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:600}.feedback-component>p{font-size:16px}.feedback-component>.-content{padding:10px;background-color:#f9f9f9}.feedback-component>.-footer{padding:10px;display:flex;flex-direction:column;text-align:center}.feedback-component>.-footer>div{display:flex;justify-content:space-around}#socket-disconnected{display:none}.test-button{background-color:red;display:flex;align-items:center;padding:10px;border-radius:10px;color:#ff0;font-weight:700}.button{background-color:var(--color-active);border-radius:7px;color:#fff;padding:10px}.button:hover{color:#fff}.text-center{text-align:center}.centered{margin-inline:auto}.on-hover-active:hover{background-color:var(--color-active);color:#fff}.rounded{border-radius:var(--standard-border-radius)}.rounded-medium{border-radius:10px!important}.rounded-big{border-radius:15px!important}.rigo-thumbnail{position:fixed;bottom:20px;cursor:pointer;right:10px;background-color:var(--color-blue-rigo);border-radius:50%;width:50px;height:50px;display:flex;justify-content:center;align-items:center;z-index:2;border:var(--read-font-color) 2px solid}.quiz-button{padding:10px;border-radius:10px;border:1px solid var(--color-active);width:fit-content;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;gap:10px}.rigo-toggle{cursor:pointer;width:40px;height:40px;display:flex;justify-content:center;align-items:center;border-radius:var(--standard-border-radius)}@media only screen and (min-width: 768px){.rigo-toggle{border-radius:0;border-top-left-radius:var(--standard-border-radius);border-top-right-radius:var(--standard-border-radius)}}.quiz-container{display:flex;flex-direction:column;gap:10px;padding:10px;border-radius:10px}.quiz-container .button-wrapper{margin-top:10px;position:sticky;bottom:50px;padding:10px;display:flex;justify-content:right}.quiz-answer{padding:10px;border-radius:50vh;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;gap:10px}.quiz-answer-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:22px;min-width:22px;height:22px;min-height:22px;border-radius:50%;position:relative;box-sizing:border-box;display:flex;justify-content:center;align-items:center}.quiz-answer-checkbox:empty{background-color:transparent;border:1px solid var(--color-active)}.quiz-answer-checkbox.selected:empty{background-color:var(--bg-color);border:1px solid var(--color-active)}.quiz-answer-checkbox.selected:empty:after{content:"";position:absolute;width:11px;height:11px;background-color:var(--color-active);border-radius:50%;top:50%;left:50%;transform:translate(-50%,-50%);box-sizing:border-box}.language-component{width:fit-content!important;border:1px solid var(--bg-color);padding:7px;border-radius:10px;background-color:transparent;position:relative}.language-dropdown{display:flex;position:absolute;top:101%;left:50%;transform:translate(-50%);border:1px solid var(--color-hovered);padding:6px;gap:5px;border-radius:9px;flex-direction:column;z-index:3;background-color:var(--bg-color)}.language-dropdown>button{display:flex;padding:2px;gap:7px;align-items:center}.language-dropdown>button img{width:21px;height:16px;border-radius:3px}.language-component>button{display:flex;gap:6px;align-items:center}.z-index-2{z-index:2}.w-min-content{width:fit-content}.nowrap{white-space:nowrap}:root{--bg-color-dark-gray: #a1a1a1;--bg-color: #f9f9f9;--app-bg-color: white;--color-active: #02a9ea;--header-height: 90px;--4geeks-yellow: #ffd900;--color-warning: #ffd900;--opaque-blue-editor: #a5d9f8;--color-blue-opaque: #eef9fe;--heavy-blue: #9fbdf0;--color-blue: #c1dfed;--soft-blue: #eef9fe;--color-blue-rigo: #0084ff;--tabs-bg-color: #f4faff;--color-hovered: rgba(224, 224, 224, .665);--light-grey: #dadada;--color-success: #21b761;--color-fail: #eb5757;--bg-color-code: #f1fcffd5;--link-inactive-color: #c1c1c1;--backdrop-background: rgba(0, 0, 0, .7);--soft-green: #a4ffbd;--soft-red: #ffbebe;--modals-bg-color: var(--bg-color);--font-color-secondary: #9c9c9c;--font-size-small: 16px;--font-size-mini: 12px;--font-size-medium: 18px;--app-width: min(100%, 1111px);--read-font-color: black;--font-color-secondary: #4c648f;--gray-blue-color: #9fbdf0;--dropdown-bg-color: white;--standard-border-radius: 8px;--bg-1: #fafdff;--bg-2: #f3fafe;--white: #ffffff;--sidebar-bg-color: #e4e8ee;font-size:16px}:root:has(main.dark){font-size:16px;--bg-color-dark-gray: #a1a1a1;--bg-color: #111f39;--app-bg-color: #111f39;--app-bg-color-opaque: #00041a38;--color-active: #02a9ea;--4geeks-yellow: #ffd900;--opaque-blue-editor: #a5d9f8;--soft-blue: #dff5ff;--color-blue-opaque: #012c57;--color-hovered: rgba(95, 95, 95, .311);--color-success: #21b761;--color-fail: #eb5757;--bg-color-code: #2d3748;--link-inactive-color: #a9a9a9;--backdrop-background: rgba(0, 0, 0, .7);--tabs-bg-color: #1e1e1e;--font-color-secondary: #9c9c9c;--font-size-small: 16px;--font-size-medium: 18px;--dropdown-bg-color: var(--bg-color);--read-font-color: white;--font-color-secondary: #6e90d1;--gray-blue-color: #9fbdf0;--white: #000000;--bg-1: #111f39;--bg-2: #1a2d50;--sidebar-bg-color: #131b25}*{margin:0;padding:0;box-sizing:border-box;font-family:Inter,sans-serif}html{font-size:14px;font-family:Inter,sans-serif;overflow-x:hidden;overflow-y:hidden}html:has(main.dark){color-scheme:dark light}body{background-color:var(--bg-color);overflow-x:hidden}img{width:100%}button{border:0;background:transparent}h1{font-size:26px;font-weight:700}hr{margin-top:15px}pre{border-left:2px solid var(--color-active);overflow:auto;padding:10px!important;margin:0!important;border-radius:0!important}code:not(pre code){padding:2px 6px;border-radius:5px;background-color:#cff3ff;color:#001926}li{padding-left:0!important;margin-left:20px!important}ul>li{list-style-type:disc}ol>li{list-style-type:decimal}blockquote{border-left:2px solid var(--color-active);padding:1px 10px;border-radius:5px;background-color:var(--bg-2)}button{cursor:pointer}table{border-collapse:collapse;width:100%}th{background-color:var(--bg-color-code);padding:6px;color:var(--read-font-color);border:1px solid rgb(130,130,130)}td{border:1px solid rgb(130,130,130);text-align:center;padding:4px}h1,h2,h3,h4,h5,h6,p{margin-block:15px;line-height:1.7}form button{width:fit-content;padding:7px;cursor:pointer;border-radius:6px}form input{border:1px solid gray;border-radius:8px;padding:10px;width:100%}a{word-break:break-all}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-thumb{background:rgba(0,0,0,.433)}::-webkit-scrollbar-thumb:hover{background:var(--color-active)}.pill{border-radius:7px;padding:5px;display:flex;align-items:center}.bg-blue{background-color:var(--color-active)!important;color:#fff}.border-blue{border:1px solid var(--color-blue-rigo)}.border-none{border:none!important}.color-blue{color:var(--color-active)}.bg-blue-rigo{background-color:var(--color-blue-rigo)!important}.bg-secondary{background-color:#e7e7e7c2}.scrolleable{overflow-y:auto!important}.blue-circle{background-color:var(--color-active);border-radius:50%;padding:10px;margin-left:10px;width:40px;height:40px;position:relative}.blue-circle>*{position:absolute;left:50%;font-size:10px;color:#fff;top:50%;transform:translate(-50%,-50%)}.pos-relative{position:relative}.pos-absolute{position:absolute}.bg-fail{background-color:var(--color-fail)!important}.bg-fail .set-path-fill path{fill:#fff}.bg-success{background-color:var(--color-success)!important}.dropdown{display:flex;flex-direction:column;position:relative}.dropdown-content{display:none;position:absolute;min-width:230px}.dropdown:hover .dropdown-content{display:flex;flex-direction:column;background-color:var(--dropdown-bg-color);padding:5px;width:fit-content;border-radius:var(--standard-border-radius)}.dropdown.up .dropdown-content{bottom:100%;left:0}.dropdown.down .dropdown-content{top:100%;left:0}.modal-container{width:100%;height:100vh!important;position:absolute;z-index:10;background-color:var(--backdrop-background);display:flex;flex-direction:column;padding:10px}.modal-container>div{display:flex;flex-direction:column;gap:8px;background-color:#fff;padding:10px;position:absolute;top:50%;width:min(99%,750px);left:50%;transform:translate(-50%,-50%);border-radius:10px}.modal-container>div .modal-header{font-weight:bolder;font-size:16px}.modal-container>div .modal-content{background-color:#ece8e8;padding:inherit;border-radius:inherit;position:relative}.float-right{position:absolute;top:10px;right:10px}.text-white{border:white;color:#fff!important;--read-font-color: white}.d-flex{display:flex}.space-between{justify-content:space-between}.justify-center{justify-content:center}.align-center{align-items:center}.palpitate{animation:palpitate 1s ease-in infinite;animation-play-state:running}@keyframes palpitate{0%{opacity:1}0%{opacity:.5}to{opacity:1}}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.separator{justify-content:center;display:flex;color:var(--font-color-secondary);align-items:center;gap:20px}.separator>div{width:100%;height:1px;background-color:var(--font-color-secondary)}.btn-dark{border:1px solid var(--bg-color-dark-gray)}.w-100{width:100%!important}.btn-dark:hover{background-color:var(--color-hovered)}#main-container{width:var(--app-width);margin-inline:auto;height:99dvh}#main-container.iframe-mode{width:100vw!important}@media only screen and (min-width: 1111px){#main-container.iframe-mode{margin-top:0}}.badge{width:100%;text-align:center;padding:10px;border-radius:4px;cursor:pointer}.clickeable:hover{background-color:var(--color-hovered)}.min-width{width:var(--app-width)}.gap-small{gap:5px}.gap-medium{gap:10px}.gap-big{gap:20px}.my-2{margin-block:20px}.my-small{margin-block:10px}.d-none{display:none}@media only screen and (min-width: 769px){.hide-continue-button{display:none!important}}.browser{height:max-content!important;background-color:var(--opaque-blue-editor);padding:3px}.browser-tab{padding:4px 20px;border-radius:5px;background-color:var(--soft-blue);color:var(--color-active);max-width:100%;text-overflow:ellipsis;overflow-x:hidden;white-space:nowrap}.browser-header{background-color:#8585852f;border-radius:5px;width:100%;padding:2px}.browser-body{background-color:var(--app-bg-color);overflow-y:auto;min-height:200px;border-radius:5px;margin-top:3px}.danger-on-hover:hover{background-color:var(--soft-red);color:#fff}.danger-on-hover:hover svg.set-path-fill path{fill:#fff!important}.success-on-hover:hover{background-color:var(--soft-green);color:#000}.success-on-hover:hover svg{--read-font-color: black}.svg-success svg path{stroke:var(--color-success)!important}.svg-danger svg path{stroke:var(--color-fail)!important}.hover:hover{background-color:#a39e9e53!important}.preview-iframe{border-radius:var(--standard-border-radius);color:var(--read-font-color)!important}.padding-medium{padding:10px}.padding-small{padding:5px}.bg-secondary{background-color:var(--color-hovered)}.bg-danger{background-color:var(--color-fail)}.bg-selected{background-color:var(--opaque-blue-editor)}.input{padding:10px;border-radius:8px;border:1px solid var(--color-hovered)}.text-blue{color:var(--color-blue-rigo)}.text-danger{color:var(--color-fail)}.circle-small{width:30px;height:30px;border-radius:50%}.vh100{height:100vh}.overflow-y-hidden{overflow-y:hidden}.justify-end{justify-content:flex-end}.flex-x{display:flex}.font-size-m{font-size:var(--font-size-medium)}.pos-fixed{position:fixed}.hiddenOnMobile{display:none}.active-hr{border-bottom:2px solid var(--color-active)}.inline-auto{margin-inline:auto}.d-block{display:block}.padding-big{padding:20px}.m-0{margin:0}.bg-rigo{background-color:var(--color-blue-rigo)}.bg-gray{background-color:var(--color-hovered)}.conector-blue{position:relative}@media only screen and (min-width: 768px){.hiddenOnMobile{display:block;text-align:center}.conector-blue:after{content:"";position:absolute;width:100%;height:100%;background-color:var(--color-blue-rigo);left:50%;transform:translate(-50%);top:95%}}.svg-white .set-stroke>path{stroke:#fff}.continue-button{animation:show-continue-button 1s ease-in-out forwards}@keyframes show-continue-button{0%{visibility:hidden}to{visibility:visible;display:block}}.opaque-blue-on-hover:hover{background-color:var(--color-blue-opaque)}.info-bubble-container{position:relative;width:fit-content;overflow:visible}.info-bubble-message{display:none;position:absolute;bottom:100%;right:0;background-color:var(--color-blue-rigo);color:#fff;padding:10px;border-radius:5px}.info-bubble-opener:hover+.info-bubble-message{display:block}.info-bubble-message:hover{display:block}.pointer{cursor:pointer}.text-small{font-size:12px}.text-medium{font-size:16px}.text-big{font-size:20px}.text-large{font-size:24px}.margin-children-none>*{margin:0!important}.padding-mini{padding:3px}.circle{border-radius:50%;width:20px;height:20px}.big-circle{border-radius:50%;width:40px;height:40px}.hidden{display:none}.margin-0{margin:0}.bg-warning{background-color:var(--color-warning)}.text-black{color:#000!important}.svg-black svg{--read-font-color: black}.stdout-prefix{color:var(--color-active);margin:0;font-weight:700;font-size:12px}.stdout{background-color:#000;padding:10px;color:#fff}.stdin{background-color:var(--bg-2);padding:10px;color:var(--read-font-color)}.stderr{background-color:#000;padding:10px;color:var(--color-fail)}.flex-y{display:flex;flex-direction:column}.bg-soft-green{color:#000;background-color:var(--soft-green)!important}.bg-soft-red{color:#000;background-color:var(--soft-red)!important}.bg-soft-blue{background-color:var(--soft-blue)!important}.fit-content{width:fit-content}.text-bold{font-weight:700}.border-gray{border:1px solid var(--color-hovered)}.scale-on-hover{transition:scale .3s ease}.scale-on-hover:hover{scale:1.05}.bg-transparent{background-color:transparent}.gray-on-hover{transition:background-color .3s ease}.gray-on-hover:hover{background-color:var(--color-hovered)}.text-dark{color:#181818}.mr-10{margin-right:40px}.wrap-wrap{flex-wrap:wrap}.h-100{height:100%}.z-index-1{z-index:1}.text-secondary{color:var(--font-color-secondary)}.svg-blue svg{--read-font-color: var(--color-blue-rigo)}.blank-input{background:transparent;border:0;padding:8px;font-size:16px}.blank-input::placeholder{color:var(--gray-blue-color)}.active-on-hover{transition:all .3s ease;cursor:pointer}.active-on-hover:hover{background-color:var(--color-blue-rigo);color:#fff;scale:1.01}.active-on-hover:hover svg{--read-font-color: white}.active-on-hover:active{scale:.99}.border-bottom-blue{border-bottom:1px solid var(--opaque-blue-editor)}.bg-1{background-color:var(--bg-1)!important}.bg-2{background-color:var(--bg-2)!important}.bg-white{background-color:var(--white)!important}.margin-left-small{margin-left:10px}.svg-blue{--read-font-color: var(--color-blue-rigo)}.textarea{border:1px solid var(--color-hovered);border-radius:5px;padding:5px;font-size:16px;resize:none}.border-warning{border:1px solid var(--color-warning)}.mermaid{display:flex;justify-content:center}.right-bottom-corner{position:absolute;bottom:10px;right:10px}.text-dark-red{color:var(--color-fail)}.text-dark-red svg{--read-font-color: var(--color-fail)}.text-dark-green{color:var(--color-success)!important}.text-dark-green svg{--read-font-color: var(--color-success)}.margin-left-medium{margin-left:20px}.top-centered{position:absolute;top:-10px;left:50%;transform:translate(-50%)}.bottom-centered{position:absolute;bottom:-10px;left:50%;transform:translate(-50%)}.align-self-end{align-self:flex-end}.row-reverse{flex-direction:row-reverse}.vertical-line{height:20px;width:1px;background-color:#0060ba;display:inline-block}.big-svg svg{width:50px!important;height:50px!important}.padding-x-small{padding-inline:10px}.d-inline-flex{display:inline-flex}.bg-lesson{background-color:var(--app-bg-color)}.above-all{z-index:1000}.border-heavy-blue{border:1px solid var(--heavy-blue)}.text-trimmed{white-space:nowrap;word-break:break-all;overflow:hidden;text-overflow:ellipsis}.w-150px{width:150px}.w-200px{width:200px}.w-250px{width:min(250px,100%)}@media only screen and (max-width: 768px){.hidden-mobile{display:none!important}}.rounded-full{border-radius:50%}.text-7xl{font-size:4rem;font-weight:900;font-family:Inter,sans-serif;line-height:1.4;letter-spacing:-.01em}.px-big{padding-inline:60px}.mt-50px{margin-top:50px}.h-fit-content{height:fit-content}.h-full{height:70vh}.preview-card{max-width:560px;position:relative}.preview-card .click{margin-inline:auto;display:block;background-color:transparent!important;display:flex;justify-content:center;height:100%;position:absolute;top:0;left:0;width:100%;align-items:center;cursor:pointer;font-size:100px;animation-fill-mode:backwards}.preview-card .click:hover{background-color:#00000080;animation:scaleOnHover .5s ease 1 both}@keyframes scaleOnHover{0%{scale:1}to{scale:1.05}}.video-modal{display:flex;justify-content:center;align-items:center;position:fixed;top:0;left:0;width:100%;height:100%;background-color:var(--backdrop-background);z-index:1}.video-modal .modal-content{position:relative;background-color:transparent;display:flex;flex-direction:column;border-radius:8px;box-shadow:0 0 20px #9999994d;width:fit-content}.video-modal .click svg{width:150px}.video-modal .close{background-color:var(--color-active);margin-top:10px;border-radius:10px;font-size:21px;cursor:pointer;text-align:center;padding:10px;width:100%;opacity:.8;color:#fff;font-weight:600}.video-modal .close:hover{opacity:1;background-color:var(--color-active)}.chat-modal{overflow-y:hidden;position:fixed;z-index:2;bottom:10px;right:50%;transform:translate(50%)}.chat-tab{background-color:#fff;overflow-y:auto;display:flex;flex-direction:column;justify-content:space-between;width:min(100vw - 5px,460px)!important;margin-inline:auto}.chat-messages{overflow-y:scroll;min-height:min(450px,50vh);padding:10px;max-height:calc(100dvh - 200px)!important}@media (max-width: 768px){.chat-tab{width:calc(100vw - 20px)!important;border-radius:0}.chat-messages{min-height:unset;max-height:calc(100dvh - 100px)}}.chat-tab-header{display:flex;background-color:var(--color-blue-rigo);justify-content:space-between;align-items:center;height:50px;border-radius:10px 10px 0 0;padding:10px}.chat-header{position:relative;align-items:center;justify-content:center;text-align:center}.chat-header button{color:var(--background-color-code);position:absolute;top:50%;right:0;transform:translateY(-50%)}.chat-input{display:flex;position:relative;width:100%;align-items:center;background-color:#d8e2f0;padding:10px;gap:10px}.chat-input input{width:100%;padding:10px 40px 10px 10px;border-radius:8px;border:0;outline:none;background-color:#fff;color:#000}.chat-input button{display:flex;border-radius:50%;right:10px;border:1px solid var(--font-color-secondary);background-color:var(--color-blue-rigo)}.chat-input button svg path{stroke:var(--font-color-secondary)}.chat-input button:hover{background-color:#02a8ea;color:var(--read-font-color)}.chat-input :hover svg path{stroke:var(--read-font-color)}.chat-footer{font-size:16px;color:var(--read-font-color);position:relative;display:flex;justify-content:end}.chat-footer:has(.informative-opener:hover) .informative-message{display:block}.informative-opener{bottom:calc(100% + 10px);right:10px;opacity:.4}.chat-footer .informative-message{display:none;position:absolute;bottom:calc(100% + 50px);background-color:var(--app-bg-color);border:1px solid var(--font-color-secondary);border-radius:10px;padding:10px}.next-button{background-color:#9f9f9f;margin-top:5px;border-radius:7px;font-weight:600;color:#000;padding:10px}.message{background-color:var(--soft-blue);padding:10px;color:var(--color-blue-rigo);border-radius:9px;margin-top:5px;line-height:25px;word-break:break-word}.message.user{background-color:#f5f5f57b;color:#000}.message p:not(:first-child){margin-top:15px}.alert{background-color:var(--4geeks-yellow);padding:3px 10px;border-radius:10px;color:#000;font-weight:700;text-align:center}.self-closing-modal{position:fixed;top:0;left:0;background-color:var(--backdrop-background);width:100vw!important;height:100%!important;display:grid;place-content:center;z-index:2}.self-closing-modal>div.modal-content{display:block;border-radius:20px;flex-direction:column;background-color:var(--modals-bg-color);padding:20px;width:min(600px,98vw);gap:10px;margin-inline:auto;overflow:auto;max-height:95vh;position:relative}.self-closing-modal .modal-closer{position:absolute;right:20px;top:25px;z-index:2;cursor:pointer}.icon-component{background-color:red}.loader{display:flex;align-items:center;gap:10px;justify-content:center;animation:glowing 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.loader-icon{width:40px;height:40px;border:2px solid var(--loader-color);border-top-color:transparent;position:relative;display:flex;align-items:center;justify-content:center}.loader-icon:after{content:"";display:block;width:100%;top:0;left:0;position:absolute;height:100%;border:2px solid var(--color-hovered);border-top:2px solid var(--color-active);border-radius:50%;animation:spin 2s linear infinite}@keyframes glowing{0%{opacity:.6}to{opacity:1}}.input-modal{text-align:center;background-color:var(--modals-bg-color);color:var(--read-font-color);padding:20px;display:flex;flex-direction:column;gap:10px}.presentator{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(141,141,141,.402);z-index:0;cursor:initial}._badge{position:fixed;width:min(90%,330px);border-radius:5px;text-align:left;background-color:#fff;border:1px solid rgba(127,127,127,.3);padding:15px;top:50vh;left:50%;z-index:2;box-shadow:0 4px 8px #0000001a}._badge>h2{color:#000;margin-bottom:10px;font-size:25px}._badge>div._content>*{margin-top:5px;line-height:1.5rem}._badge>._footer{display:flex;justify-content:space-between;flex-direction:row}._badge>p{color:#000;font-size:1rem;font-weight:400;margin-top:0}._container_1cky8_1{width:100%;background-color:#e0e0e0;border-radius:4px;overflow:hidden}._filler_1cky8_15{height:100%;background-color:var(--color-blue-rigo);border-radius:4px 0 0 4px;transition:width .3s ease}.reset-modal{text-align:center}.reset-modal>section{display:flex;justify-content:center;width:100%;gap:20px}.login-modal{font-size:16px}.login-modal h2{text-align:center}.login-modal>div div:has(button){display:flex;align-items:center;justify-content:center;gap:5px}.login-modal button,.login-modal input{font-size:16px}._header_1u10v_1{display:flex;justify-content:space-between;padding-inline:10px;padding-block:10px;align-items:center;background-color:var(--app-bg-color);border-top-left-radius:10px;border-top-right-radius:10px}._header_1u10v_1>section{display:flex;gap:8px}._header_1u10v_1>section:last-child{display:flex;gap:15px}._header_1u10v_1>section>button:disabled{cursor:not-allowed;opacity:.5}._container_ezryg_1{display:flex;gap:8px;background-color:var(--bg-color);flex-wrap:nowrap;min-height:calc(100dvh - 200px);max-height:calc(100dvh - var(--header-height))}._container_ezryg_1>div{width:65%}._container_ezryg_1>div:only-child{width:100%}._content_ezryg_31{display:flex;position:relative}._content_ezryg_31>section{padding:8px;width:100%;max-height:90vh;overflow:auto}._appTabs_ezryg_55{display:flex;background-color:var(--tabs-bg-color);justify-content:space-between;position:absolute;top:0;left:0;width:100%}._appTabs_ezryg_55>div{width:100%;text-align:center;padding:10px;color:#728ec0;border-bottom:1px solid transparent;cursor:pointer}._appTabs_ezryg_55>div[data-visible=true]{background-color:var(--bg-color);color:var(--color-active);border-bottom:3px solid var(--color-active)}._hiddenOnMobile_ezryg_103{display:none}@media only screen and (min-width: 768px){._container_ezryg_1{gap:8px}._content_ezryg_31>section{padding:8px;width:100%}._appTabs_ezryg_55{display:none}._hiddenOnMobile_ezryg_103{display:block;text-align:center}}.tabs{display:flex;align-items:center;gap:2px}.tab{display:flex;background-color:var(--bg-color);border-top-right-radius:6px;border-top-left-radius:6px;cursor:pointer;transition:background-color .3s ease;padding:5px 6px}.tab.active{background-color:var(--opaque-blue-editor)}.tab.active button{color:var(--color-active)}.editor{border:7px solid var(--opaque-blue-editor);border-radius:0 5px 0 0;position:relative}.editor-monaco .view-lines,.editor-monaco .margin-view-overlays{height:min(400px,fit-content)!important}.terminal{border:3px solid var(--opaque-blue-editor);border-top:0;overflow-y:auto;position:relative;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.terminal.html{height:min(400px,fit-content);overflow-y:auto;border:none}.terminal.only{margin-top:0;border:0;max-height:70vh;border-radius:5px}.terminal.only .editor-footer{margin-top:20px;display:block;position:relative}.terminal.hidden{display:none}.terminal>h5{border-bottom:1px solid #dadada;display:flex;justify-content:space-between;align-items:center;margin:0;font-size:16px}.terminal>pre{background-color:var(--bg-color);border:none;max-width:100%;height:fit-content F;word-break:break-word!important;white-space:pre-wrap}.terminal>pre>code{word-wrap:break-word}.editor-footer{background-color:var(--app-bg-color);position:absolute;bottom:8px;width:calc(100% - 16px);left:8px;border-radius:8px;font-size:12px}.editor-footer .compiler{background-color:var(--color-active);color:#fff!important}.editor-footer .compiler .set-stroke path{stroke:#fff}.editor-footer.UNMODIFIED,.editor-footer.MODIFIED{background-color:var(--modals-bg-color)}.editor .editor-footer.success{background-color:var(--soft-green)}.editor .editor-footer.error{color:#fff!important;background-color:var(--soft-red)}.editor-footer .not-started{display:flex;align-items:center;gap:9px;color:var(--color-active);padding:4px;justify-content:space-between;font-size:12px}.editor-footer .not-started span{font-size:12px}.editor-footer .not-started>div:first-child{display:flex;align-items:center;gap:5px}.editor-footer .footer-actions{display:flex;align-items:center;justify-content:space-between;gap:4px;padding:4px}.editor-footer .footer-actions>div>button,.editor-footer .footer-actions>button,.editor-footer .footer-actions>div{width:100%;border-radius:4px;display:flex;font-size:12px;justify-content:center;align-items:center;gap:5px;color:var(--color-active)}.editor-footer.success{background-color:var(--soft-green)}.editor-footer.success .footer-actions>button svg path{stroke:var(--color-success)}.editor-footer.success .footer-actions>div>button>svg path{stroke:var(--color-success)}.editor-footer.success .footer-actions>div{color:var(--color-success)}.editor-footer.success .footer-actions>button{color:#000}.editor-footer.success .footer-actions>div>button{color:#000}.editor-footer.success .editor-footer-child .set-path-fill path{fill:var(--color-success)}.editor-footer.success .compiler{background-color:var(--color-success);color:#fff!important}.editor-footer.success .compiler .set-path-fill path{stroke:#fff}.editor-footer.error{background-color:var(--soft-red)}.editor-footer.error .footer-actions>button svg path{stroke:var(--color-fail)}.editor-footer.error .footer-actions>div>button>svg path{stroke:var(--color-fail)}.editor-footer.error .footer-actions>div>button{color:var(--color-fail)}.editor-footer.error .footer-actions>button{color:var(--color-fail)}.editor-footer.error .footer-actions>div{color:var(--color-fail)}.editor-footer.error .editor-footer-child .set-path-fill path{fill:var(--color-fail)}.editor-footer.error .compiler{background-color:var(--color-fail);color:#fff!important}.editor-footer.error .compiler .set-path-fill path{stroke:#fff}.footer-actions button{font-size:15px!important}.app-header{animation:scale-navbar auto linear both;animation-timeline:scroll();animation-range:10px 150px;position:sticky;top:0}.app-header:hover{opacity:1!important}.navbar-component{padding:10px;background-color:var(--bg-color);display:flex;width:100%;transition:all 2s;margin:0 auto;max-width:1145px;justify-content:space-between}.navbar-component>section{display:flex;gap:3px;align-items:center}.navbar-component>section>button,.navbar-component>section>div{border:1px solid var(--color-active);border-radius:5px}.lesson-options{display:flex;align-items:center;background-color:var(--bg-color);margin:0 auto;max-width:1145px;padding:8px;justify-content:space-between}.lesson-options>div{display:flex;gap:10px;align-items:center}.lesson-options button:disabled{opacity:.5;cursor:not-allowed}@keyframes scale-navbar{to{opacity:0}}.feedback-dropdown{position:absolute;width:250px!important;padding:2px;border:1px solid var(--color-active);background-color:var(--modals-bg-color);border-radius:7px;max-width:300px;font-size:var(--font-size-small);display:flex;gap:5px;align-items:baseline!important;z-index:4;flex-direction:column}.feedback-dropdown.up{bottom:103%;right:0}.feedback-dropdown.down{top:103%;left:-75%}.feedback-dropdown>*{width:fit-content}.feedback-dropdown>button{color:var(--color-active);width:100%;padding:7px;text-align:left;display:flex;justify-content:left;align-items:center}.feedback-dropdown>button:hover{background-color:var(--color-blue-opaque)}.feedback-dropdown>p{padding:3px;background-color:var(--bg-color);margin:0;font-size:var(--font-size-mini);color:var(--read-font-color)}.feedback-dropdown>p>a{font-weight:600;color:var(--color-active);cursor:pointer}#feedback-button{min-width:fit-content}.sidebar-component{position:absolute;left:0%;font-size:17px;z-index:2;background-color:var(--sidebar-bg-color);display:flex;flex-direction:column;align-items:center;width:100%}@media (min-width: 768px){.sidebar-component{width:min(100vw - 5px,460px)!important;position:relative;height:calc(100vh - var(--header-height))}.sidebar-component .footer{width:100%;position:fixed;bottom:0}}.sidebar-component section h2{text-align:center;padding:10px;margin-block:0;width:100%}.sidebar-component>section:not(:last-child){display:flex;justify-content:space-between;padding:2px 14px}.sidebar-component .footer{background-color:transparent;position:relative;width:100%;padding:15px;display:flex;align-items:center;justify-content:space-between}.sidebar-component .footer>a{padding:10px;text-decoration:none;color:var(--read-font-color);display:block;border-radius:8px}.sidebar-component .footer>a:hover{background-color:var(--color-hovered)}.sidebar-component .exercise-list{display:flex;flex-direction:column;width:100%;gap:5px;padding:5px;max-height:83vh!important;overflow-y:scroll;width:var(--app-width);margin-inline:auto}.exercise-list .exercise-card{background-color:var(--bg-1);display:flex;padding:3px 5px;cursor:pointer;width:100%;justify-content:space-between;font-size:18px;border-radius:10px;align-items:center;position:relative}.exercise-circle{background-color:var(--bg-1);border-radius:50%;width:40px;height:40px;display:flex;align-items:center;justify-content:center;color:#0097cf;padding:10px}.exercise-circle.done{background-color:#0097cf;color:#fff}.sidebar-component .exercise-list .exercise-card:hover{background-color:var(--bg-2)}.sidebar-component .exercise-list .exercise-card:active{background-color:var(--color-blue-opaque);transition:all .3s ease}.sidebar-disappear{animation:disappear-4-right .4s ease 1 forwards}@keyframes appear-4-right{0%{left:101%}to{left:0}}@keyframes disappear-4-right{0%{left:0}to{left:101%}}.bg-blue-opaque{background-color:var(--color-blue-opaque)}.lesson-content{padding-bottom:70px;font-size:20px;padding-inline:16px;line-height:2rem;max-height:100vh;position:relative}.lesson-content img{margin:5px auto;max-width:750px;display:block}.lesson-content h1{font-size:32px}.lesson-content h2{font-size:25px}.lesson-content h3{font-size:20px}.creator-wrapper{position:relative}.creator-wrapper .display-on-hover{display:none}.creator-wrapper:hover .display-on-hover{display:block}.inverted{transform:scaleY(-1)}.inverted>*{transform:scaleY(-1)}.creator-options{display:flex;border-radius:5px;gap:3px;position:absolute;top:0;left:0;flex-direction:column;z-index:1000}.creator-options-buttons{background-color:var(--color-blue-opaque);width:fit-content;padding:5px;border-radius:5px}.text-in-editor{position:relative}.creator-options-opener{display:none;position:absolute;right:100%;top:5px;z-index:1000;padding:2px;border-radius:5px;background-color:var(--app-bg-color)}.creator-wrapper:hover>.text-in-editor>.creator-options-opener{display:block}.creator-wrapper:hover{background-color:var(--color-blue-opaque);border-radius:2px}.creator-target-content{color:var(--color-success)}.creator-target{border-radius:5px}.code-buttons{background-color:var(--color-blue-opaque);border-top-left-radius:5px;border-top-right-radius:5px;padding-left:10px;padding-right:10px;font-size:12px;color:var(--color-blue-rigo)}.custom-code-block{position:relative}.execution-result{background-color:var(--color-blue-opaque);padding:10px;border-bottom-left-radius:5px;border-bottom-right-radius:5px;font-size:12px;color:var(--color-success)}.katex{font-size:1.2rem;line-height:2rem}.rigo-input{border-radius:5px;font-size:16px;padding:5px;width:min(600px,90vw)!important;display:flex;align-items:center;gap:5px}.rigo-button{background:linear-gradient(132deg,#0fb0fc,#022cc2);border:2px solid white;color:var(--white);opacity:1;border-radius:50%;padding:5px;display:flex;justify-content:center;align-items:center;width:50px;height:50px;margin-right:-12px;z-index:1}.rigo-textarea{border:0;background:#c8dbfc;font-size:16px;padding:7px;outline:none;width:100%;border-radius:10px;color:#000}.rigo-textarea::placeholder{color:var(--color-blue-rigo)}._button_1y12h_5{background-color:var(--color-blue-rigo);color:#fff;border:none;padding:.5rem 1rem;border-radius:.25rem;cursor:pointer;display:flex;align-items:center}._icon_1y12h_27{margin-left:.5rem;color:currentColor}._menu_1y12h_37{position:absolute;right:0;margin-top:.25rem;width:15rem;background-color:#dce9ff;border-radius:.25rem;box-shadow:0 2px 8px #0000001a;z-index:100;padding:.5rem 10px}
@@ -332,7 +332,7 @@ to {
332
332
  `+t.slice(s+1):l+=t.slice(a),l.slice(1)}function ZUe(t){for(var e="",r,n,a,i=0;i<t.length;i++){if(r=t.charCodeAt(i),r>=55296&&r<=56319&&(n=t.charCodeAt(i+1),n>=56320&&n<=57343)){e+=cee((r-55296)*1024+n-56320+65536),i++;continue}a=Ji[r],e+=!a&&J0(r)?t[i]:a||cee(r)}return e}function JUe(t,e,r){var n="",a=t.tag,i,s;for(i=0,s=r.length;i<s;i+=1)mp(t,e,r[i],!1,!1)&&(i!==0&&(n+=","+(t.condenseFlow?"":" ")),n+=t.dump);t.tag=a,t.dump="["+n+"]"}function e$e(t,e,r,n){var a="",i=t.tag,s,o;for(s=0,o=r.length;s<o;s+=1)mp(t,e+1,r[s],!0,!0)&&((!n||s!==0)&&(a+=wL(t,e)),t.dump&&Qy===t.dump.charCodeAt(0)?a+="-":a+="- ",a+=t.dump);t.tag=i,t.dump=a||"[]"}function t$e(t,e,r){var n="",a=t.tag,i=Object.keys(r),s,o,l,u,d;for(s=0,o=i.length;s<o;s+=1)d="",s!==0&&(d+=", "),t.condenseFlow&&(d+='"'),l=i[s],u=r[l],mp(t,e,l,!1,!1)&&(t.dump.length>1024&&(d+="? "),d+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),mp(t,e,u,!1,!1)&&(d+=t.dump,n+=d));t.tag=a,t.dump="{"+n+"}"}function r$e(t,e,r,n){var a="",i=t.tag,s=Object.keys(r),o,l,u,d,h,f;if(t.sortKeys===!0)s.sort();else if(typeof t.sortKeys=="function")s.sort(t.sortKeys);else if(t.sortKeys)throw new Gy("sortKeys must be a boolean or a function");for(o=0,l=s.length;o<l;o+=1)f="",(!n||o!==0)&&(f+=wL(t,e)),u=s[o],d=r[u],mp(t,e+1,u,!0,!0,!0)&&(h=t.tag!==null&&t.tag!=="?"||t.dump&&t.dump.length>1024,h&&(t.dump&&Qy===t.dump.charCodeAt(0)?f+="?":f+="? "),f+=t.dump,h&&(f+=wL(t,e)),mp(t,e+1,d,!0,h)&&(t.dump&&Qy===t.dump.charCodeAt(0)?f+=":":f+=": ",f+=t.dump,a+=f));t.tag=i,t.dump=a||"{}"}function bee(t,e,r){var n,a,i,s,o,l;for(a=r?t.explicitTypes:t.implicitTypes,i=0,s=a.length;i<s;i+=1)if(o=a[i],(o.instanceOf||o.predicate)&&(!o.instanceOf||typeof e=="object"&&e instanceof o.instanceOf)&&(!o.predicate||o.predicate(e))){if(t.tag=r?o.tag:"?",o.represent){if(l=t.styleMap[o.tag]||o.defaultStyle,eee.call(o.represent)==="[object Function]")n=o.represent(e,l);else if(tee.call(o.represent,l))n=o.represent[l](e,l);else throw new Gy("!<"+o.tag+'> tag resolver accepts not "'+l+'" style');t.dump=n}return!0}return!1}function mp(t,e,r,n,a,i){t.tag=null,t.dump=r,bee(t,r,!1)||bee(t,r,!0);var s=eee.call(t.dump);n&&(n=t.flowLevel<0||t.flowLevel>e);var o=s==="[object Object]"||s==="[object Array]",l,u;if(o&&(l=t.duplicates.indexOf(r),u=l!==-1),(t.tag!==null&&t.tag!=="?"||u||t.indent!==2&&e>0)&&(a=!1),u&&t.usedDuplicates[l])t.dump="*ref_"+l;else{if(o&&u&&!t.usedDuplicates[l]&&(t.usedDuplicates[l]=!0),s==="[object Object]")n&&Object.keys(t.dump).length!==0?(r$e(t,e,t.dump,a),u&&(t.dump="&ref_"+l+t.dump)):(t$e(t,e,t.dump),u&&(t.dump="&ref_"+l+" "+t.dump));else if(s==="[object Array]"){var d=t.noArrayIndent&&e>0?e-1:e;n&&t.dump.length!==0?(e$e(t,d,t.dump,a),u&&(t.dump="&ref_"+l+t.dump)):(JUe(t,d,t.dump),u&&(t.dump="&ref_"+l+" "+t.dump))}else if(s==="[object String]")t.tag!=="?"&&KUe(t,t.dump,e,i);else{if(t.skipInvalid)return!1;throw new Gy("unacceptable kind of an object to dump "+s)}t.tag!==null&&t.tag!=="?"&&(t.dump="!<"+t.tag+"> "+t.dump)}return!0}function n$e(t,e){var r=[],n=[],a,i;for(kL(t,r,n),a=0,i=n.length;a<i;a+=1)e.duplicates.push(r[n[a]]);e.usedDuplicates=new Array(i)}function kL(t,e,r){var n,a,i;if(t!==null&&typeof t=="object")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,i=t.length;a<i;a+=1)kL(t[a],e,r);else for(n=Object.keys(t),a=0,i=n.length;a<i;a+=1)kL(t[n[a]],e,r)}function wee(t,e){e=e||{};var r=new GUe(e);return r.noRefs||n$e(t,r),mp(r,0,t,!0,!0)?r.dump+`
333
333
  `:""}function a$e(t,e){return wee(t,jy.extend({schema:CUe},e))}bL.dump=wee,bL.safeDump=a$e;var A5=$y,xee=bL;function m5(t){return function(){throw new Error("Function "+t+" is deprecated and cannot be used.")}}oa.Type=fi,oa.Schema=W0,oa.FAILSAFE_SCHEMA=gL,oa.JSON_SCHEMA=BJ,oa.CORE_SCHEMA=RJ,oa.DEFAULT_SAFE_SCHEMA=Vy,oa.DEFAULT_FULL_SCHEMA=u5,oa.load=A5.load,oa.loadAll=A5.loadAll,oa.safeLoad=A5.safeLoad,oa.safeLoadAll=A5.safeLoadAll,oa.dump=xee.dump,oa.safeDump=xee.safeDump,oa.YAMLException=Hy,oa.MINIMAL_SCHEMA=gL,oa.SAFE_SCHEMA=Vy,oa.DEFAULT_SCHEMA=u5,oa.scan=m5("scan"),oa.parse=m5("parse"),oa.compose=m5("compose"),oa.addConstructor=m5("addConstructor");var i$e=oa,s$e=i$e,kee=s$e,o$e="\\ufeff?",l$e=typeof process<"u"?process.platform:"",c$e="^("+o$e+"(= yaml =|---)$([\\s\\S]*?)^(?:\\2|\\.\\.\\.)\\s*$"+(l$e==="win32"?"\\r?":"")+"(?:\\n)?)",_ee=new RegExp(c$e,"m");hL.exports=u$e,hL.exports.test=f$e;function u$e(t,e){t=t||"";var r={allowUnsafe:!1};e=e instanceof Object?{...r,...e}:r,e.allowUnsafe=!!e.allowUnsafe;var n=t.split(/(\r?\n)/);return n[0]&&/= yaml =|---/.test(n[0])?h$e(t,e.allowUnsafe):{attributes:{},body:t,bodyBegin:1}}function d$e(t,e){for(var r=1,n=e.indexOf(`
334
334
  `),a=t.index+t[0].length;n!==-1;){if(n>=a)return r;r++,n=e.indexOf(`
335
- `,n+1)}return r}function h$e(t,e){var r=_ee.exec(t);if(!r)return{attributes:{},body:t,bodyBegin:1};var n=e?kee.load:kee.safeLoad,a=r[r.length-1].replace(/^\s+|\s+$/g,""),i=n(a)||{},s=t.replace(r[0],""),o=d$e(r,t);return{attributes:i,body:s,bodyBegin:o,frontmatter:a}}function f$e(t){return t=t||"",_ee.test(t)}var p$e=hL.exports;const g$e=aa(p$e),Fn={get:(t,e=!0)=>{const r=localStorage.getItem(t);return r?e?JSON.parse(r):r:null},set:(t,e)=>{localStorage.setItem(t,JSON.stringify(e))},remove:t=>{localStorage.removeItem(t)},clear:()=>{localStorage.clear()},getEditorTabs:t=>Fn.get(`editorTabs_${t}`)||[],setEditorTabs:(t,e)=>{Fn.set(`editorTabs_${t}`,e)}},A$e=1;class m$e{calculateStepIndicator(e,r){return r.status!=="skipped"&&r.status!=="unread"?Math.min(r.time_spent/3600*100,100):0}calculateGlobalIndicator(e,r){const n={total_time:.3,num_sessions:.2,completion_rate:.3,interactions:.2},a=Math.min(r.total_time_on_platform/36e3,1)*100,i=Math.min(r.num_sessions/5,1)*100,s=r.completion_rate,o=Math.min(r.total_interactions/100,1)*100;return(a*n.total_time+i*n.num_sessions+s*n.completion_rate+o*n.interactions)/100*100}}class y$e{calculateStepIndicator(e,r){return r.status==="completed"?Math.min((r.comp_struggles+r.test_struggles)/20*100,100):r.status==="attempted"?Math.min(r.time_spent/1800*100,100):r.status==="skipped"?25:0}calculateGlobalIndicator(e,r){const n={steps_not_completed:.3,time_on_incomplete:.2,avg_comp_struggles:.2,avg_test_struggles:.2,skipped_steps:.1},a=r.total_steps>0?r.steps_not_completed/r.total_steps*100:0,i=Math.min(r.time_on_incomplete/18e3,1)*100,s=Math.min(r.avg_comp_struggles/10,1)*100,o=Math.min(r.avg_test_struggles/10,1)*100,l=r.total_steps>0?r.skipped_steps/r.total_steps*100:0;return(a*n.steps_not_completed+i*n.time_on_incomplete+s*n.avg_comp_struggles+o*n.avg_test_struggles+l*n.skipped_steps)/100*100}}function Eee(t){var o,l,u,d;let e=t.completed_at?"completed":t.opened_at?"attempted":"unread";const r=t.completed_at&&t.opened_at?(t.completed_at-t.opened_at)/1e3:0,n=((o=t.compilations)==null?void 0:o.filter(h=>h.exit_code!==0).length)||0,a=((l=t.tests)==null?void 0:l.filter(h=>h.exit_code!==0).length)||0;let i=0,s=0;for(let h=((u=t.compilations)==null?void 0:u.length)-1;h>=0&&t.compilations[h].exit_code!==0;h--)i++;for(let h=((d=t.tests)==null?void 0:d.length)-1;h>=0&&t.tests[h].exit_code!==0;h--)s++;return{status:e,time_spent:r,comp_struggles:n,test_struggles:a,streak_comp_struggles:i,streak_test_struggle:s}}function v$e(t){const e=t.length,r=t.map(Eee),n=r.filter(p=>p.status==="completed").length,a=r.filter(p=>p.status==="attempted").length,i=r.filter(p=>p.status==="skipped").length,s=e?n/e*100:0,o=t.reduce((p,g)=>{var A,m;return p+(((A=g.compilations)==null?void 0:A.length)||0)+(((m=g.tests)==null?void 0:m.length)||0)},0),l=r.reduce((p,g)=>p+g.time_spent,0),u=a+i,d=e?r.reduce((p,g)=>p+g.comp_struggles,0)/e:0,h=e?r.reduce((p,g)=>p+g.test_struggles,0)/e:0;let f=0;for(const p of t){let g=0;for(const A of p.tests||[])A.exit_code===0?g++:g=0,f=Math.max(f,g)}return{total_time_on_platform:l,num_sessions:1,completion_rate:s,total_interactions:o,steps_not_completed:u,time_on_incomplete:l,avg_comp_struggles:d,avg_test_struggles:h,skipped_steps:i,total_steps:e,global_test_success_streak:f}}function Cee(t){const e=[new m$e,new y$e],r=t.steps.map(s=>Eee(s)),n=v$e(t.steps),a=t.steps.map((s,o)=>{const l=r[o],u={};return e.forEach(d=>{u[d.constructor.name]=d.calculateStepIndicator(s,l)}),{slug:s.slug,metrics:l,indicators:u}}),i={};return e.forEach(s=>{i[s.constructor.name]=s.calculateGlobalIndicator(a.map(o=>o.indicators[s.constructor.name]),n)}),{algo_version:A$e,global:{metrics:n,indicators:i},steps:a}}const See={name:"learnpack-ai",private:!0,version:"5.0.176",scripts:{dev:"node src/utils/development.js --turn on && vite",build:"node src/utils/development.js --turn off && tsc && vite build && node src/utils/uploadLearnpack.js && node bin/publish.js && node src/utils/createVersionsFile.js ","dev-build":"node src/utils/development.js --turn on && tsc && vite build",lint:"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",preview:"vite preview","compile-command":"tsc src/utils/development.ts && node src/utils/development.js --turn on"},dependencies:{"@monaco-editor/react":"^4.6.0",axios:"^1.7.7","front-matter":"^4.0.2","highlight.js":"^11.11.1",html2canvas:"^1.4.1",i18next:"^23.10.1","js-yaml":"^4.1.0",mermaid:"^11.6.0","monaco-editor":"^0.50.0",react:"^18.2.0","react-dom":"^18.2.0","react-draggable":"^4.4.6","react-gtm-module":"^2.0.11","react-hot-toast":"^2.4.1","react-i18next":"^14.1.0","react-markdown":"^9.0.1","react-monaco-editor":"^0.56.1","react-router-dom":"^6.27.0","react-syntax-highlighter":"^15.6.1","rehype-katex":"^7.0.1","remark-emoji":"^5.0.1","remark-gfm":"^4.0.0","remark-math":"^6.0.0","socket.io":"^4.7.2","socket.io-client":"^4.7.2",uuid:"^10.0.0",zustand:"^4.4.1"},devDependencies:{"@aws-sdk/client-s3":"^3.709.0","@types/js-yaml":"^4.0.9","@types/markdown-it":"^14.1.2","@types/react":"^18.2.15","@types/react-dom":"^18.2.7","@types/react-gtm-module":"^2.0.3","@types/react-syntax-highlighter":"^15.5.13","@types/remarkable":"^2.0.3","@types/uuid":"^10.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","@vitejs/plugin-react-swc":"^3.3.2",archiver:"^6.0.1",dotenv:"^16.4.7",eslint:"^8.45.0","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.3",inquirer:"^9.2.12",typescript:"^5.0.2",vite:"^4.5.13"}},Tee="http://localhost:3000",b$e=async(t,e,r)=>{try{const n=Zi();return(await Es.post(`/exercise/${t}/create?slug=${n}`,{title:t,readme:e,language:r})).data}catch(n){throw console.error("Error creating exercise:",n),n}},w$e=async t=>{try{const e=Zi();return(await Es.delete(`/exercise/${t}/delete?slug=${e}`)).data}catch(e){throw console.error("Error deleting exercise:",e),e}},x$e=async(t,e)=>{try{const r=Zi();return(await Es.put(`/actions/rename?slug=${r}`,{slug:t,newSlug:e})).data}catch(r){throw console.error("Error renaming exercise:",r),r}},k$e=async(t,e)=>{try{const r=Zi(),n={"x-breathecode-token":t,"x-rigo-token":e};return(await Es.post(`${My?"http://localhost:3000":""}/actions/publish/${r}`,{categoryId:"663296363296363296363296",academyId:"663296363296363296363296"},{headers:n})).data}catch(r){throw console.error("Error publishing tutorial:",r),r}},_$e=async function(t,e,r){if(!t||!r){console.error("URL and token are required");return}r=r.trim();const n={"Content-Type":"application/json",Authorization:`Token ${r}`};try{return(await Es.post(t,e,{headers:n})).data}catch(a){throw console.error("Error while sending batch telemetry",a),Es.isAxiosError(a)&&a.response&&(console.error("Response data:",a.response.data),console.error("Response status:",a.response.status),console.error("Response headers:",a.response.headers)),a}},E$e=async function(t,e,r){!t||!r||fetch(t,{method:"POST",body:JSON.stringify(e)}).then(n=>n).catch(n=>{console.log("Error while sending stream Telemetry",n)})},C$e=async function(){try{return(await Es.get(`${Tee}/telemetry`)).data}catch(t){return console.error("Error while retrieving telemetry from CLI",t),null}},S$e=async function(t){try{const e=await Es.post(`${Tee}/telemetry`,t);return console.debug("Saved telemetry in CLI",e.data),e.data}catch(e){return console.error("Error while saving telemetry in CLI",e),null}};function T$e(){return Math.random().toString(36).slice(2,10)+Math.random().toString(36).slice(2,10)}function _L(t){if(typeof t!="string")throw new TypeError("Input must be a string");return btoa(encodeURIComponent(t))}const kh={current:null,urls:{},telemetryKey:"",listeners:{},agent:"cloud",user:{token:"",id:"",email:""},tutorialSlug:"",started:!1,version:`CLOUD:${See.version}`||"CLOUD:0.0.0",salute:t=>{console.log(t)},start:function(t,e,r,n,a){this.telemetryKey=n,this.tutorialSlug=r,this.agent=t,this.user.id=a.user_id,this.user.token=a.token,this.current||this.retrieve().then(i=>{if(i?(this.current=i,this.finishWorkoutSession()):(console.debug("No previous telemetry found, creating new one. Agent: ",t),this.current={telemetry_id:T$e(),slug:r,version:`CLOUD:${this.version}`,agent:t,tutorial_started_at:Date.now(),last_interaction_at:Date.now(),steps:e,workout_session:[{started_at:Date.now()}]}),this.current.user_id=this.user.id,this.current.version||(this.current.version=`CLOUD:${this.version}`),this.save(),this.started=!0,!this.user.id){console.warn("No user ID found, impossible to submit telemetry at start");return}this.submit()}).catch(i=>{throw console.log("ERROR: There was a problem starting the Telemetry"),console.error(i),new Error(`There was a problem starting, reload LearnPack
335
+ `,n+1)}return r}function h$e(t,e){var r=_ee.exec(t);if(!r)return{attributes:{},body:t,bodyBegin:1};var n=e?kee.load:kee.safeLoad,a=r[r.length-1].replace(/^\s+|\s+$/g,""),i=n(a)||{},s=t.replace(r[0],""),o=d$e(r,t);return{attributes:i,body:s,bodyBegin:o,frontmatter:a}}function f$e(t){return t=t||"",_ee.test(t)}var p$e=hL.exports;const g$e=aa(p$e),Fn={get:(t,e=!0)=>{const r=localStorage.getItem(t);return r?e?JSON.parse(r):r:null},set:(t,e)=>{localStorage.setItem(t,JSON.stringify(e))},remove:t=>{localStorage.removeItem(t)},clear:()=>{localStorage.clear()},getEditorTabs:t=>Fn.get(`editorTabs_${t}`)||[],setEditorTabs:(t,e)=>{Fn.set(`editorTabs_${t}`,e)}},A$e=1;class m$e{calculateStepIndicator(e,r){return r.status!=="skipped"&&r.status!=="unread"?Math.min(r.time_spent/3600*100,100):0}calculateGlobalIndicator(e,r){const n={total_time:.3,num_sessions:.2,completion_rate:.3,interactions:.2},a=Math.min(r.total_time_on_platform/36e3,1)*100,i=Math.min(r.num_sessions/5,1)*100,s=r.completion_rate,o=Math.min(r.total_interactions/100,1)*100;return(a*n.total_time+i*n.num_sessions+s*n.completion_rate+o*n.interactions)/100*100}}class y$e{calculateStepIndicator(e,r){return r.status==="completed"?Math.min((r.comp_struggles+r.test_struggles)/20*100,100):r.status==="attempted"?Math.min(r.time_spent/1800*100,100):r.status==="skipped"?25:0}calculateGlobalIndicator(e,r){const n={steps_not_completed:.3,time_on_incomplete:.2,avg_comp_struggles:.2,avg_test_struggles:.2,skipped_steps:.1},a=r.total_steps>0?r.steps_not_completed/r.total_steps*100:0,i=Math.min(r.time_on_incomplete/18e3,1)*100,s=Math.min(r.avg_comp_struggles/10,1)*100,o=Math.min(r.avg_test_struggles/10,1)*100,l=r.total_steps>0?r.skipped_steps/r.total_steps*100:0;return(a*n.steps_not_completed+i*n.time_on_incomplete+s*n.avg_comp_struggles+o*n.avg_test_struggles+l*n.skipped_steps)/100*100}}function Eee(t){var o,l,u,d;let e=t.completed_at?"completed":t.opened_at?"attempted":"unread";const r=t.completed_at&&t.opened_at?(t.completed_at-t.opened_at)/1e3:0,n=((o=t.compilations)==null?void 0:o.filter(h=>h.exit_code!==0).length)||0,a=((l=t.tests)==null?void 0:l.filter(h=>h.exit_code!==0).length)||0;let i=0,s=0;for(let h=((u=t.compilations)==null?void 0:u.length)-1;h>=0&&t.compilations[h].exit_code!==0;h--)i++;for(let h=((d=t.tests)==null?void 0:d.length)-1;h>=0&&t.tests[h].exit_code!==0;h--)s++;return{status:e,time_spent:r,comp_struggles:n,test_struggles:a,streak_comp_struggles:i,streak_test_struggle:s}}function v$e(t){const e=t.length,r=t.map(Eee),n=r.filter(p=>p.status==="completed").length,a=r.filter(p=>p.status==="attempted").length,i=r.filter(p=>p.status==="skipped").length,s=e?n/e*100:0,o=t.reduce((p,g)=>{var A,m;return p+(((A=g.compilations)==null?void 0:A.length)||0)+(((m=g.tests)==null?void 0:m.length)||0)},0),l=r.reduce((p,g)=>p+g.time_spent,0),u=a+i,d=e?r.reduce((p,g)=>p+g.comp_struggles,0)/e:0,h=e?r.reduce((p,g)=>p+g.test_struggles,0)/e:0;let f=0;for(const p of t){let g=0;for(const A of p.tests||[])A.exit_code===0?g++:g=0,f=Math.max(f,g)}return{total_time_on_platform:l,num_sessions:1,completion_rate:s,total_interactions:o,steps_not_completed:u,time_on_incomplete:l,avg_comp_struggles:d,avg_test_struggles:h,skipped_steps:i,total_steps:e,global_test_success_streak:f}}function Cee(t){const e=[new m$e,new y$e],r=t.steps.map(s=>Eee(s)),n=v$e(t.steps),a=t.steps.map((s,o)=>{const l=r[o],u={};return e.forEach(d=>{u[d.constructor.name]=d.calculateStepIndicator(s,l)}),{slug:s.slug,metrics:l,indicators:u}}),i={};return e.forEach(s=>{i[s.constructor.name]=s.calculateGlobalIndicator(a.map(o=>o.indicators[s.constructor.name]),n)}),{algo_version:A$e,global:{metrics:n,indicators:i},steps:a}}const See={name:"learnpack-ai",private:!0,version:"5.0.178",scripts:{dev:"node src/utils/development.js --turn on && vite",build:"node src/utils/development.js --turn off && tsc && vite build && node src/utils/uploadLearnpack.js && node bin/publish.js && node src/utils/createVersionsFile.js ","dev-build":"node src/utils/development.js --turn on && tsc && vite build",lint:"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",preview:"vite preview","compile-command":"tsc src/utils/development.ts && node src/utils/development.js --turn on"},dependencies:{"@monaco-editor/react":"^4.6.0",axios:"^1.7.7","front-matter":"^4.0.2","highlight.js":"^11.11.1",html2canvas:"^1.4.1",i18next:"^23.10.1","js-yaml":"^4.1.0",mermaid:"^11.6.0","monaco-editor":"^0.50.0",react:"^18.2.0","react-dom":"^18.2.0","react-draggable":"^4.4.6","react-gtm-module":"^2.0.11","react-hot-toast":"^2.4.1","react-i18next":"^14.1.0","react-markdown":"^9.0.1","react-monaco-editor":"^0.56.1","react-router-dom":"^6.27.0","react-syntax-highlighter":"^15.6.1","rehype-katex":"^7.0.1","remark-emoji":"^5.0.1","remark-gfm":"^4.0.0","remark-math":"^6.0.0","socket.io":"^4.7.2","socket.io-client":"^4.7.2",uuid:"^10.0.0",zustand:"^4.4.1"},devDependencies:{"@aws-sdk/client-s3":"^3.709.0","@types/js-yaml":"^4.0.9","@types/markdown-it":"^14.1.2","@types/react":"^18.2.15","@types/react-dom":"^18.2.7","@types/react-gtm-module":"^2.0.3","@types/react-syntax-highlighter":"^15.5.13","@types/remarkable":"^2.0.3","@types/uuid":"^10.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","@vitejs/plugin-react-swc":"^3.3.2",archiver:"^6.0.1",dotenv:"^16.4.7",eslint:"^8.45.0","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.3",inquirer:"^9.2.12",typescript:"^5.0.2",vite:"^4.5.13"}},Tee="http://localhost:3000",b$e=async(t,e,r)=>{try{const n=Zi();return(await Es.post(`/exercise/${t}/create?slug=${n}`,{title:t,readme:e,language:r})).data}catch(n){throw console.error("Error creating exercise:",n),n}},w$e=async t=>{try{const e=Zi();return(await Es.delete(`/exercise/${t}/delete?slug=${e}`)).data}catch(e){throw console.error("Error deleting exercise:",e),e}},x$e=async(t,e)=>{try{const r=Zi();return(await Es.put(`/actions/rename?slug=${r}`,{slug:t,newSlug:e})).data}catch(r){throw console.error("Error renaming exercise:",r),r}},k$e=async(t,e)=>{try{const r=Zi(),n={"x-breathecode-token":t,"x-rigo-token":e};return(await Es.post(`${My?"http://localhost:3000":""}/actions/publish/${r}`,{categoryId:"663296363296363296363296",academyId:"663296363296363296363296"},{headers:n})).data}catch(r){throw console.error("Error publishing tutorial:",r),r}},_$e=async function(t,e,r){if(!t||!r){console.error("URL and token are required");return}r=r.trim();const n={"Content-Type":"application/json",Authorization:`Token ${r}`};try{return(await Es.post(t,e,{headers:n})).data}catch(a){throw console.error("Error while sending batch telemetry",a),Es.isAxiosError(a)&&a.response&&(console.error("Response data:",a.response.data),console.error("Response status:",a.response.status),console.error("Response headers:",a.response.headers)),a}},E$e=async function(t,e,r){!t||!r||fetch(t,{method:"POST",body:JSON.stringify(e)}).then(n=>n).catch(n=>{console.log("Error while sending stream Telemetry",n)})},C$e=async function(){try{return(await Es.get(`${Tee}/telemetry`)).data}catch(t){return console.error("Error while retrieving telemetry from CLI",t),null}},S$e=async function(t){try{const e=await Es.post(`${Tee}/telemetry`,t);return console.debug("Saved telemetry in CLI",e.data),e.data}catch(e){return console.error("Error while saving telemetry in CLI",e),null}};function T$e(){return Math.random().toString(36).slice(2,10)+Math.random().toString(36).slice(2,10)}function _L(t){if(typeof t!="string")throw new TypeError("Input must be a string");return btoa(encodeURIComponent(t))}const kh={current:null,urls:{},telemetryKey:"",listeners:{},agent:"cloud",user:{token:"",id:"",email:""},tutorialSlug:"",started:!1,version:`CLOUD:${See.version}`||"CLOUD:0.0.0",salute:t=>{console.log(t)},start:function(t,e,r,n,a){this.telemetryKey=n,this.tutorialSlug=r,this.agent=t,this.user.id=a.user_id,this.user.token=a.token,this.current||this.retrieve().then(i=>{if(i?(this.current=i,this.finishWorkoutSession()):(console.debug("No previous telemetry found, creating new one. Agent: ",t),this.current={telemetry_id:T$e(),slug:r,version:`CLOUD:${this.version}`,agent:t,tutorial_started_at:Date.now(),last_interaction_at:Date.now(),steps:e,workout_session:[{started_at:Date.now()}]}),this.current.user_id=this.user.id,this.current.version||(this.current.version=`CLOUD:${this.version}`),this.save(),this.started=!0,!this.user.id){console.warn("No user ID found, impossible to submit telemetry at start");return}this.submit()}).catch(i=>{throw console.log("ERROR: There was a problem starting the Telemetry"),console.error(i),new Error(`There was a problem starting, reload LearnPack
336
336
  Run
337
337
  $ learnpack start`)})},registerListener:function(t,e){this.listeners[t]=e},getStepIndicators:function(t){return this.current?Cee(this.current).steps[t]:null},finishWorkoutSession:function(){var e,r;if(!this.current)return;console.log("Finishing workout session",this.current);const t=(e=this.current)==null?void 0:e.workout_session[this.current.workout_session.length-1];t&&!t.ended_at&&((r=this.current)!=null&&r.last_interaction_at)&&(t.ended_at=this.current.last_interaction_at,this.current.workout_session.push({started_at:Date.now()}))},registerStepEvent:function(t,e,r){if(console.debug(`Registering Telemetry Event ${e} for user ${this.user.id}`),!this.current){console.error(`Telemetry has not been started, ${e} NOT REGISTERED`);return}const n=this.current.steps[t];if(!n){console.error(`No step ${t} found ${e} NOT REGISTERED`);return}switch(r.source_code&&(r.source_code=_L(r.source_code)),r.stdout&&(r.stdout=_L(r.stdout)),r.stderr&&(r.stderr=_L(r.stderr)),Object.prototype.hasOwnProperty.call(r,"exitCode")&&(r.exit_code=r.exitCode,r.exitCode=void 0),e){case"compile":n.compilations||(n.compilations=[]),n.compilations.push(r),this.current.steps[t]=n;break;case"test":n.tests||(n.tests=[]),n.tests.push(r),r.exit_code===0&&(n.completed_at=Date.now()),this.current.steps[t]=n;break;case"ai_interaction":n.ai_interactions||(n.ai_interactions=[]),n.ai_interactions.push(r);break;case"quiz_submission":{n.quiz_submissions||(n.quiz_submissions=[]),n.quiz_submissions.push(r);break}case"open_step":{const a=Date.now();if(n.opened_at||(n.opened_at=a,this.current.steps[t]=n),this.prevStep||this.prevStep===0){const i=this.current.steps[this.prevStep];!i.is_testeable&&!i.completed_at&&(i.completed_at=a,this.current.steps[this.prevStep]=i)}this.prevStep=t,this.submit();break}default:throw new Error(`Event type ${e} is not supported`)}if(this.current.last_interaction_at=Date.now(),this.streamEvent(t,e,r),this.save(),e==="test"&&typeof this.listeners.test_struggles=="function"){const i=Cee(this.current).steps[t];i.metrics.streak_test_struggle>=3&&this.listeners.test_struggles(i)}},retrieve:function(){if(this.agent==="os"||this.agent==="vscode")return C$e();const t=Fn.get(this.telemetryKey);return t&&t.slug===this.tutorialSlug?Promise.resolve(t):Promise.resolve(null)},submit:async function(){if(!this.current||!this.user.token||!this.user.id)return console.warn("Telemetry and user token are required to send telemetry, telemetry was not sent"),console.warn({current:!!this.current,id:!!this.user.id,token:!!this.user.token}),Promise.resolve();const t=this.urls.batch;if(!t){console.error("Batch URL is required to send telemetry");return}const e=this.current;e.user_id||(e.user_id=this.user.id);try{await _$e(t,e,this.user.token),console.debug("Telemetry submitted successfully for user",this.user.id)}catch(r){console.error("Error submitting telemetry",r)}},save:function(){if(!this.current){console.error("No current telemetry to save");return}this.agent==="os"||this.agent==="vscode"?S$e(this.current):Fn.set(this.telemetryKey,this.current)},getStep:function(t){var e;return((e=this.current)==null?void 0:e.steps[t])||null},streamEvent:async function(t,e,r){if(!this.current)return;const n=this.urls.streaming;if(!n)return;const i={slug:this.current.steps[t].slug,telemetry_id:this.current.telemetry_id,user_id:this.current.user_id,step_position:t,event:e,data:r};E$e(n,i,this.user.token)}};for(var Ri=[],EL=0;EL<256;++EL)Ri.push((EL+256).toString(16).slice(1));function L$e(t,e=0){return(Ri[t[e+0]]+Ri[t[e+1]]+Ri[t[e+2]]+Ri[t[e+3]]+"-"+Ri[t[e+4]]+Ri[t[e+5]]+"-"+Ri[t[e+6]]+Ri[t[e+7]]+"-"+Ri[t[e+8]]+Ri[t[e+9]]+"-"+Ri[t[e+10]]+Ri[t[e+11]]+Ri[t[e+12]]+Ri[t[e+13]]+Ri[t[e+14]]+Ri[t[e+15]]).toLowerCase()}var y5,B$e=new Uint8Array(16);function R$e(){if(!y5&&(y5=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!y5))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return y5(B$e)}var I$e=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);const Lee={randomUUID:I$e};function N$e(t,e,r){if(Lee.randomUUID&&!e&&!t)return Lee.randomUUID();t=t||{};var n=t.random||(t.rng||R$e)();if(n[6]=n[6]&15|64,n[8]=n[8]&63|128,e){r=r||0;for(var a=0;a<16;++a)e[r+a]=n[a];return e}return L$e(n)}const Et={ENVIRONMENT:"",HOST:"",LOGOUT_CALLBACK:()=>{},init:(t,e,r)=>{Et.ENVIRONMENT=t,Et.HOST=e,typeof r=="function"&&(Et.LOGOUT_CALLBACK=r)},getExercises:async t=>{const e=Et.ENVIRONMENT==="localhost"||Et.ENVIRONMENT==="creatorWeb"?"config":"config.json";let r=Et.ENVIRONMENT==="localhost"||Et.ENVIRONMENT==="creatorWeb"?`${Et.HOST}/${e}`:"/config.json";const n=Zi();return n&&(r=`${r}?slug=${n}`),await(await fetch(r,{headers:{"x-rigo-token":t}})).json()},getReadme:async(t,e)=>{const r=Zi();let n=Et.ENVIRONMENT==="localhost"||Et.ENVIRONMENT==="creatorWeb"?`${Et.HOST}/exercise/${t}/readme?lang=${e}${r?`&slug=${r}`:""}`:`/exercises/${t}/README.${e==="us"?"":"es."}md`;const a=await fetch(n);if(Et.ENVIRONMENT==="localhost"||Et.ENVIRONMENT==="creatorWeb")return await a.json();const i=await a.text();return g$e(i)},getFileContent:async(t,e,r={cached:!1})=>await{localhost:async()=>{const a=`${Et.HOST}/exercise/${t}/file/${e}`;return{fileContent:await(await fetch(a)).text(),edited:!1}},localStorage:async()=>{let a=!1;const i=`/exercises/${t}/${e}`,o=await(await fetch(i)).text();if(r.cached){const l=Fn.get(`editorTabs_${t}`);if(l){const u=l.find(d=>d.name===e);if(u)return a=!0,{fileContent:u.content,edited:a}}}return{fileContent:o,edited:a}},creatorWeb:async()=>{let a=!1;const i=Zi(),s=`${Et.HOST}/courses/${i}/exercises/${t}/file/${e}`,l=await(await fetch(s)).text();if(r.cached){const u=Fn.get(`editorTabs_${t}`);if(u){const d=u.find(h=>h.name===e);if(d)return a=!0,{fileContent:d.content,edited:a}}}return{fileContent:l,edited:a}}}[Et.ENVIRONMENT](),getExerciseInfo:async t=>await{localhost:async()=>await(await oFe(t)).json(),localStorage:async()=>(await(await fetch("/config.json")).json()).exercises.find(i=>i.slug===t),creatorWeb:async()=>{try{const r=Zi();return await(await fetch(`${My?"http://localhost:3000":""}/courses/${r}/exercises/${t}/`)).json()}catch(r){return console.log("Error fetching exercise info in creatorWeb"),console.log(r),null}}}[Et.ENVIRONMENT](),saveFileContent:async(t,e,r)=>await{localhost:async()=>{try{const a=`${Et.HOST}/exercise/${t}/file/${e}`;await fetch(a,{method:"PUT",body:r})}catch(a){console.log("Error saving file content in CLI"),console.log(a)}},localStorage:async()=>{},creatorWeb:async()=>{const a=Zi();return await(await fetch(`/steps/${t}?slug=${a}`)).json()}}[Et.ENVIRONMENT](),getTelemetryStep:async t=>kh.getStep(t),checkLoggedStatus:async()=>({localStorage:async()=>{const e=Fn.get("session");if(!e)throw console.log("No session in LS"),Error("The user is not logged in");const r=await eA(e.token);if(!r||!await CL(e.rigobot.key))throw Fn.remove("session"),Error("The token is invalid or inactive!");return{payload:{...e},rigoToken:e.rigobot.key,user:r}},localhost:async()=>{const e=await fetch(`${Et.HOST}/check/rigo/status`);if(e.status===400)throw Error("The user is not logged in");const r=await e.json(),n=await eA(r.payload.token);if(n===null)throw Et.logout(),Error("The user session is expired!");return{...r,user:n}},creatorWeb:async()=>{const e=Fn.get("session");if(!e)throw console.log("No session in LS"),Error("The user is not logged in");const r=await eA(e.token);if(!r)throw Fn.remove("session"),console.log("No user in session"),Error("The token is invalid or inactive!");if(!await CL(e.rigobot.key))throw Fn.remove("session"),Error("The token is invalid or inactive!");return{payload:{...e},rigoToken:e.rigobot.key,user:r}}})[Et.ENVIRONMENT](),getSyllabus:async()=>({localhost:async()=>null,localStorage:async()=>null,creatorWeb:async()=>{try{const e=Zi();return await(await fetch(`${Et.HOST}/courses/${e}/syllabus`)).json()}catch(e){return console.log("Error fetching syllabus in creatorWeb"),console.log(e),null}}})[Et.ENVIRONMENT](),setTabHash:async t=>({localhost:async()=>{const r={hash:t},n=await fetch(`${Et.HOST}/set-tab-hash`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(n.status===400)throw console.log("ERROR"),console.log(n),Error("Impossible to set tab hash");return await n.json(),!0},localStorage:async()=>(Fn.set("TAB_HASH",t),!0),creatorWeb:async()=>(Fn.set("TAB_HASH",t),!0)})[Et.ENVIRONMENT](),getTabHash:async()=>P$e(),getSessionKey:async()=>({localhost:async()=>{const e=await fetch(`${Et.HOST}/check/rigo/status`);if(e.status===400)throw Error("The user is not logged in");const r=await e.json();return r&&r.payload&&"sessionKey"in r.payload?r.payload.sessionKey:null},localStorage:async()=>{let e=Fn.get("LEARNPACK_SESSION_KEY");return e||null},creatorWeb:async()=>{let e=Fn.get("LEARNPACK_SESSION_KEY");return e||null}})[Et.ENVIRONMENT](),setSessionKey:async t=>({localhost:async()=>{const r={sessionKey:t},n=await fetch(`${Et.HOST}/set-session-key`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(n.status===400)throw console.log("ERROR"),console.log(n),Error("Impossible to set session key");return await n.json(),!0},localStorage:async()=>{Fn.set("LEARNPACK_SESSION_KEY",t)},creatorWeb:async()=>{Fn.set("LEARNPACK_SESSION_KEY",t)}})[Et.ENVIRONMENT](),getSidebar:async t=>({localhost:async()=>{try{return await(await fetch(`${Et.HOST}/sidebar`)).json()}catch(r){return console.error(r,"error getting sidebar"),{}}},localStorage:async()=>{try{return await(await fetch("/sidebar.json")).json()}catch(r){return console.error(r,"error getting sidebar"),{}}},creatorWeb:async()=>{try{const r=Zi(),n={"Content-Type":"application/json","x-rigo-token":t};return await(await fetch(`${Et.HOST}/translations/sidebar?slug=${r}`,{headers:n})).json()}catch(r){return console.error(r,"error getting sidebar"),{}}}})[Et.ENVIRONMENT](),login:async t=>({localhost:async()=>await D$e(t,Et.HOST),localStorage:async()=>await Ree(t),creatorWeb:async()=>await Ree(t)})[Et.ENVIRONMENT](),loginWithToken:async t=>{const e=await eA(t);if(!e)throw Error("Unable to login with provided credentials");const r=await Bee(t),n={...e,rigobot:{...r},token:t},a=await Et.getTabHash(),i={payload:{...n},rigoToken:n.rigobot.key,user:e,tabHash:a,rigobot:{...n.rigobot},user_id:n.id};return Et.ENVIRONMENT==="localhost"?await F$e({...i.payload,token:t,tabHash:a}):(Et.ENVIRONMENT==="localStorage"||Et.ENVIRONMENT==="creatorWeb")&&Fn.set("session",{token:t,email:i.user.email,user_id:i.user_id,rigobot:{...i.rigobot},user:{...i.user}}),i},replaceReadme:async(t,e,r)=>({localhost:async()=>{const a=`${Et.HOST}/exercise/${t}/file/README.${e==="us"?"":"es."}md`;return!!(await fetch(a,{method:"PUT",body:r})).ok},localStorage:async()=>{Ar.error("IMPOSSIBLE TO REPLACE README IN LS")},creatorWeb:async()=>{const a=Zi(),i=`${Et.HOST}/exercise/${t}/file/README.${e==="us"?"":"es."}md?slug=${a}`;return!!(await fetch(i,{method:"PUT",body:r})).ok}})[Et.ENVIRONMENT](),logout:async()=>{({localhost:async()=>{await O$e(Et.HOST)},localStorage:async()=>{Fn.remove("session");const e=Zx();e.token&&delete e.token,hp(e),typeof Et.LOGOUT_CALLBACK=="function"&&Et.LOGOUT_CALLBACK()},creatorWeb:async()=>{Fn.remove("session");const e=Zx();e.token&&delete e.token,hp(e)}})[Et.ENVIRONMENT]()},translateExercises:async(t,e,r)=>({localhost:async()=>{const a=`${Et.HOST}/actions/translate`;return await(await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({exerciseSlugs:t,languages:e})})).json()},localStorage:async()=>{Ar.error("IMPOSSIBLE TO TRANSLATE EXERCISES IN LS")},creatorWeb:async()=>{const a=Zi();try{const i=`${Et.HOST}/actions/translate?slug=${a}`;return await(await fetch(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({exerciseSlugs:t,languages:e,rigoToken:r})})).json()}catch(i){return console.error(i,"error translating exercises"),{}}}})[Et.ENVIRONMENT]()},eA=async t=>{const e={method:"GET",headers:{"Content-Type":"application/json",Authorization:`Token ${t}`}},r=await fetch(`${Q0}/v1/auth/user/me`,e);if(!r.ok)return null;const n=await r.json();return"roles"in n&&delete n.roles,"permissions"in n&&delete n.permissions,"settings"in n&&delete n.settings,n},O$e=async t=>{const e={method:"post",body:JSON.stringify({}),headers:{"Content-Type":"application/json"}},r=await fetch(t+"/logout",e);r.ok||console.log("Error trying to logout",r.statusText)},D$e=async(t,e)=>{const r={method:"post",body:JSON.stringify(t),headers:{"Content-Type":"application/json"}},a=await(await fetch(e+"/login",r)).json(),i=await eA(a.token);return{...a,user:i}},Bee=async t=>{const e=`${ml}/v1/auth/me/token?breathecode_token=${t}`,r=await fetch(e);if(!r.ok)throw new e5("Unable to obtain Rigobot token");return await r.json()},Ree=async t=>{const e=`${Q0}/v1/auth/login/`,r=await fetch(e,{body:JSON.stringify(t),method:"post",headers:{"Content-Type":"application/json"}});if(!r.ok)throw Error("Unable to login with provided credentials");const n=await r.json(),a=await Bee(n.token),i=await eA(n.token),s={...n,rigobot:{...a},user:i};return Fn.set("session",s),s},F$e=async t=>{const e={payload:{...t}},r=await fetch(`${Et.HOST}/set-session`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(r.status===400)throw console.log("ERROR"),console.log(r),Error("Impossible to set tab hash");return await r.json(),!0},CL=async t=>{const e=`${ml}/v1/auth/token/${t}`;if(!(await fetch(e)).ok)throw new AJ("Unable to obtain Rigobot token");return!0},M$e=t=>{let e=2166136261;for(let r=0;r<t.length;r++)e^=t.charCodeAt(r),e+=(e<<1)+(e<<4)+(e<<7)+(e<<8)+(e<<24);return(e>>>0).toString(16)},P$e=()=>{try{const e=window.location.href.split("?")[0].split("#")[0],r=M$e(e);return console.debug(r,"HASH"),r}catch(t){return console.error("Error generating tab hash:",t),N$e()}},no={started:!1,load:()=>{if(no.started)return;const t=document.createElement("script");t.src="https://unpkg.com/rigo-ai@0.1.8/dist/main.js",t.type="text/javascript",t.async=!0,document.head.appendChild(t),no.started=!0},init:({chatHash:t,purposeSlug:e,userToken:r,context:n})=>{console.log("Initilizing RigoAI"),no.started||no.load(),window.rigo&&(window.rigo.init(t,{purposeSlug:e,user:{token:r},context:n||"",sockethost:Kx}),window.rigo.show({showBubble:!1,collapsed:!0}))},useTemplate:({slug:t,inputs:e,target:r,onComplete:n})=>{if(!window.rigo){console.error("RIGOBOT AI NOT LOADED");return}window.rigo.complete({templateSlug:t,payload:{...e},target:r,format:"markdown",onComplete:(i,s)=>{n&&n(i,s)}}).run()},ask:(t,e,r=[])=>{const n=window.rigo.ask({prompt:t,target:e,previousMessages:r,format:"markdown",useVectorStore:!1,onStart:()=>{Ar.success("AI is starting...")},onComplete:(a,i)=>{console.log("success",a),console.log("data",i)}});n&&n.run()}};function v5(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=Math.random()*16|0,r=t=="x"?e:e&3|8;return r.toString(16)})}const U$e={js:"prompt(",py:"input(",java:"Scanner(System.in).nextLine()",cs:"Console.ReadLine()",rb:"gets",php:"$_POST['input']",go:"bufio.NewReader(os.Stdin).ReadString('\\n')",swift:"readLine()"};function $$e(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Iee(t,e){try{const r=t.split(".").pop();if(!r)return null;const n=U$e[r];if(!n)return null;let a;if(r==="js"||r==="py"||r==="swift"){const l=$$e(n);a=new RegExp(`${l}\\s*\\s*("(.*?)"|'(.*?)')`,"g")}const i=[];let s;for(;(s=a==null?void 0:a.exec(e))!==null;)s&&i.push(s[1]||s[2]);const o=i.map(l=>l.replace(/['"]/g,""));return o.length>0?o:null}catch(r){return console.error("Something went wrong:",r),null}}let z$e=Xx();const la={events:{},statusEvents:{},type:"localStorageEventEmitter",emit:(t,e)=>{la.events[t]&&la.events[t].forEach(r=>r(e))},emitStatus:(t,e)=>{la.statusEvents[t]&&la.statusEvents[t](e)},on:(t,e)=>{la.events[t]||(la.events[t]=[]),la.events[t].push(e)},onStatus:(t,e)=>{la.statusEvents[t]=e},openWindow:t=>{t&&t.url?t.options.redirect?window.location.href=t.url:window.open(t.url,"__blank"):console.error("No URL provided in data")}};function Nee(t){const e=/<REPEAT\s+"(.*?)"\s+(\d+)\s*\/>/g;return t.replace(e,(r,n,a)=>{const i=parseInt(a,10);return Array(i).fill(n).join(`
338
338
  `)})}la.on("build",async t=>{try{const e=Fn.get(`editorTabs_${t.exerciseSlug}`)||t.editorTabs;let r="",n=[];const a={},i=[];if(e.forEach(l=>{n.push(l.name.split(".").pop());const u=Iee(l.name,l.content);if(u&&i.push(...u),l.name.includes("solution"))return;const d=`
@@ -395,7 +395,7 @@ ${n.body}
395
395
  ### NOTES FOR AI:
396
396
  The user's set up the application in "${i}" language, give your feedback in "${i}" language, please.\`\`\`
397
397
 
398
- `,s))},fetchExercises:async()=>{const{user_id:r,setOpenedModals:n,environment:a,token:i}=e();if(a==="creatorWeb"){const s=Zi();if(!i||i===""){n({mustLogin:!0}),t({mustLoginMessageKey:"to-access-this-course-you-need-to-login"});return}const{isAuthor:o,status:l}=await Z$e(i,s);if(!o){n(l===403?{notAuthor:!0}:{packageNotFound:!0});return}}try{const s=await Et.getExercises(i);if(!s)return;s.config.authentication&&s.config.authentication.mandatory&&t({authentication:{mandatory:!0}}),s.config.assessment&&s.config.assessment.maxQuizRetries&&t({maxQuizRetries:s.config.assessment.maxQuizRetries}),s.config.warnings&&s.config.warnings.agent&&a!=="localStorage"&&(t({dialogData:{message:s.config.warnings.agent,format:"md"}}),n({dialog:!0})),s.config.warnings&&s.config.warnings.extension&&(t({dialogData:{message:s.config.warnings.extension,format:"md"}}),n({dialog:!0}));const o=s.config.slug;if(R9.dataLayer({dataLayer:{event:"start_exercise",slug:o,user_id:r}}),s.exercises&&s.exercises.length>0&&t({exercises:s.exercises}),s.currentExercise){const l=s.exercises.findIndex(u=>u.slug===s.currentExercise);l!==-1&&t({currentExercisePosition:l})}return s.config.title.us&&t({lessonTitle:s.config.title.us}),t({configObject:s}),s.config.editor&&s.config.editor.agent&&a!=="localStorage"&&t({agent:s.config.editor.agent}),!0}catch(s){return console.log(s,"ERROR"),pJ(),!1}},checkParams:({justReturn:r})=>{const{setLanguage:n,setPosition:a,language:i,setOpenedModals:s}=e();let o=Zx();if(r)return o;const l={language:d=>{i!==d&&n(d,!1)},currentExercise:d=>{a(Number(d))},iframe:d=>{d.toLowerCase()==="true"&&t({isIframe:!0}),d.toLowerCase()==="false"&&t({isIframe:!1})},theme:d=>{["light","dark"].includes(d.toLowerCase().trim())&&t({theme:d})},autoclose:d=>{d.toLowerCase()==="true"&&s({closeWindow:!0})},token:d=>{t({token:d})}},u=Object.entries(o);for(let[d,h]of u)d in l?l[d](h):console.debug(`Unknown param passed: ${d}`);return o},fetchSingleExerciseInfo:async r=>{var d;const{exercises:n}=e();if(n.length<=0)return;const a=(d=n[r])==null?void 0:d.slug;if(!a)return;const i=await Et.getExerciseInfo(a);let s=i.graded,o,l=!1;i.entry&&(o=!0),i.language||(o=!1);const u=i.files.filter(h=>h.name.includes("solution.hide"));if(u.length>0){l=!0;let h=await Et.getFileContent(a,u[0].name);t({currentSolution:h.fileContent})}return t({isTesteable:s,isBuildable:o,hasSolution:l}),i},setPosition:r=>{const{startConversation:n,fetchReadme:a,token:i,setBuildButtonPrompt:s,setFeedbackButtonProps:o,checkParams:l,registerTelemetryEvent:u}=e();let d=l({justReturn:!0});hp({...d,currentExercise:String(r)}),t({currentExercisePosition:r}),i&&n(r),s("execute-my-code",""),o("test-my-code",""),t({lastState:""}),u("open_step",{step_position:r}),a()},startConversation:async r=>{const{token:n,learnpackPurposeId:a,conversationIdsCache:i}=e();let s=null,o=null;if(n){try{if(s=i[r],!s)throw new Error("ConversationID not found in cache")}catch{o=await lFe(a,n),s=o.conversation_id}o&&o.salute&&t({chatInitialMessage:o.salute}),t({conversationIdsCache:{...i,[r]:s}}),w5.emit("start",{token:n,purpose:a,conversationId:s})}},loginToRigo:async r=>{const{setToken:n,startConversation:a,currentExercisePosition:i,setOpenedModals:s,language:o,reportEnrichDataLayer:l,getOrCreateActiveSession:u,getUserConsumables:d}=e();try{const h=await Et.login(r);if(t({bc_token:h.token,user_id:h.user_id,user:h.user}),h.rigobot==null)throw new e5("No rigobot user found, did you already accept Rigobot's invitation?");n(h.rigobot.key),Ar.success(r.messages.success,{icon:"✅"}),l("session_load",{method:"native",user_id:h.user_id,language:o,path:window.location.href,agent:"cloud"}),d()}catch(h){return h instanceof e5?(s({login:!1,rigobotInvite:!0}),!1):(Ar.error(r.messages.error),!1)}return a(Number(i)),s({login:!1}),u(),!0},checkRigobotInvitation:async r=>{try{const{bc_token:n,setToken:a,openLink:i,language:s,environment:o}=e(),l=()=>{const f="https://rigobot.herokuapp.com/invite?referer=4geeks&lang="+hFe(s)+"&token="+n+"&callback="+fFe(window.location.href+"?autoclose=true");i(f)},u=`${ml}/v1/auth/me/token?breathecode_token=${n}`,d=await fetch(u);if(d.status!=200)return Ar.error(r.error,{icon:at.rigoSvg}),l(),!1;const h=await d.json();if(console.log("DATA FROM RIGOBOT INVITATION",h),a(h.key),o==="localhost"){const f={token:h.key},p={method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)};await fetch(`${qy}/set-rigobot-token`,p)}return h.key}catch(n){return console.log(n,"ERROR"),!1}},openLink:(r,n={redirect:!1})=>{const{compilerSocket:a,getCurrentExercise:i}=e(),s={...n},o={url:r,exerciseSlug:i().slug,options:s};a.openWindow(o)},updateEditorTabs:(r=null)=>{const{getCurrentExercise:n,editorTabs:a,setAllowedActions:i,environment:s}=e(),o=n(),l=o.files.filter(h=>!h.hidden);let u=[...a];if(r)if(u.some(f=>f.name===r.name)){const f=u.findIndex(p=>p.name===r.name);u[f]={...r,isActive:r.name!=="terminal"}}else r.name==="terminal"?u.push({...r,isActive:!1}):(u=u.map(f=>({...f,isActive:!1})),u.push({...r,isActive:!0}));(async()=>{for(const[f,p]of l.entries()){let g="";const{fileContent:A,edited:m}=await Et.getFileContent(o.slug,p.name,{cached:!0});g=A,"content"in p&&p.content!==g&&await Et.saveFileContent(o.slug,p.name,g);const y=u.some(w=>w.name===p.name),v={id:f,content:g,name:p.name,isActive:f===0&&!r,modified:m};if(!y)u=[...u,v];else{const w=u.findIndex(k=>k.name===p.name);u[w]=v}}!u.some(f=>f.isActive)&&u.length>0&&(u[0].isActive=!0),t({editorTabs:[...u]}),u.length>0&&s==="localStorage"&&i(["tutorial","test","build"])})()},cleanTerminal:()=>{const{editorTabs:r}=e(),n=r.filter(a=>a.name!=="terminal");t({editorTabs:[...n]})},fetchReadme:async()=>{var h;const{language:r,exercises:n,currentExercisePosition:a,fetchSingleExerciseInfo:i,configObject:s,updateEditorTabs:o}=e(),l=(h=n[a])==null?void 0:h.slug;if(!l)return;const u=await Et.getReadme(l,r);if(!u)return;u.attributes&&u.attributes.tutorial?t({videoTutorial:u.attributes.tutorial}):u.attributes.intro?t({videoTutorial:u.attributes.intro,showVideoTutorial:!0}):t({videoTutorial:"",showVideoTutorial:!1});let d=gJ(u.body,"{{publicUrl}}",qy);if(typeof s.config.variables=="object")for(let f in s.config.variables)d=gJ(d,`{{${f}}}`,s.config.variables[f]);return t({currentContent:{body:d,bodyBegin:u.bodyBegin}}),t({editorTabs:[]}),i(a),o(),!0},toggleSidebar:()=>{sFe()},setLanguage:(r,n=!0)=>{const{fetchReadme:a,checkParams:i}=e();t({language:r});let s=i({justReturn:!0});hp({...s,language:r}),n&&a()},openTerminal:()=>{const{compilerSocket:r,getCurrentExercise:n}=e(),a={exerciseSlug:n().slug};r.emit("open_terminal",a)},handleNext:()=>{const{currentExercisePosition:r,handlePositionChange:n}=e();n(Number(r)+1)},getSyllabus:async()=>{const{environment:r}=e();if(r!=="creatorWeb")return[];const n=await Et.getSyllabus();return!n||n.length===0?[]:(t({syllabus:n}),n)},checkExerciseAvailability:async r=>{const{exercises:n,environment:a,syllabus:i,setOpenedModals:s}=e();return a!=="creatorWeb"||!n||n.length===0||!i||i.lessons.length===0||i.lessons[r].generated?!0:(s({syllabusFeedback:!0}),!1)},handlePositionChange:async r=>{const{configObject:n,currentExercisePosition:a,exercises:i,setPosition:s,isTesteable:o,runExerciseTests:l,checkExerciseAvailability:u}=e();if(!n||!n.config){console.log("Impossible to continue, the configuration is not ready!");return}isNaN(r)&&(r=0);const d=n.config.grading,h=i.length-1;if(r>h||r<0){Ar.error("The exercise you are looking for does not exist!");return}if(r==a)return;let f=!0;if(r>Number(a)&&(f=!o||d==="isolated"||d==="incremental"&&i[a].done),await u(r),!f){l({toast:!0,setFeedbackButton:!0,feedbackButtonText:"Running...",targetButton:"feedback"});return}s(Number(r))},toastFromStatus:r=>{const{language:n}=e(),[a,i]=o5(r,n);let s=1500;r==="testing-error"&&(s=3e3),Ar.success(i,{icon:a,duration:s})},setTestResult:(r,n)=>{const{exercises:a,currentExercisePosition:i,updateDBSession:s}=e(),o=[...a];o[Number(i)].done=r==="successful",t({exercises:o}),s()},setShouldBeTested:r=>{t({shouldBeTested:r})},build:async(r,n=[])=>{const{setBuildButtonPrompt:a,compilerSocket:i,getCurrentExercise:s,editorTabs:o,token:l,updateEditorTabs:u,setOpenedModals:d,setEditorTabs:h,environment:f,userConsumables:p,bc_token:g,toastFromStatus:A,reportEnrichDataLayer:m}=e();if(!g||!l){d({mustLogin:!0});return}if(f==="localStorage"&&!(p.ai_compilation>0||p.ai_compilation===-1)){d({limitReached:!0}),m("learnpack_consumable_depleted ",{service_slug:"ai_compilation"});return}o.find(v=>v.name==="terminal")&&h(o.map(v=>v.name==="terminal"?{...v,content:""}:v)),a(r,""),A("compiling");const y={exerciseSlug:s().slug,token:l,updateEditorTabs:u,editorTabs:o,submittedInputs:n};i.emit("build",y),t({lastStartedAt:new Date}),m("learnpack_run",{})},setEditorTabs:r=>{t({editorTabs:r})},runExerciseTests:async(r,n=[])=>{const{compilerSocket:a,getCurrentExercise:i,setFeedbackButtonProps:s,toastFromStatus:o,token:l,updateEditorTabs:u,setOpenedModals:d,editorTabs:h,language:f,setEditorTabs:p,bc_token:g,environment:A,userConsumables:m,currentContent:y}=e();if(!l||!g){d({mustLogin:!0});return}if(A==="localStorage"&&!(m.ai_compilation>0||m.ai_compilation===-1)){d({limitReached:!0});return}h.find(w=>w.name==="terminal")&&p(h.map(w=>w.name==="terminal"?{...w,content:""}:w));const v={exerciseSlug:i().slug,token:l,updateEditorTabs:u,editorTabs:h,submittedInputs:n,language:f,instructions:y.body};a.emit("test",v),t({shouldBeTested:!1}),r!=null&&r.targetButton&&t({targetButtonForFeedback:r.targetButton}),r&&r.setFeedbackButton&&r.targetButton==="feedback"&&r.feedbackButtonText&&s(r.feedbackButtonText,"palpitate"),r&&r.toast&&o("testing")},getOrCreateActiveSession:async()=>{const{token:r,configObject:n,setOpenedModals:a,updateEditorTabs:i,tabHash:s,checkParams:o}=e();let l=s;if(!o({justReturn:!0}).autoclose&&r){l||(l=await Et.getTabHash(),t({tabHash:l}));try{console.log(n,"configObject");const d=await Dee(r,n.config.slug);if(console.log(d,"session"),d.tab_hash||(await TL(r,l,n.config.slug,n,d.key),t({sessionKey:d.key})),d.tab_hash&&d.tab_hash!==l){a({session:!0});return}else if(d.tab_hash&&d.tab_hash===l)t({configObject:d.config_json}),t({sessionKey:d.key}),await Et.setSessionKey(d.key),i();else{t({sessionKey:d.key});return}}catch(d){console.error(d),console.log("Error trying to get session")}}},updateDBSession:async()=>{const{configObject:r,exercises:n,token:a,tabHash:i,sessionKey:s,getCurrentExercise:o}=e(),l=o(),u={...r,exercises:n,currentExercise:l.slug};let d="";s||(d=await Et.getSessionKey()),await TL(a,i,r.config.slug,u,s||d)},updateFileContent:async(r,n,a=!1)=>{const{exercises:i,updateEditorTabs:s,setShouldBeTested:o}=e();let l=i.map(u=>u.slug===r?{...u,files:u.files.map(d=>d.name===n.name?{...d,content:n.content,modified:!0}:d)}:u);await Et.saveFileContent(r,n.name,n.content),t({exercises:l}),o(!0),a&&s()},resetExercise:({exerciseSlug:r})=>{const{updateEditorTabs:n,exercises:a,compilerSocket:i,updateDBSession:s,setEditorTabs:o,editorTabs:l,reportEnrichDataLayer:u}=e();l.find(f=>f.name==="terminal")&&o(l.filter(f=>f.name!=="terminal"));let d=a.map(f=>f.slug===r?{...f,files:f.files.map(p=>(delete p.content,delete p.modified,p))}:f);t({exercises:d,lastState:""}),s();const h={exerciseSlug:r,updateEditorTabs:n};i.emit("reset",h),u("learnpack_reset",{})},sessionActions:async({action:r="new"})=>{const{configObject:n,token:a,updateEditorTabs:i,tabHash:s,handlePositionChange:o}=e();let l=s;if(l||(l=await Et.getTabHash()),r==="new"){const u=await Y$e(a,s,n.config.slug,n);await Et.setSessionKey(u.key),t({sessionKey:u.key})}if(r==="continue"){const u=await Dee(a,n.config.slug);if(await TL(a,s,n.config.slug,null,u.key),t({configObject:u.config_json,sessionKey:u.key}),u.config_json.exercises&&u.config_json.exercises.length>0&&u.config_json.currentExercise){const d=u.config_json.exercises.findIndex(h=>h.slug===u.config_json.currentExercise);o(d)}await Et.setSessionKey(u.key),i()}},refreshDataFromAnotherTab:({newToken:r,newTabHash:n,newBCToken:a})=>{const{token:i,bc_token:s,tabHash:o,getOrCreateActiveSession:l}=e();i!==r&&t({token:r}),s!==a&&t({bc_token:a}),o!==n&&t({tabHash:n}),l()},toggleTheme:()=>{const{theme:r,checkParams:n}=e();let a=n({justReturn:!0});r==="dark"?(hp({...a,theme:"light"}),t({theme:"light"})):(hp({...a,theme:"dark"}),t({theme:"dark"}))},toggleRigo:r=>{const{token:n,isRigoOpened:a,setOpenedModals:i,showSidebar:s,setShowSidebar:o}=e();if(!n){i({mustLogin:!0});return}if(s&&o(!1),r&&r.ensure==="open"){t({isRigoOpened:!0});return}if(r&&r.ensure==="close"){t({isRigoOpened:!1});return}t({isRigoOpened:!a})},registerTelemetryEvent:(r,n)=>{const{currentExercisePosition:a}=e();kh.registerStepEvent(Number(a),r,n)},startTelemetry:async()=>{var l,u;const{configObject:r,bc_token:n,user:a,registerTelemetryEvent:i,environment:s,setOpenedModals:o}=e();if(!n||!r){console.error("No token or config found, impossible to start telemetry");return}if(!a||!a.id){console.error("No user found, impossible to start telemetry"),console.log(a,"User");return}if(r.exercises&&r.exercises.length>0){console.log("Starting telemetry");const d=r.exercises.map((g,A)=>({slug:g.slug,position:g.position||A,files:g.files,ai_interactions:[],compilations:[],tests:[],is_testeable:g.graded||!1,is_completed:!1,quiz_submissions:[]})),h=s==="localhost"?(l=r.config)==null?void 0:l.editor.agent:"cloud",f=((u=r.config)==null?void 0:u.slug)||"",p="TELEMETRY";if(!r.config.telemetry){console.error("No telemetry urls found in config");return}if(!d||d.length===0){console.error("No steps found in config, telemetry will not start");return}kh.urls=r.config.telemetry,kh.start(h,d,f,p,{token:n,user_id:String(a.id),email:a.email}),kh.registerListener("compile_struggles",g=>{console.log(g,"In compile struggles")}),kh.registerListener("test_struggles",g=>{g.metrics.streak_test_struggle===3&&o({testStruggles:!0}),g.metrics.streak_test_struggle===9&&o({testStruggles:!0}),g.metrics.streak_test_struggle>=15&&o({testStruggles:!0})}),i("open_step",{step_slug:d[0].slug,step_position:d[0].position})}},setRigoContext:r=>{const{rigoContext:n}=e();t({rigoContext:{...n,...r}})},setShowSidebar:r=>{const{isRigoOpened:n,toggleRigo:a}=e();n&&a({ensure:"close"}),t({showSidebar:r})},setUser:r=>{t({user:r})},useConsumable:async r=>{const{bc_token:n,userConsumables:a}=e();if(!n)return!1;const i=r==="ai-conversation-message"?"ai_conversation_message":"ai_compilation";if(a[i]===0||a[i]===void 0)return!1;if(a[i]<0)return console.log("User consumable is less than 0, it should be a bootcamp student"),!1;const s=await X$e(n,r);return s&&t({userConsumables:{...a,[i]:a[i]-1}}),s},getUserConsumables:async()=>{const{bc_token:r,environment:n,checkParams:a}=e();if(!r)return;const i=await K$e(r),s=sL(i,"ai-compilation"),o=sL(i,"ai-conversation-message"),l=sL(i,"ai-generation");t({userConsumables:{ai_compilation:s,ai_conversation_message:o,ai_generation:l}}),console.table({ai_compilation:s,ai_conversation_message:o,ai_generation:l});const u=(l>0||l===-1)&&n!=="localStorage";t({isCreator:u});const d=a({justReturn:!0});if(u&&d.mode&&d.mode==="teacher"&&t({mode:"creator"}),d.token){const h={...d};delete h.token,hp({...h})}return{ai_compilation:s,ai_conversation_message:o,ai_generation:l}},reportEnrichDataLayer:(r,n)=>{const{configObject:a,agent:i,isIframe:s,user:o,language:l,currentExercisePosition:u,getCurrentExercise:d}=e();mJ({dataLayer:{event:r,method:"learnpack",asset_slug:a.config.slug,path:window.location.href,iframe:s,user_id:o.id,content_type:"exercise",current_step_index:Number(u),current_step_slug:d().slug,agent:i,language:l,...n}})},displayTestButton:My,getTelemetryStep:async r=>await Et.getTelemetryStep(r),setMode:r=>{t({mode:r})},getSidebar:async()=>{const{token:r}=e(),n=await Et.getSidebar(r);return t({sidebar:n}),n},test:async()=>{const{configObject:r}=e();t({currentContent:{body:'\n```loader slug="01-some-title"\n```\n ',bodyBegin:0}}),setTimeout(async()=>{const a=await fetch(`http://localhost:3000/test/${r.config.slug}`,{method:"GET",headers:{"Content-Type":"application/json"}});console.log(a)},3e3)},addVideoTutorial:async r=>{const{getCurrentExercise:n,language:a}=e(),i=await Et.getReadme(n().slug,a);let s=i.attributes;s.tutorial=r;const o=oL(s,i.body);await Et.replaceReadme(n().slug,a,o),t({videoTutorial:r,showVideoTutorial:!0})},replaceInReadme:async(r,n,a)=>{const{getCurrentExercise:i,language:s}=e(),o=await Et.getReadme(i().slug,s);let l=o.body;l=l.slice(0,n.offset)+r+l.slice(a.offset);const u=oL(o.attributes,l);t({currentContent:{body:yJ(u),bodyBegin:o.bodyBegin}}),await Et.replaceReadme(i().slug,s,u);const d=await Et.getReadme(i().slug,s);t({currentContent:{body:d.body,bodyBegin:d.bodyBegin}})},insertBeforeOrAfter:async(r,n,a)=>{const{getCurrentExercise:i,language:s}=e(),o=await Et.getReadme(i().slug,s);let l=o.body;(n==="before"||n==="after")&&(l=l.slice(0,a)+`
398
+ `,s))},fetchExercises:async()=>{const{user_id:r,setOpenedModals:n,environment:a,token:i}=e();if(a==="creatorWeb"){const s=Zi();if(!i||i===""){n({mustLogin:!0}),t({mustLoginMessageKey:"to-access-this-course-you-need-to-login"});return}const{isAuthor:o,status:l}=await Z$e(i,s);if(!o){n(l===403?{notAuthor:!0}:{packageNotFound:!0});return}}try{const s=await Et.getExercises(i);if(!s)return;s.config.authentication&&s.config.authentication.mandatory&&t({authentication:{mandatory:!0}}),s.config.assessment&&s.config.assessment.maxQuizRetries&&t({maxQuizRetries:s.config.assessment.maxQuizRetries}),s.config.warnings&&s.config.warnings.agent&&a!=="localStorage"&&(t({dialogData:{message:s.config.warnings.agent,format:"md"}}),n({dialog:!0})),s.config.warnings&&s.config.warnings.extension&&(t({dialogData:{message:s.config.warnings.extension,format:"md"}}),n({dialog:!0}));const o=s.config.slug;if(R9.dataLayer({dataLayer:{event:"start_exercise",slug:o,user_id:r}}),s.exercises&&s.exercises.length>0&&t({exercises:s.exercises}),s.currentExercise){const l=s.exercises.findIndex(u=>u.slug===s.currentExercise);l!==-1&&t({currentExercisePosition:l})}return s.config.title.us&&t({lessonTitle:s.config.title.us}),t({configObject:s}),s.config.editor&&s.config.editor.agent&&a!=="localStorage"&&t({agent:s.config.editor.agent}),!0}catch(s){return console.log(s,"ERROR"),pJ(),!1}},checkParams:({justReturn:r})=>{const{setLanguage:n,setPosition:a,language:i,setOpenedModals:s}=e();let o=Zx();if(r)return o;const l={language:d=>{i!==d&&n(d,!1)},currentExercise:d=>{a(Number(d))},iframe:d=>{d.toLowerCase()==="true"&&t({isIframe:!0}),d.toLowerCase()==="false"&&t({isIframe:!1})},theme:d=>{["light","dark"].includes(d.toLowerCase().trim())&&t({theme:d})},autoclose:d=>{d.toLowerCase()==="true"&&s({closeWindow:!0})},token:d=>{t({token:d})}},u=Object.entries(o);for(let[d,h]of u)d in l?l[d](h):console.debug(`Unknown param passed: ${d}`);return o},fetchSingleExerciseInfo:async r=>{var d;const{exercises:n}=e();if(n.length<=0)return;const a=(d=n[r])==null?void 0:d.slug;if(!a)return;const i=await Et.getExerciseInfo(a);let s=i.graded,o,l=!1;i.entry&&(o=!0),i.language||(o=!1);const u=i.files.filter(h=>h.name.includes("solution.hide"));if(u.length>0){l=!0;let h=await Et.getFileContent(a,u[0].name);t({currentSolution:h.fileContent})}return t({isTesteable:s,isBuildable:o,hasSolution:l}),i},setPosition:r=>{const{startConversation:n,fetchReadme:a,token:i,setBuildButtonPrompt:s,setFeedbackButtonProps:o,checkParams:l,registerTelemetryEvent:u}=e();let d=l({justReturn:!0});hp({...d,currentExercise:String(r)}),t({currentExercisePosition:r}),i&&n(r),s("execute-my-code",""),o("test-my-code",""),t({lastState:""}),u("open_step",{step_position:r}),a()},startConversation:async r=>{const{token:n,learnpackPurposeId:a,conversationIdsCache:i}=e();let s=null,o=null;if(n){try{if(s=i[r],!s)throw new Error("ConversationID not found in cache")}catch{o=await lFe(a,n),s=o.conversation_id}o&&o.salute&&t({chatInitialMessage:o.salute}),t({conversationIdsCache:{...i,[r]:s}}),w5.emit("start",{token:n,purpose:a,conversationId:s})}},loginToRigo:async r=>{const{setToken:n,startConversation:a,currentExercisePosition:i,setOpenedModals:s,language:o,reportEnrichDataLayer:l,getOrCreateActiveSession:u,getUserConsumables:d}=e();try{const h=await Et.login(r);if(t({bc_token:h.token,user_id:h.user_id,user:h.user}),h.rigobot==null)throw new e5("No rigobot user found, did you already accept Rigobot's invitation?");n(h.rigobot.key),Ar.success(r.messages.success,{icon:"✅"}),l("session_load",{method:"native",user_id:h.user_id,language:o,path:window.location.href,agent:"cloud"}),d()}catch(h){return h instanceof e5?(s({login:!1,rigobotInvite:!0}),!1):(Ar.error(r.messages.error),!1)}return a(Number(i)),s({login:!1}),u(),!0},checkRigobotInvitation:async r=>{try{const{bc_token:n,setToken:a,openLink:i,language:s,environment:o}=e(),l=()=>{const f="https://rigobot.herokuapp.com/invite?referer=4geeks&lang="+hFe(s)+"&token="+n+"&callback="+fFe(window.location.href+"?autoclose=true");i(f)},u=`${ml}/v1/auth/me/token?breathecode_token=${n}`,d=await fetch(u);if(d.status!=200)return Ar.error(r.error,{icon:at.rigoSvg}),l(),!1;const h=await d.json();if(console.log("DATA FROM RIGOBOT INVITATION",h),a(h.key),o==="localhost"){const f={token:h.key},p={method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)};await fetch(`${qy}/set-rigobot-token`,p)}return h.key}catch(n){return console.log(n,"ERROR"),!1}},openLink:(r,n={redirect:!1})=>{const{compilerSocket:a,getCurrentExercise:i}=e(),s={...n},o={url:r,exerciseSlug:i().slug,options:s};a.openWindow(o)},updateEditorTabs:(r=null)=>{const{getCurrentExercise:n,editorTabs:a,setAllowedActions:i,environment:s}=e(),o=n(),l=o.files.filter(h=>!h.hidden);let u=[...a];if(r)if(u.some(f=>f.name===r.name)){const f=u.findIndex(p=>p.name===r.name);u[f]={...r,isActive:r.name!=="terminal"}}else r.name==="terminal"?u.push({...r,isActive:!1}):(u=u.map(f=>({...f,isActive:!1})),u.push({...r,isActive:!0}));(async()=>{for(const[f,p]of l.entries()){let g="";const{fileContent:A,edited:m}=await Et.getFileContent(o.slug,p.name,{cached:!0});g=A,"content"in p&&p.content!==g&&await Et.saveFileContent(o.slug,p.name,g);const y=u.some(w=>w.name===p.name),v={id:f,content:g,name:p.name,isActive:f===0&&!r,modified:m};if(!y)u=[...u,v];else{const w=u.findIndex(k=>k.name===p.name);u[w]=v}}!u.some(f=>f.isActive)&&u.length>0&&(u[0].isActive=!0),t({editorTabs:[...u]}),u.length>0&&s==="localStorage"&&i(["tutorial","test","build"])})()},cleanTerminal:()=>{const{editorTabs:r}=e(),n=r.filter(a=>a.name!=="terminal");t({editorTabs:[...n]})},fetchReadme:async()=>{var h;const{language:r,exercises:n,currentExercisePosition:a,fetchSingleExerciseInfo:i,configObject:s,updateEditorTabs:o}=e(),l=(h=n[a])==null?void 0:h.slug;if(!l)return;const u=await Et.getReadme(l,r);if(!u)return;u.attributes&&u.attributes.tutorial?t({videoTutorial:u.attributes.tutorial}):u.attributes.intro?t({videoTutorial:u.attributes.intro,showVideoTutorial:!0}):t({videoTutorial:"",showVideoTutorial:!1});let d=gJ(u.body,"{{publicUrl}}",qy);if(typeof s.config.variables=="object")for(let f in s.config.variables)d=gJ(d,`{{${f}}}`,s.config.variables[f]);return t({currentContent:{body:d,bodyBegin:u.bodyBegin}}),t({editorTabs:[]}),i(a),o(),!0},toggleSidebar:()=>{sFe()},setLanguage:(r,n=!0)=>{const{fetchReadme:a,checkParams:i}=e();t({language:r});let s=i({justReturn:!0});hp({...s,language:r}),n&&a()},openTerminal:()=>{const{compilerSocket:r,getCurrentExercise:n}=e(),a={exerciseSlug:n().slug};r.emit("open_terminal",a)},handleNext:()=>{const{currentExercisePosition:r,handlePositionChange:n}=e();n(Number(r)+1)},getSyllabus:async()=>{const{environment:r}=e();if(r!=="creatorWeb")return[];const n=await Et.getSyllabus();return!n||n.length===0?[]:(t({syllabus:n}),n)},checkExerciseAvailability:async r=>{const{exercises:n,environment:a,syllabus:i,setOpenedModals:s}=e();return a!=="creatorWeb"||!n||n.length===0||!i||i.lessons.length===0||i.lessons[r].generated?!0:(s({syllabusFeedback:!0}),!1)},handlePositionChange:async r=>{const{configObject:n,currentExercisePosition:a,exercises:i,setPosition:s,isTesteable:o,runExerciseTests:l}=e();if(!n||!n.config){console.log("Impossible to continue, the configuration is not ready!");return}isNaN(r)&&(r=0);const u=n.config.grading,d=i.length-1;if(r>d||r<0){Ar.error("The exercise you are looking for does not exist!");return}if(r==a)return;let h=!0;if(r>Number(a)&&(h=!o||u==="isolated"||u==="incremental"&&i[a].done),!h){l({toast:!0,setFeedbackButton:!0,feedbackButtonText:"Running...",targetButton:"feedback"});return}s(Number(r))},toastFromStatus:r=>{const{language:n}=e(),[a,i]=o5(r,n);let s=1500;r==="testing-error"&&(s=3e3),Ar.success(i,{icon:a,duration:s})},setTestResult:(r,n)=>{const{exercises:a,currentExercisePosition:i,updateDBSession:s}=e(),o=[...a];o[Number(i)].done=r==="successful",t({exercises:o}),s()},setShouldBeTested:r=>{t({shouldBeTested:r})},build:async(r,n=[])=>{const{setBuildButtonPrompt:a,compilerSocket:i,getCurrentExercise:s,editorTabs:o,token:l,updateEditorTabs:u,setOpenedModals:d,setEditorTabs:h,environment:f,userConsumables:p,bc_token:g,toastFromStatus:A,reportEnrichDataLayer:m}=e();if(!g||!l){d({mustLogin:!0});return}if(f==="localStorage"&&!(p.ai_compilation>0||p.ai_compilation===-1)){d({limitReached:!0}),m("learnpack_consumable_depleted ",{service_slug:"ai_compilation"});return}o.find(v=>v.name==="terminal")&&h(o.map(v=>v.name==="terminal"?{...v,content:""}:v)),a(r,""),A("compiling");const y={exerciseSlug:s().slug,token:l,updateEditorTabs:u,editorTabs:o,submittedInputs:n};i.emit("build",y),t({lastStartedAt:new Date}),m("learnpack_run",{})},setEditorTabs:r=>{t({editorTabs:r})},runExerciseTests:async(r,n=[])=>{const{compilerSocket:a,getCurrentExercise:i,setFeedbackButtonProps:s,toastFromStatus:o,token:l,updateEditorTabs:u,setOpenedModals:d,editorTabs:h,language:f,setEditorTabs:p,bc_token:g,environment:A,userConsumables:m,currentContent:y}=e();if(!l||!g){d({mustLogin:!0});return}if(A==="localStorage"&&!(m.ai_compilation>0||m.ai_compilation===-1)){d({limitReached:!0});return}h.find(w=>w.name==="terminal")&&p(h.map(w=>w.name==="terminal"?{...w,content:""}:w));const v={exerciseSlug:i().slug,token:l,updateEditorTabs:u,editorTabs:h,submittedInputs:n,language:f,instructions:y.body};a.emit("test",v),t({shouldBeTested:!1}),r!=null&&r.targetButton&&t({targetButtonForFeedback:r.targetButton}),r&&r.setFeedbackButton&&r.targetButton==="feedback"&&r.feedbackButtonText&&s(r.feedbackButtonText,"palpitate"),r&&r.toast&&o("testing")},getOrCreateActiveSession:async()=>{const{token:r,configObject:n,setOpenedModals:a,updateEditorTabs:i,tabHash:s,checkParams:o}=e();let l=s;if(!o({justReturn:!0}).autoclose&&r){l||(l=await Et.getTabHash(),t({tabHash:l}));try{console.log(n,"configObject");const d=await Dee(r,n.config.slug);if(console.log(d,"session"),d.tab_hash||(await TL(r,l,n.config.slug,n,d.key),t({sessionKey:d.key})),d.tab_hash&&d.tab_hash!==l){a({session:!0});return}else if(d.tab_hash&&d.tab_hash===l)t({configObject:d.config_json}),t({sessionKey:d.key}),await Et.setSessionKey(d.key),i();else{t({sessionKey:d.key});return}}catch(d){console.error(d),console.log("Error trying to get session")}}},updateDBSession:async()=>{const{configObject:r,exercises:n,token:a,tabHash:i,sessionKey:s,getCurrentExercise:o}=e(),l=o(),u={...r,exercises:n,currentExercise:l.slug};let d="";s||(d=await Et.getSessionKey()),await TL(a,i,r.config.slug,u,s||d)},updateFileContent:async(r,n,a=!1)=>{const{exercises:i,updateEditorTabs:s,setShouldBeTested:o}=e();let l=i.map(u=>u.slug===r?{...u,files:u.files.map(d=>d.name===n.name?{...d,content:n.content,modified:!0}:d)}:u);await Et.saveFileContent(r,n.name,n.content),t({exercises:l}),o(!0),a&&s()},resetExercise:({exerciseSlug:r})=>{const{updateEditorTabs:n,exercises:a,compilerSocket:i,updateDBSession:s,setEditorTabs:o,editorTabs:l,reportEnrichDataLayer:u}=e();l.find(f=>f.name==="terminal")&&o(l.filter(f=>f.name!=="terminal"));let d=a.map(f=>f.slug===r?{...f,files:f.files.map(p=>(delete p.content,delete p.modified,p))}:f);t({exercises:d,lastState:""}),s();const h={exerciseSlug:r,updateEditorTabs:n};i.emit("reset",h),u("learnpack_reset",{})},sessionActions:async({action:r="new"})=>{const{configObject:n,token:a,updateEditorTabs:i,tabHash:s,handlePositionChange:o}=e();let l=s;if(l||(l=await Et.getTabHash()),r==="new"){const u=await Y$e(a,s,n.config.slug,n);await Et.setSessionKey(u.key),t({sessionKey:u.key})}if(r==="continue"){const u=await Dee(a,n.config.slug);if(await TL(a,s,n.config.slug,null,u.key),t({configObject:u.config_json,sessionKey:u.key}),u.config_json.exercises&&u.config_json.exercises.length>0&&u.config_json.currentExercise){const d=u.config_json.exercises.findIndex(h=>h.slug===u.config_json.currentExercise);o(d)}await Et.setSessionKey(u.key),i()}},refreshDataFromAnotherTab:({newToken:r,newTabHash:n,newBCToken:a})=>{const{token:i,bc_token:s,tabHash:o,getOrCreateActiveSession:l}=e();i!==r&&t({token:r}),s!==a&&t({bc_token:a}),o!==n&&t({tabHash:n}),l()},toggleTheme:()=>{const{theme:r,checkParams:n}=e();let a=n({justReturn:!0});r==="dark"?(hp({...a,theme:"light"}),t({theme:"light"})):(hp({...a,theme:"dark"}),t({theme:"dark"}))},toggleRigo:r=>{const{token:n,isRigoOpened:a,setOpenedModals:i,showSidebar:s,setShowSidebar:o}=e();if(!n){i({mustLogin:!0});return}if(s&&o(!1),r&&r.ensure==="open"){t({isRigoOpened:!0});return}if(r&&r.ensure==="close"){t({isRigoOpened:!1});return}t({isRigoOpened:!a})},registerTelemetryEvent:(r,n)=>{const{currentExercisePosition:a}=e();kh.registerStepEvent(Number(a),r,n)},startTelemetry:async()=>{var l,u;const{configObject:r,bc_token:n,user:a,registerTelemetryEvent:i,environment:s,setOpenedModals:o}=e();if(!n||!r){console.error("No token or config found, impossible to start telemetry");return}if(!a||!a.id){console.error("No user found, impossible to start telemetry"),console.log(a,"User");return}if(r.exercises&&r.exercises.length>0){console.log("Starting telemetry");const d=r.exercises.map((g,A)=>({slug:g.slug,position:g.position||A,files:g.files,ai_interactions:[],compilations:[],tests:[],is_testeable:g.graded||!1,is_completed:!1,quiz_submissions:[]})),h=s==="localhost"?(l=r.config)==null?void 0:l.editor.agent:"cloud",f=((u=r.config)==null?void 0:u.slug)||"",p="TELEMETRY";if(!r.config.telemetry){console.error("No telemetry urls found in config");return}if(!d||d.length===0){console.error("No steps found in config, telemetry will not start");return}kh.urls=r.config.telemetry,kh.start(h,d,f,p,{token:n,user_id:String(a.id),email:a.email}),kh.registerListener("compile_struggles",g=>{console.log(g,"In compile struggles")}),kh.registerListener("test_struggles",g=>{g.metrics.streak_test_struggle===3&&o({testStruggles:!0}),g.metrics.streak_test_struggle===9&&o({testStruggles:!0}),g.metrics.streak_test_struggle>=15&&o({testStruggles:!0})}),i("open_step",{step_slug:d[0].slug,step_position:d[0].position})}},setRigoContext:r=>{const{rigoContext:n}=e();t({rigoContext:{...n,...r}})},setShowSidebar:r=>{const{isRigoOpened:n,toggleRigo:a}=e();n&&a({ensure:"close"}),t({showSidebar:r})},setUser:r=>{t({user:r})},useConsumable:async r=>{const{bc_token:n,userConsumables:a}=e();if(!n)return!1;const i=r==="ai-conversation-message"?"ai_conversation_message":"ai_compilation";if(a[i]===0||a[i]===void 0)return!1;if(a[i]<0)return console.log("User consumable is less than 0, it should be a bootcamp student"),!1;const s=await X$e(n,r);return s&&t({userConsumables:{...a,[i]:a[i]-1}}),s},getUserConsumables:async()=>{const{bc_token:r,environment:n,checkParams:a}=e();if(!r)return;const i=await K$e(r),s=sL(i,"ai-compilation"),o=sL(i,"ai-conversation-message"),l=sL(i,"ai-generation");t({userConsumables:{ai_compilation:s,ai_conversation_message:o,ai_generation:l}}),console.table({ai_compilation:s,ai_conversation_message:o,ai_generation:l});const u=(l>0||l===-1)&&n!=="localStorage";t({isCreator:u});const d=a({justReturn:!0});if(u&&d.mode&&d.mode==="teacher"&&t({mode:"creator"}),d.token){const h={...d};delete h.token,hp({...h})}return{ai_compilation:s,ai_conversation_message:o,ai_generation:l}},reportEnrichDataLayer:(r,n)=>{const{configObject:a,agent:i,isIframe:s,user:o,language:l,currentExercisePosition:u,getCurrentExercise:d}=e();mJ({dataLayer:{event:r,method:"learnpack",asset_slug:a.config.slug,path:window.location.href,iframe:s,user_id:o.id,content_type:"exercise",current_step_index:Number(u),current_step_slug:d().slug,agent:i,language:l,...n}})},displayTestButton:My,getTelemetryStep:async r=>await Et.getTelemetryStep(r),setMode:r=>{t({mode:r})},getSidebar:async()=>{const{token:r}=e(),n=await Et.getSidebar(r);return t({sidebar:n}),n},test:async()=>{const{configObject:r}=e();t({currentContent:{body:'\n```loader slug="01-some-title"\n```\n ',bodyBegin:0}}),setTimeout(async()=>{const a=await fetch(`http://localhost:3000/test/${r.config.slug}`,{method:"GET",headers:{"Content-Type":"application/json"}});console.log(a)},3e3)},addVideoTutorial:async r=>{const{getCurrentExercise:n,language:a}=e(),i=await Et.getReadme(n().slug,a);let s=i.attributes;s.tutorial=r;const o=oL(s,i.body);await Et.replaceReadme(n().slug,a,o),t({videoTutorial:r,showVideoTutorial:!0})},replaceInReadme:async(r,n,a)=>{const{getCurrentExercise:i,language:s}=e(),o=await Et.getReadme(i().slug,s);let l=o.body;l=l.slice(0,n.offset)+r+l.slice(a.offset);const u=oL(o.attributes,l);t({currentContent:{body:yJ(u),bodyBegin:o.bodyBegin}}),await Et.replaceReadme(i().slug,s,u);const d=await Et.getReadme(i().slug,s);t({currentContent:{body:d.body,bodyBegin:d.bodyBegin}})},insertBeforeOrAfter:async(r,n,a)=>{const{getCurrentExercise:i,language:s}=e(),o=await Et.getReadme(i().slug,s);let l=o.body;(n==="before"||n==="after")&&(l=l.slice(0,a)+`
399
399
 
400
400
  `+r+`
401
401
 
package/src/ui/app.tar.gz CHANGED
Binary file