Selbstgesteuertes Projekt
Frontend Engineering with Prediction Game
Junior Front-End Engineer · Softwareentwicklung · Juli 2026
Built a complete World Cup prediction game end to end: rendered the tournament fixtures as interactive pick cards, scored picks with the exact 5/2/0 rubric, derived team attack/defense strengths from real historical results, and used those strengths to generate bot predictions. Also implemented a persistent ranked leaderboard and deployed the finished experience to a live Netlify URL.
Bewertet nach
- Scoring engine correctness30%
- Prediction model genuinely from real data25%
- Game completeness and leaderboard soundness25%
- Shipped and shareable: live deployed URL20%
Bestanden · Bestehensgrenze 60/100
Was herausstach6
- Rendered the fixture board with one card per match and two numeric score inputs per card.
- Implemented scorePick with correct handling for exact scores, same-result different-score cases, and draws.
- Computed team strengths from a real-results sample and used those strengths inside botPredict rather than hard-coding outcomes.
- Shipped a live https deployment on Netlify.
- Leakage-Free Feature Engineering
- Honest Model Evaluation
Meine eingereichte Arbeit10 Aufgaben
Lab Orientation
{"code":"<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Predict the Cup</title>\n <style>\n body {\n font-family: -apple-system, sans-serif;\n background: #FDFCF7;\n color: #0E1726;\n padding: 32px;\n margin: 0;\n }\n h1 {\n color: #00C65A;\n font-size: 32px;\n margin: 0 0 12px 0;\n }\n p { color: #3F4B5F; margin: 0; }\n </style>\n </head>\n <body>\n <!-- TODO: change this title to something of your own -->\n <h1>Prediction Game</h1>\n <p>Welcome to your prediction game.</p>\n </body>\n</html>","ranAt":"2026-07-26T10:01:56.247Z"}Example Render Fixtures
{"code":"<!doctype html>\n<html><head>\n <meta charset=\"utf-8\" />\n <title>Worked example · render two matches</title>\n <style>\n body { font: 15px/1.4 system-ui; padding: 24px; background: #F7F8FA; }\n .match { background: #fff; border: 1px solid #E4E8EE; border-radius: 12px;\n padding: 14px; margin-bottom: 12px; max-width: 360px; }\n .teams { font-weight: 800; color: #0E1726; margin-bottom: 8px; }\n .picks { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; }\n input { padding: 8px; border: 1px solid #E4E8EE; border-radius: 8px; text-align: center; }\n .vs { color: #6A7589; font-weight: 700; font-size: 12px; }\n </style>\n</head><body>\n\n <h1>My picks</h1>\n <div id=\"board\"></div>\n\n <script>\n // (1) The data — a small 2-match sample so the loop is easy to see.\n const SAMPLE_FIXTURES = [\n { home: \"Germany\", away: \"Brazil\", date: \"2026-06-28\" },\n { home: \"France\", away: \"Spain\", date: \"2026-06-29\" },\n ];\n\n // (2) Grab the empty box on the page we'll add cards to.\n const board = document.getElementById(\"board\");\n\n // (3) For each match, build a card and append it.\n SAMPLE_FIXTURES.forEach((match) => {\n const card = document.createElement(\"div\");\n card.className = \"match\";\n card.setAttribute(\"data-match\", match.home + \"-\" + match.away);\n\n // (4) Team names + two score boxes (a \"vs\" between them).\n card.innerHTML =\n '<div class=\"teams\">' + match.home + ' vs ' + match.away + '</div>' +\n '<div class=\"picks\">' +\n '<input type=\"number\" min=\"0\" placeholder=\"0\" />' +\n '<span class=\"vs\">vs</span>' +\n '<input type=\"number\" min=\"0\" placeholder=\"0\" />' +\n '</div>';\n\n // (5) Add the finished card to the page.\n board.appendChild(card);\n });\n </script>\n\n</body></html>","ranAt":"2026-07-26T10:02:18.540Z"}Act1 Fixtures Form
{"code":"<!doctype html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <title>Predict the Cup · my picks</title>\n\n <style>\n body {\n font: 15px/1.45 system-ui, -apple-system, \"Segoe UI\", sans-serif;\n padding: 24px;\n background: #F7F8FA;\n color: #0E1726;\n }\n\n h1 {\n margin: 0 0 4px;\n font-size: 22px;\n }\n\n .sub {\n color: #6A7589;\n font-size: 13px;\n margin-bottom: 16px;\n }\n\n #board {\n display: grid;\n gap: 12px;\n max-width: 640px;\n }\n\n .match {\n background: #fff;\n border: 1px solid #E4E8EE;\n border-radius: 12px;\n padding: 14px;\n }\n\n .meta {\n color: #6A7589;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.14em;\n margin-bottom: 6px;\n }\n\n .teams {\n font-weight: 800;\n font-size: 15.5px;\n margin-bottom: 8px;\n }\n\n .picks {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n gap: 8px;\n align-items: center;\n }\n\n .picks input {\n padding: 9px;\n border: 1px solid #E4E8EE;\n border-radius: 8px;\n text-align: center;\n font: inherit;\n font-weight: 700;\n font-size: 15px;\n }\n\n .vs {\n color: #6A7589;\n font-weight: 700;\n font-size: 12px;\n text-align: center;\n }\n\n footer {\n color: #6A7589;\n font-size: 11px;\n margin-top: 24px;\n max-width: 640px;\n line-height: 1.5;\n }\n </style>\n</head>\n\n<body>\n\n<h1>My picks</h1>\n<div class=\"sub\">2026 World Cup · Round of 32</div>\n\n<div id=\"board\"></div>\n\n<footer>\n Independent learning project. Not affiliated with or endorsed by FIFA.\n Fixtures snapshot: openfootball/worldcup.json (CC0-1.0).\n</footer>\n\n<script>\n\nconst FIXTURES = [\n { home: \"Germany\", away: \"Mexico\", date: \"2026-06-28\", round: \"R32\" },\n { home: \"Argentina\", away: \"Switzerland\", date: \"2026-06-29\", round: \"R32\" },\n { home: \"France\", away: \"Portugal\", date: \"2026-06-30\", round: \"R32\" },\n { home: \"Spain\", away: \"Uruguay\", date: \"2026-07-01\", round: \"R32\" },\n { home: \"Brazil\", away: \"Japan\", date: \"2026-07-02\", round: \"R32\" },\n { home: \"England\", away: \"Netherlands\", date: \"2026-07-03\", round: \"R32\" }\n];\n\nfunction renderFixtures() {\n\n const board = document.getElementById(\"board\");\n\n FIXTURES.forEach(function(match) {\n\n const card = document.createElement(\"div\");\n card.className = \"match\";\n\n card.setAttribute(\"data-match\", match.home + \"-\" + match.away);\n\n card.innerHTML =\n '<div class=\"meta\">' +\n match.round + \" · \" + match.date +\n '</div>' +\n\n '<div class=\"teams\">' +\n match.home + \" vs \" + match.away +\n '</div>' +\n\n '<div class=\"picks\">' +\n '<input type=\"number\" min=\"0\" placeholder=\"0\">' +\n '<span class=\"vs\">vs</span>' +\n '<input type=\"number\" min=\"0\" placeholder=\"0\">' +\n '</div>';\n\n board.appendChild(card);\n\n });\n\n}\n\nrenderFixtures();\n\n</script>\n\n</body>\n</html>","ranAt":"2026-07-26T10:07:32.270Z","selfCheck":{"cases":[{"name":"FIXTURES const is in scope","pass":true,"detail":""},{"name":"One card per fixture (data-match)","pass":true,"detail":""},{"name":"Two number inputs per card","pass":true,"detail":""},{"name":"Team names visible on each card","pass":true,"detail":""}],"ranAt":"2026-07-26T10:07:32.270Z"},"passed":true,"attempt":1}Act2 Scoring Function
{"code":"<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>scorePick · your turn</title>\n </head>\n\n <body>\n <h1>scorePick · your turn</h1>\n\n <pre id=\"out\" style=\"font-family:ui-monospace,Menlo,monospace;font-size:13px;white-space:pre-wrap\"></pre>\n\n <script>\n // Returns:\n // 5 = exact score\n // 2 = correct result\n // 0 = wrong result\n\n function scorePick(predicted, actual) {\n\n // Exact score\n if (\n predicted.home === actual.home &&\n predicted.away === actual.away\n ) {\n return 5;\n }\n\n // Determine predicted result\n let predictedResult;\n\n if (predicted.home > predicted.away) {\n predictedResult = \"home\";\n } else if (predicted.home < predicted.away) {\n predictedResult = \"away\";\n } else {\n predictedResult = \"draw\";\n }\n\n // Determine actual result\n let actualResult;\n\n if (actual.home > actual.away) {\n actualResult = \"home\";\n } else if (actual.home < actual.away) {\n actualResult = \"away\";\n } else {\n actualResult = \"draw\";\n }\n\n // Same result but different score\n if (predictedResult === actualResult) {\n return 2;\n }\n\n // Wrong result\n return 0;\n }\n\n // Local sanity-check\n const cases = [\n { pred: { home: 2, away: 1 }, actual: { home: 2, away: 1 }, why: 'exact 2-1' },\n { pred: { home: 3, away: 0 }, actual: { home: 1, away: 0 }, why: 'home win, wrong score' },\n { pred: { home: 0, away: 1 }, actual: { home: 2, away: 0 }, why: 'wrong result' },\n { pred: { home: 1, away: 1 }, actual: { home: 2, away: 2 }, why: 'both draws' },\n ];\n\n const out = document.getElementById('out');\n\n out.textContent = cases\n .map(c =>\n `${c.pred.home}-${c.pred.away} vs ${c.actual.home}-${c.actual.away} -> ${scorePick(c.pred, c.actual)} // ${c.why}`\n )\n .join('\\n');\n </script>\n\n </body>\n</html>","ranAt":"2026-07-26T10:08:56.336Z","passed":true,"attempt":1,"selfCheck":null}Act3 Compute Strength
{"passed":true,"attempt":1,"selfCheck":{"allPass":true,"failedNames":[]},"ranAt":"2026-07-26T10:09:55.526Z"}Act3 House Bot
{"passed":true,"attempt":1,"selfCheck":{"allPass":true,"failedNames":[]},"ranAt":"2026-07-26T10:10:39.686Z"}Act4 Leaderboard
{"code":"<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>Section 4 · the leaderboard</title>\n <style>\n body {\n font-family: ui-sans-serif, system-ui, sans-serif;\n padding: 20px;\n max-width: 520px;\n margin: 0 auto;\n }\n\n h1 {\n font-size: 18px;\n margin: 0 0 4px 0;\n }\n\n .sub {\n color: #6B7280;\n font-size: 12px;\n margin: 0 0 14px 0;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n th,\n td {\n text-align: left;\n padding: 8px 10px;\n border-bottom: 1px solid #E5E7EB;\n font-size: 14px;\n }\n\n th {\n color: #6B7280;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .06em;\n }\n\n .rank {\n width: 36px;\n color: #9CA3AF;\n font-variant-numeric: tabular-nums;\n }\n\n .total {\n text-align: right;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n }\n\n button {\n font: inherit;\n padding: 8px 14px;\n border-radius: 999px;\n border: 0;\n background: #00C65A;\n color: #fff;\n font-weight: 700;\n cursor: pointer;\n }\n </style>\n </head>\n\n <body>\n\n <h1>Predict the Cup · leaderboard</h1>\n <p class=\"sub\">One box, one ranked table.</p>\n\n <table>\n <thead>\n <tr>\n <th class=\"rank\">#</th>\n <th>Player</th>\n <th class=\"total\">Total</th>\n </tr>\n </thead>\n <tbody id=\"board\"></tbody>\n </table>\n\n <p style=\"margin-top:14px\">\n <button id=\"run\">Run saveAndRank()</button>\n </p>\n\n <script>\n\n var KEY = \"proov_predict_v1\";\n\n var rowsThisRound = [\n { name: \"You\", total: 17 },\n { name: \"House bot\", total: 11 },\n { name: \"Alex\", total: 22 }\n ];\n\n function render(rows) {\n var html = rows.map(function (r, i) {\n return \"\"\n + \"<tr>\"\n + \"<td class='rank'>\" + (i + 1) + \"</td>\"\n + \"<td>\" + r.name + \"</td>\"\n + \"<td class='total'>\" + r.total + \"</td>\"\n + \"</tr>\";\n }).join(\"\");\n\n document.getElementById(\"board\").innerHTML = html;\n }\n\n function saveAndRank(entries) {\n\n // Save to localStorage\n localStorage.setItem(KEY, JSON.stringify(entries));\n\n // Read back\n var rows = JSON.parse(localStorage.getItem(KEY));\n\n // Sort highest score first\n rows.sort(function(a, b) {\n return b.total - a.total;\n });\n\n // Render leaderboard\n render(rows);\n }\n\n document.getElementById(\"run\").addEventListener(\"click\", function () {\n saveAndRank(rowsThisRound);\n });\n\n window.saveAndRank = saveAndRank;\n window.__LB_KEY__ = KEY;\n window.__LB_ROWS__ = rowsThisRound;\n\n </script>\n\n </body>\n</html>","ranAt":"2026-07-26T10:11:32.680Z","passed":false,"attempt":1}Act5 Assemble
{"code":"<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>Predict the Cup — my World Cup prediction game</title>\n<style>\n :root { --green:#00C65A; --ink:#0E1726; --soft:#3F4B5F; --faint:#6A7589; --line:#E4E8EE; --paper:#fff; --bg:#F4F7F6; }\n * { box-sizing: border-box; }\n body { font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n margin:0; background:var(--bg); color:var(--ink); }\n .wrap { max-width: 760px; margin: 0 auto; padding: 22px 18px 40px; }\n header { display:flex; align-items:center; gap:12px; margin-bottom:6px; }\n .badge { width:42px; height:42px; border-radius:12px; background:var(--green); color:#fff;\n display:flex; align-items:center; justify-content:center; font-weight:900; font-size:18px; }\n h1 { font-size:21px; margin:0; letter-spacing:-0.01em; }\n .tag { color:var(--faint); font-size:13px; margin:2px 0 18px; }\n h2 { font-size:13px; text-transform:uppercase; letter-spacing:0.12em; color:var(--faint); margin:24px 0 12px; }\n #board { display:grid; grid-template-columns:1fr; gap:12px; }\n @media (min-width:560px){ #board { grid-template-columns:1fr 1fr; } }\n .match { background:var(--paper); border:1px solid var(--line); border-radius:14px; padding:14px; }\n .meta { color:var(--faint); font-size:10.5px; text-transform:uppercase; letter-spacing:0.12em; margin-bottom:8px; }\n .teams { display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; font-weight:800; font-size:15px; }\n .teams .vs { color:var(--faint); font-weight:700; font-size:11px; }\n .teams .away { text-align:right; }\n .picks { display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; margin-top:10px; }\n .picks input { padding:10px; border:1px solid var(--line); border-radius:9px; text-align:center;\n font:inherit; font-weight:800; font-size:16px; width:100%; }\n .picks input:focus { outline:2px solid var(--green); border-color:var(--green); }\n .picks .dash { color:var(--faint); font-weight:800; text-align:center; }\n .botline { margin-top:10px; font-size:12px; color:var(--soft); }\n .botline b { color:var(--ink); font-variant-numeric:tabular-nums; }\n .botline .prob { color:var(--faint); font-weight:600; }\n .hint { color:var(--faint); font-size:12px; line-height:1.5; margin:8px 0 2px; max-width:560px; }\n .challenge-banner { background:rgba(0,198,90,0.10); border:1px solid var(--green); border-radius:12px; padding:12px 14px; font-size:14px; font-weight:700; color:var(--ink); margin:14px 0 4px; }\n .vs-friend { font-size:15px; font-weight:800; color:var(--green); margin-top:12px; }\n .share-row { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-top:14px; }\n .namebox { flex:1; min-width:150px; padding:11px 12px; border:1px solid var(--line); border-radius:10px; font:inherit; }\n .namebox:focus { outline:2px solid var(--green); border-color:var(--green); }\n .sharebtn { font:inherit; font-weight:800; color:#fff; background:var(--ink); border:0; border-radius:999px; padding:11px 18px; cursor:pointer; }\n .sharebtn:hover { filter:brightness(1.15); }\n .shareurl { width:100%; margin-top:8px; padding:9px 11px; border:1px solid var(--line); border-radius:8px; font-family:ui-monospace,Menlo,monospace; font-size:12px; color:var(--soft); }\n .proov-credit { margin-top:12px; font-size:11.5px; }\n .proov-credit a { color:var(--green); font-weight:800; text-decoration:none; }\n .result { margin-top:10px; font-size:12px; font-weight:700; color:var(--green);\n border-top:1px dashed var(--line); padding-top:9px; }\n .scorebtn { margin-top:18px; font:inherit; font-weight:800; font-size:15px; color:#fff;\n background:var(--green); border:0; border-radius:999px; padding:13px 22px; cursor:pointer; width:100%; }\n @media (min-width:560px){ .scorebtn { width:auto; } }\n .
…Final Submission
{"url":"https://gentle-lebkuchen-ff5f12.netlify.app/","submittedAt":"2026-07-26T10:16:07.976Z"}Jupyterlite Code
base64:CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTm90ZWJvb2s6IHZ3X3NwcmludDFfZWRhLmlweW5iCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIDxkaXYgc3R5bGU9ImJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgxMzVkZWcsICMxQTNDNkUgMCUsICMwQjEzMkIgMTAwJSk7IGJvcmRlci1yYWRpdXM6IDE2cHg7IHBhZGRpbmc6IDM2cHggMzJweDsgbWFyZ2luLWJvdHRvbTogOHB4OyI+CiMgICA8ZGl2IHN0eWxlPSJkaXNwbGF5OmZsZXg7IGFsaWduLWl0ZW1zOmNlbnRlcjsgZ2FwOjE2cHg7IG1hcmdpbi1ib3R0b206MjBweDsiPgojICAgICA8ZGl2PgojICAgICAgIDxkaXYgc3R5bGU9ImNvbG9yOiM2MGE1ZmE7IGZvbnQtc2l6ZToxMXB4OyBmb250LXdlaWdodDo3MDA7IGxldHRlci1zcGFjaW5nOjNweDsgdGV4dC10cmFuc2Zvcm06dXBwZXJjYXNlOyBtYXJnaW4tYm90dG9tOjRweDsiPlByb29WIFdvcmsgRXhwZXJpZW5jZTwvZGl2PgojICAgICAgIDxkaXYgc3R5bGU9ImNvbG9yOiNmZmY7IGZvbnQtc2l6ZToyMnB4OyBmb250LXdlaWdodDo4MDA7IGxpbmUtaGVpZ2h0OjEuMjsiPlVzZWQgQ2FyIFByaWNlIFByZWRpY3Rpb248L2Rpdj4KIyAgICAgPC9kaXY+CiMgICA8L2Rpdj4KIyAgIDxkaXYgc3R5bGU9ImRpc3BsYXk6ZmxleDsgZ2FwOjEwcHg7IGZsZXgtd3JhcDp3cmFwOyBtYXJnaW4tYm90dG9tOjIwcHg7Ij4KIyAgICAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQ6cmdiYSgyNTUsMjU1LDI1NSwwLjEyKTsgY29sb3I6I2ZmZjsgYm9yZGVyLXJhZGl1czoyMHB4OyBwYWRkaW5nOjVweCAxNHB4OyBmb250LXNpemU6MTJweDsgZm9udC13ZWlnaHQ6NjAwOyI+RGF0YSBTY2llbnRpc3QgLSBWVyBDYXNlIFN0dWR5PC9zcGFuPgojICAgICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZDpyZ2JhKDI1NSwyNTUsMjU1LDAuMTIpOyBjb2xvcjojZmZmOyBib3JkZXItcmFkaXVzOjIwcHg7IHBhZGRpbmc6NXB4IDE0cHg7IGZvbnQtc2l6ZToxMnB4OyBmb250LXdlaWdodDo2MDA7Ij5QeXRob24gLyBzY2lraXQtbGVhcm4gLyBwYW5kYXM8L3NwYW4+CiMgICAgIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsMC4xMik7IGNvbG9yOiNmZmY7IGJvcmRlci1yYWRpdXM6MjBweDsgcGFkZGluZzo1cHggMTRweDsgZm9udC1zaXplOjEycHg7IGZvbnQtd2VpZ2h0OjYwMDsiPkVzdC4gNC02IGhvdXJzPC9zcGFuPgojICAgPC9kaXY+CiMgICA8ZGl2IHN0eWxlPSJiYWNrZ3JvdW5kOnJnYmEoMjU1LDI1NSwyNTUsMC4wOCk7IGJvcmRlcjoxcHggc29saWQgcmdiYSgyNTUsMjU1LDI1NSwwLjE1KTsgYm9yZGVyLXJhZGl1czoxMHB4OyBwYWRkaW5nOjEycHggMTZweDsiPgojICAgICA8cCBzdHlsZT0iY29sb3I6Izk0YTNiODsgZm9udC1zaXplOjExcHg7IG1hcmdpbjowOyBsaW5lLWhlaWdodDoxLjY7Ij4KIyAgICAgICA8c3Ryb25nIHN0eWxlPSJjb2xvcjojY2JkNWUxOyI+TGVnYWwgbm90aWNlOjwvc3Ryb25nPiBUaGlzIGlzIGFuIGluZGVwZW5kZW50IGVkdWNhdGlvbmFsIGNhc2Ugc3R1ZHkgY3JlYXRlZCBieSBQcm9vVi4gVm9sa3N3YWdlbiwgQXVkaSwgVlcsIEdvbGYsIGFuZCBBNCBhcmUgdHJhZGVtYXJrcyBvZiBWb2xrc3dhZ2VuIEFHLiBUaGlzIG5vdGVib29rIGlzIG5vdCBlbmRvcnNlZCBieSwgYWZmaWxpYXRlZCB3aXRoLCBvciBzcG9uc29yZWQgYnkgVm9sa3N3YWdlbiBBRyBvciBhbnkgb2YgaXRzIHN1YnNpZGlhcmllcy4gRGF0YXNldCBzb3VyY2VkIGZyb20gdGhlIDxlbT4xMDAsMDAwIFVLIFVzZWQgQ2FyPC9lbT4gZGF0YXNldCBieSBhZGl0eWFkZXNhaTEzIG9uIEthZ2dsZSwgdXNlZCB1bmRlciBub21pbmF0aXZlIGZhaXIgdXNlIGZvciBlZHVjYXRpb25hbCBwdXJwb3NlcyBvbmx5LgojICAgICA8L3A+CiMgICA8L2Rpdj4KIyA8L2Rpdj4KCiMgIyMgWW91ciBNaXNzaW9uCiMgCiMgSW4gdGhpcyBzaW11bGF0ZWQgY2FzZSBzdHVkeSBieSBQcm9vViwgeW91IHdpbGwgc3RlcCBpbnRvIHRoZSByb2xlIG9mIGEgRGF0YSBTY2llbnRpc3QgYW5hbHl6aW5nIHRoZSB1c2VkIGNhciBtYXJrZXQgZm9yIFZvbGtzd2FnZW4gYW5kIEF1ZGkgdmVoaWNsZXMuIENlcnRpZmllZCBQcmUtT3duZWQgKENQTykgcHJvZ3JhbXMgcHJpY2UgdGhvdXNhbmRzIG9mIHVzZWQgdmVoaWNsZXMgZXZlcnkgbW9udGggLSBhbmQgb2Z0ZW4gZG8gaXQgbWFudWFsbHkuIFlvdXIgam9iOiAqKmJ1aWxkIGEgbWFjaGluZSBsZWFybmluZyBtb2RlbCB0aGF0IHByZWRpY3RzIHJlc2FsZSBwcmljZXMgYXV0b21hdGljYWxseSoqLgojIAojIFlvdSdsbCB3b3JrIHdpdGggcmVhbCBVSyBtYXJrZXQgZGF0YToKIyAtICoqfjE1LDIwMCBWVyBsaXN0aW5ncyoqIChtb3N0bHkgR29sZikKIyAtICoqfjEwLDcwMCBBdWRpIGxpc3RpbmdzKiogKG1vc3RseSBBNCkKIyAtIENvbHVtbnM6IGBtb2RlbGAsIGB5ZWFyYCwgYHByaWNlYCwgYHRyYW5zbWlzc2lvbmAsIGBtaWxlYWdlYCwgYGZ1ZWxUeXBlYCwgYHRheGAsIGBtcGdgLCBgZW5naW5lU2l6ZWAKIyAKIyBCeSB0aGUgZW5kIHlvdSdsbCBoYXZlIHRyYWluZWQgdHdvIG1vZGVscywgY29tcGFyZWQgdGhlbSwgYW5kIHdyaXR0ZW4gYSBidXNpbmVzcyByZWNvbW1lbmRhdGlvbiBmb3IgbGVhZGVyc2hpcC4KIyAKIyAtLS0KIyAKIyAqKkZvbGxvdyB0aGUgc2VjdGlvbnMgaW4gb3JkZXIuKiogRWFjaCBvbmUgaGFzIGEgY2hlY2tsaXN0LiBGaWxsIGluIHRoZSBgIyBZT1VSIENPREUgSEVSRWAgY2VsbHMuCgojIC0tLQojICMjIFNlY3Rpb24gMCAtIFNldHVwICYgRGF0YSBMb2FkaW5nCiMgPiAqKlJ1biB0aGlzIGNlbGwgZmlyc3QuIERvIG5vdCBtb2RpZnkgaXQuKioKCiMgSW5bM106CiMgUHJvb1Y6IFZXICYgQXVkaSBVc2VkIENhciBQcmljZSBQcmVkaWN0aW9uCiMgVm9sa3N3YWdlbiwgQXVkaSwgVlcsI
…