{"id":28742022,"url":"https://github.com/liaplayground/oer-hackathon-2025","last_synced_at":"2026-02-02T17:38:07.086Z","repository":{"id":290362148,"uuid":"974180704","full_name":"LiaPlayground/OER-Hackathon-2025","owner":"LiaPlayground","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-28T11:32:06.000Z","size":8,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-28T12:41:19.900Z","etag":null,"topics":["gottingen-uni","hackathon","liascript","liascript-course","oer"],"latest_commit_sha":null,"homepage":"https://liascript.github.io/course/?https://raw.githubusercontent.com/LiaPlayground/OER-Hackathon-2025/refs/heads/main/README.md","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiaPlayground.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-28T11:31:15.000Z","updated_at":"2025-04-28T12:17:29.000Z","dependencies_parsed_at":"2025-04-28T12:42:21.429Z","dependency_job_id":"c38c2fea-dba4-43bb-bab3-de5086972d46","html_url":"https://github.com/LiaPlayground/OER-Hackathon-2025","commit_stats":null,"previous_names":["liaplayground/oer-hackathon-2025"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LiaPlayground/OER-Hackathon-2025","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaPlayground%2FOER-Hackathon-2025","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaPlayground%2FOER-Hackathon-2025/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaPlayground%2FOER-Hackathon-2025/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaPlayground%2FOER-Hackathon-2025/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiaPlayground","download_url":"https://codeload.github.com/LiaPlayground/OER-Hackathon-2025/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiaPlayground%2FOER-Hackathon-2025/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260124225,"owners_count":22962210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gottingen-uni","hackathon","liascript","liascript-course","oer"],"created_at":"2025-06-16T08:13:55.181Z","updated_at":"2026-02-02T17:38:02.052Z","avatar_url":"https://github.com/LiaPlayground.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n\nauthor: André Dietrich; Sebastian Zug\n\nemail:  LiaScript@web.de\n\nlogo:   media/logo.jpg\n\nscript: https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js\n\nimport: https://raw.githubusercontent.com/liaTemplates/ABCjs/main/README.md\n        https://raw.githubusercontent.com/LiaTemplates/GGBScript/refs/heads/main/README.md\n\n@style\n@keyframes burn {\n  0% {\n    text-shadow: 0 0 5px #ff0, 0 0 10px #ff0, 0 0 15px #f00, 0 0 20px #f00,\n      0 0 25px #f00, 0 0 30px #f00, 0 0 35px #f00;\n  }\n  50% {\n    text-shadow: 0 0 10px #ff0, 0 0 15px #ff0, 0 0 20px #ff0, 0 0 25px #f00,\n      0 0 30px #f00, 0 0 35px #f00, 0 0 40px #f00;\n  }\n  100% {\n    text-shadow: 0 0 5px #ff0, 0 0 10px #ff0, 0 0 15px #f00, 0 0 20px #f00,\n      0 0 25px #f00, 0 0 30px #f00, 0 0 35px #f00;\n  }\n}\n\n.burning-text {\n  font-weight: bold;\n  color: #fff;\n  animation: burn 1.5s infinite alternate;\n}\n@end\n\n@burn: \u003cspan class=\"burning-text\"\u003e@0\u003c/span\u003e\n\n@WebSerial\n\u003cscript\u003e\n(async function() {\n  // Check if the Web Serial API is supported.\n  if (!(\"serial\" in navigator)) {\n    console.error(\"Web Serial API is not supported in this browser.\");\n    return;\n  }\n\n  // Declare connection-related variables for later cleanup.\n  let port = null;\n  let reader = null;\n\n  try {\n    // Request and open the serial port.\n    port = await navigator.serial.requestPort();\n    await port.open({ baudRate: 115200 });\n\n    // Create a TextEncoder instance.\n    const encoder = new TextEncoder();\n    // Function to stop any currently running code by sending Ctrl-C.\n    async function stopCurrentProgram() {\n      try {\n        const writer = port.writable.getWriter();\n        // Send Ctrl-C (ASCII 0x03) to interrupt any running code.\n        await writer.write(encoder.encode(\"\\x03\"));\n        // Wait briefly to allow the interrupt to be processed.\n        await new Promise(resolve =\u003e setTimeout(resolve, 100));\n        // Send a second Ctrl-C in case the first one was missed.\n        await writer.write(encoder.encode(\"\\x03\"));\n        writer.releaseLock();\n      } catch (e) {\n        console.error(\"Error sending Ctrl-C:\", e);\n      }\n    }\n\n    // Stop any running code before sending new code.\n    await stopCurrentProgram();\n\n    // Retrieve the entire Python code from the liascript input.\n    const pythonCode = `@input(0)`;\n\n    // Function to send code using MicroPython's paste mode.\n    // In paste mode, the REPL buffers all lines until Ctrl‑D is received,\n    // then it compiles and executes the entire code block at once.\n    async function sendCodeInPasteMode(code) {\n      const writer = port.writable.getWriter();\n      // Enter paste mode (Ctrl‑E, ASCII 0x05).\n      await writer.write(encoder.encode(\"\\x05\"));\n      // Wait briefly for paste mode to be activated.\n      await new Promise(resolve =\u003e setTimeout(resolve, 100));\n\n      // Split the code into lines, preserving all indentation.\n      const codeLines = code.split(/\\r?\\n/);\n      for (const line of codeLines) {\n        // Send each line exactly as-is, with CR+LF.\n        await writer.write(encoder.encode(line + \"\\r\\n\"));\n      }\n      // Exit paste mode by sending Ctrl‑D (ASCII 0x04).\n      await writer.write(encoder.encode(\"\\x04\"));\n      writer.releaseLock();\n      send.lia(\"LIA: terminal\");\n    }\n\n    // Function that sends the code and reads output until the REPL prompt (\"\u003e\u003e\u003e\") is detected.\n    // This ensures the entire block is executed before further input is allowed.\n    async function sendCodeAndWaitForPrompt(code) {\n      await sendCodeInPasteMode(code);\n      let outputBuffer = \"\";\n      const tempReader = port.readable.getReader();\n      const decoder = new TextDecoder();\n      let promptFound = false;\n\n      while (!promptFound) {\n        const { value, done } = await tempReader.read();\n        if (done) break;\n        if (value) {\n          const text = decoder.decode(value);\n          outputBuffer += text;\n          console.stream(text);\n          // Look for the REPL prompt (adjust if your prompt differs).\n          if (outputBuffer.includes(\"\u003e\u003e\u003e\")) {\n            promptFound = true;\n          }\n        }\n      }\n      await tempReader.releaseLock();\n      return outputBuffer;\n    }\n\n    // Send the Python code and wait until the prompt is detected.\n    await sendCodeAndWaitForPrompt(pythonCode);\n    console.log(\"Python code executed and prompt detected.\");\n\n    // Now that execution is complete, enable terminal input.\n    send.lia(\"LIA: terminal\");\n\n    // Start a global read loop to capture and display subsequent output.\n    reader = port.readable.getReader();\n    const globalDecoder = new TextDecoder();\n    (async function readLoop() {\n      try {\n        while (true) {\n          const { value, done } = await reader.read();\n          if (done) {\n            console.debug(\"Stream closed\");\n            send.lia(\"LIA: stop\");\n            break;\n          }\n          if (value) {\n            console.stream(globalDecoder.decode(value));\n          }\n        }\n      } catch (error) {\n        console.error(\"Read error:\", error);\n      } finally {\n        try { reader.releaseLock(); } catch (e) { /* ignore */ }\n      }\n    })();\n\n    // Handler to send terminal input lines to MicroPython.\n    send.handle(\"input\", input =\u003e {\n      (async function() {\n        try {\n          const writer = port.writable.getWriter();\n          // Send the terminal input (preserving any whitespace) with CR+LF.\n          await writer.write(encoder.encode(input + \"\\r\\n\"));\n          writer.releaseLock();\n        } catch (e) {\n          console.error(\"Error sending input to MicroPython:\", e);\n        }\n      })();\n    });\n\n    // Handler to clean up all connections and variables when a \"stop\" command is received.\n    send.handle(\"stop\", async () =\u003e {\n      console.log(\"Cleaning up connections and stopping execution.\");\n\n      // Cancel the reader if it exists.\n      if (reader) {\n        try {\n          await reader.cancel();\n        } catch (e) {\n          console.error(\"Error canceling reader:\", e);\n        }\n        try { reader.releaseLock(); } catch (e) { /* ignore */ }\n      }\n\n      // Close the serial port if it's open.\n      if (port) {\n        try {\n          await port.close();\n        } catch (e) {\n          console.error(\"Error closing port:\", e);\n        }\n      }\n\n      // Reset connection variables.\n      port = null;\n      reader = null;\n      console.log(\"Cleanup complete.\");\n    });\n\n  } catch (error) {\n    console.error(\"Error connecting to the MicroPython device:\", error);\n    send.lia(\"LIA: stop\");\n  }\n})();\n\n\"LIA: wait\"\n\u003c/script\u003e\n@end\n\n--\u003e\n\n\n# OER-Hackathon LiaScript\n\n![hackthon](https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExcDhibzBpbzQ4YjN5Z3h3Mng5dXB6dW9jbGNmbTlhdHA2OXZsbDFyYyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Pt1dNUR9Zttkt9FEyA/giphy.gif)\n\n---\n\nTU Bergakademie Freiberg\n------------------------\n\nAndré Dietrich \u0026 Sebastian Zug\n==============================\n\n[andre.dietrich@informatik.tu-freiberg.de](mailto:andre.dietrich@informatik.tu-freiberg.de) \u0026 [sebastian.zug@informatik.tu-freiberg.de](mailto:sebastian.zug@informatik.tu-freiberg.de)\n-----------------------------------------\n\n## LiaScript: Hello World\n\n    --{{0}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_0.webm)\nHello, my name is LiaScript, I am a Markdown-based language that has been specially developed to create educational materials.\nThe advantage of Markdown is that it is already widely used, easy to write and read, and supported by many platforms.\nThe biggest drawback, however, is that it is @burn(static as hell) and offers no interactivity.\n\n     {{1-2}}\n\u003csection\u003e\n\n    --{{1}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_1.webm)\nSo my creators set out to rethink Markdown from the ground up...\n\n?[Giorgio Moroder](https://music.youtube.com/watch?v=zhl-Cs1-sG4\u0026si=fwB6LT2I0rQ0_CGE\u0026start=301\u0026end=312\u0026autoplay=1)\u003c!-- style=\"border-radius: 10px; border: none\" --\u003e\n\n\u003e \u003cmarquee\u003e... Once you free your mind about a concept of Harmony and of music being \"correct\" you can do whatever you want ...\u003c/marquee\u003e\n\u003e\n\u003e -- Giorgio Moroder (inventor of disco music)\n\n\u003c/section\u003e\n\n    --{{2}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_2.webm)\nActually, tables in Markdown are simple to create and, as mentioned, are quite @burn(static).\nHowever, a table can also represent a dataset that strives for its ideal visualization.\n\n      {{2}}\n| Animal                  | Weight in kg | Lifespan (years) | Mitogen |\n| ----------------------- | -----------: | ---------------: | ------: |\n| Mouse                   |      0.028 |               02 |      95 |\n| Flying Squirrel         |      0.085 |               15 |      50 |\n| Brown Bat               |      0.020 |               30 |      10 |\n| Sheep                   |         90 |               12 |      95 |\n| Human                   |         68 |               70 |      10 |\n\n    --{{3}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_3.webm)\nAnother tabular structure can produce a different visualization that can be fine-tuned by the creator.\nIn total, I support 10 different types of visualizations.\n\n      {{3}}\n\u003c!--\ndata-type=\"heatmap\"\ndata-title=\"Seattle Average Temperature in Fahrenheit\"\ndata-show\n--\u003e\n| Seattle |  Jan |  Feb |  Mar |  Apr |  May |  Jun |  Jul |  Aug |  Sep |  Oct |  Nov |  Dec |\n| -------:| ----:| ----:| ----:| ----:| ----:| ----:| ----:| ----:| ----:| ----:| ----:| ----:|\n|       0 | 40.7 | 41.5 | 43.6 | 46.6 | 51.4 | 56.0 | 60.5 | 61.2 | 57.0 | 50.1 | 44.1 | 39.6 |\n|       2 | 40.2 | 40.7 | 42.7 | 45.3 | 50.0 | 54.4 | 58.5 | 59.2 | 55.4 | 49.2 | 43.5 | 39.3 |\n|       4 | 39.7 | 40.0 | 41.9 | 44.4 | 48.9 | 53.2 | 57.0 | 57.7 | 54.2 | 48.6 | 43.1 | 38.9 |\n|       6 | 39.6 | 39.5 | 41.3 | 44.2 | 49.5 | 54.2 | 57.8 | 57.4 | 53.6 | 48.2 | 42.8 | 38.7 |\n|       8 | 39.6 | 39.9 | 42.9 | 47.1 | 52.7 | 57.3 | 61.3 | 61.1 | 56.7 | 49.5 | 43.1 | 38.7 |\n|      10 | 41.3 | 42.7 | 46.4 | 50.7 | 56.4 | 60.9 | 65.2 | 65.4 | 60.9 | 52.8 | 45.5 | 40.4 |\n|      12 | 43.8 | 46.0 | 49.5 | 53.8 | 59.6 | 64.3 | 69.4 | 69.8 | 65.1 | 56.0 | 47.8 | 42.6 |\n|      14 | 45.1 | 47.7 | 51.3 | 55.9 | 61.9 | 66.9 | 72.6 | 73.2 | 67.7 | 57.8 | 48.8 | 43.6 |\n|      16 | 44.5 | 47.5 | 51.4 | 55.9 | 62.3 | 67.5 | 73.9 | 74.3 | 68.2 | 57.4 | 47.8 | 42.6 |\n|      18 | 42.6 | 44.7 | 48.7 | 53.8 | 60.3 | 65.9 | 72.3 | 72.2 | 64.6 | 53.9 | 46.0 | 41.2 |\n|      20 | 42.0 | 43.3 | 46.4 | 50.2 | 56.0 | 61.4 | 66.9 | 66.6 | 60.7 | 52.3 | 45.2 | 40.7 |\n|      22 | 41.4 | 42.5 | 45.0 | 48.3 | 53.5 | 58.2 | 63.2 | 63.5 | 58.7 | 51.1 | 44.5 | 40.1 |\n\n    --{{4}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_4.webm)\nWhat Markdown has always lacked was the embedding of multimedia content ...\n\n    --{{5}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_5.webm)\nI support audio content ...\n\n     {{5-6}}\n?[a horse](https://www.w3schools.com/html/horse.mp3 \"hear a horse\")\n\n    --{{6}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_6.webm)\nI can handle video as well, and of course, I work on feature phones even if they are offline.\n\n     {{6-7}}\n!?[LiaScript on Nokia](https://www.youtube.com/watch?v=U_UW69w0uHE)\n\n    --{{7}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_7.webm)\nI can also try to embed other types of content that do not fall into either of the two categories\n\n      {{7}}\n??[Esther’s scroll in a cover](https://sketchfab.com/3d-models/esthers-scroll-in-a-cover-21a13eba33cb4343bab56f0c0f982876 \"Historical Museum of the City of Kraków\")\n\n    --{{8}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_8.webm)\nAnd much, much more... We will soon show you how everything works.\n\n      {{8}}\n```abc\nX: 1\nM: 4/4\nL: 1/8\nK: Emin\n|:D2|\"Em\"EBBA B2 EB|~B2 AB dBAG|\"D\"FDAD BDAD|FDAD dAFD|\n\"Em\"EBBA B2 EB|B2 AB defg|\"D\"afe^c dBAF|\"Em\"DEFD E2:|\n```\n@ABCJS.eval\n\n    --{{9}}--\n!?[](https://raw.githubusercontent.com/LiaPlayground/Expert-Meeting-on-AI-and-TVET-2025/refs/heads/main/media/liascript_9.webm)\nYou might have noticed that this document is being used like a PowerPoint presentation.\nHowever, our intention was to utilize LiaScript in various contexts.\nWith LiaScript, you can create presentations, enable self-study through browser-based text-to-speech output, or read the content as a simple yet interactive textbook, without animations.\n\n## Our Goal\n\nImprove the Exporter\n--------------------\n\n* https://www.npmjs.com/package/@liascript/exporter\n* https://liascript.github.io/exporter/\n\n!?[Exporter](https://www.youtube.com/watch?v=yk4uEqoKcpw)\n\n1. localhost \u0026 globalhost mit besserem UI/UX\n2. Konvertierung in ausführbare Datei (Winow.exe, Linux.out, Mac.wasAuchImmer)\n3. Addon ... Bibliothek, die in verschiedenen Editoren als Plugin eingebettet werden kann\n\n## Programming\n\n### WebSerial \u0026 MicroPython\n\u003c!--\npersistent: true\n--\u003e\n\n\n\n``` python\nfrom microbit import *\n\n# Display a scrolling message\ndisplay.scroll(\"Hello edrys!\")\n\n# Read the temperature\ntemp = temperature()\nprint(\"Temperature:\", temp)\n\n# Display a heart on the LED matrix\ndisplay.show(Image.HEART)\n```\n@WebSerial\n\n\n\u003cvideo autoplay=\"false\" id=\"videoElement\" style=\"display: none; width: 100%; padding: 5px\"\u003e\u003c/video\u003e\n\n\u003cscript input=\"submit\" default=\"Open Camera\"\u003e\nconst video = document.querySelector(\"#videoElement\")\n\nif (video.srcObject === null) {\n    if (navigator.mediaDevices.getUserMedia) {\n        navigator.mediaDevices.getUserMedia({ video: true })\n            .then(function (stream) {\n                video.srcObject = stream\n                video.style.display = \"block\"\n                send.lia(\"Close Camera\")\n            })\n            .catch(function (error) {\n                console.log(\"Something went wrong!\")\n                send.lia(\"Camera Problem\")\n            });\n\n        send.output(\"Waiting for Camera\")\n        \"LIA: wait\"\n    } else {\n        \"No Camera connected\"\n    }\n} else {\n    const tracks = video.srcObject.getTracks()\n    // Stop all tracks\n    tracks.forEach(track =\u003e track.stop())\n    video.style.display = \"none\"\n    video.srcObject = null\n    \"Open Camera\"\n}\n\u003c/script\u003e\n\n\n### Interactive Geometry\n\n\n\u003e Source: https://github.com/LiaTemplates/GGBScript\n\u003e\n\u003e A GGBScript JavaScript interpreter based on JavaScript.\n\u003e\n\u003e `import: https://raw.githubusercontent.com/LiaTemplates/GGBScript/refs/heads/main/README.md`\n\n\n``` js @GGBScript\nTitel(\"Punkt A \u0026 B\");\n\n// Definiere einen Punkt\nconst A = Punkt(1, 2, \"A\");\nconst B = Punkt([4, 6], \"B\");\n```\n\n### Interactive Geometry 2\n\nA = (\u003cscript input=\"range\" min=\"0\" max=\"100\" value=\"50\" step=\"1\" default=\"50\" output=\"A0\"\u003e\n@input\n\u003c/script\u003e,\n\u003cscript input=\"range\" min=\"-100\" max=\"100\" value=\"50\" step=\"1\" default=\"50\" output=\"A1\"\u003e\n@input\n\u003c/script\u003e\n)\n\nB = (\u003cscript input=\"range\" min=\"0\" max=\"100\" value=\"96\" step=\"1\" default=\"96\" output=\"B0\"\u003e\n@input\n\u003c/script\u003e,\n\u003cscript input=\"range\" min=\"-100\" max=\"100\" value=\"27\" step=\"1\" default=\"27\" output=\"B1\"\u003e\n@input\n\u003c/script\u003e\n)\n\n\nC = (\u003cscript input=\"range\" min=\"0\" max=\"100\" value=\"20\" step=\"1\" default=\"20\" output=\"C0\"\u003e\n@input\n\u003c/script\u003e,\n\u003cscript input=\"range\" min=\"-100\" max=\"100\" value=\"20\" step=\"1\" default=\"20\" output=\"C1\"\u003e\n@input\n\u003c/script\u003e\n)\n\nRotation: \n\u003cscript input=\"range\" min=\"0\" max=\"360\" value=\"0\" step=\"1\" default=\"0\" output=\"rotation\"\u003e\n@input\n\u003c/script\u003e°\n\n\n``` js @GGBScript\nUserAxisLimits(0,150,0,60);\n\nconst A = Punkt(@input(`A0`), @input(`A1`), \"A\");\nconst B = Punkt(@input(`B0`), @input(`B1`), \"B\");\nconst C = Punkt(@input(`C0`), @input(`C1`), \"C\");\n\nconst P = Polygon(\"A\", \"B\", \"C\");\n\nFarbe(P, \"red\");\n\nconst M = Mittelpunkt(P);\n\nconst P2 = Rotation(P, M, @input(`rotation`));\n\nFarbe(P2, \"blue\");\n\nKreis(M, 16, \"Kreis\");\n```\n\n## Classrooms ?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliaplayground%2Foer-hackathon-2025","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliaplayground%2Foer-hackathon-2025","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliaplayground%2Foer-hackathon-2025/lists"}