{"id":901191,"date":"2026-09-03T00:34:57","date_gmt":"2026-09-03T00:34:57","guid":{"rendered":"https:\/\/knightongrange.co.uk\/portal\/?page_id=901191"},"modified":"2026-09-03T12:14:11","modified_gmt":"2026-09-03T12:14:11","slug":"python-compiler","status":"publish","type":"page","link":"https:\/\/knightongrange.co.uk\/portal\/python-compiler\/","title":{"rendered":"Python Compiler"},"content":{"rendered":"\n<!-- KGE Python Compiler \u2014 visual redesign only -->\n<!-- Paste this complete file into one WordPress Custom HTML block. -->\n\n<section class=\"kge-python-page\" aria-labelledby=\"kge-python-page-title\">\n  <header class=\"kge-page-intro\">\n    <div>\n      <h1 id=\"kge-python-page-title\">Online Python &#8211; IDE, Editor, Compiler, Interpreter<\/h1>\n      <p>Write, run and test Python code in your browser.<\/p>\n    <\/div>\n    <div id=\"kge-python-status\" class=\"kge-python-status\" role=\"status\">Starting Python&#8230;<\/div>\n  <\/header>\n\n  <div id=\"kge-python-lab\">\n    <style>\n      #kge-python-lab, #kge-python-lab *, #kge-python-lab *::before, #kge-python-lab *::after,\n      .kge-python-page, .kge-python-page *, .kge-python-page *::before, .kge-python-page *::after { box-sizing:border-box; }\n      .kge-python-page { width:100%; max-width:1500px; margin:32px auto; padding:0 22px; font-family:Montserrat,Arial,sans-serif; color:#232323; }\n      .kge-page-intro { display:flex; align-items:flex-end; justify-content:space-between; gap:24px; margin:0 0 20px; }\n      .kge-page-intro h1 { margin:0; color:#20242a; font-size:clamp(30px,3vw,46px); line-height:1.1; font-weight:800; letter-spacing:-.035em; }\n      .kge-page-intro p { margin:8px 0 0; color:#626a73; font-size:17px; }\n      .kge-python-status { display:flex; align-items:center; gap:8px; color:#C5A059; font-size:12px; font-weight:700; white-space:nowrap; }\n      .kge-python-status::before { content:\"\"; width:9px; height:9px; border-radius:50%; background:currentColor; box-shadow:0 0 0 4px rgba(197,160,89,.12); }\n\n      #kge-python-lab { width:100%; background:#0d1117; border:1px solid #29313b; border-radius:15px; overflow:hidden; box-shadow:0 18px 48px rgba(0,31,24,.18); color:#fff; }\n      .kge-workbench-bar { min-height:64px; display:flex; align-items:center; justify-content:space-between; gap:16px; padding:10px 14px 10px 22px; background:linear-gradient(180deg,#151c23 0%,#11171d 100%); border-bottom:1px solid #303944; }\n      .kge-file-tab { display:flex; align-items:center; gap:10px; font:700 14px Consolas,Monaco,monospace; }\n      .kge-file-tab::after { content:\"\"; width:10px; height:10px; border-radius:50%; background:#4dcc72; }\n      .kge-top-actions { display:flex; align-items:center; gap:10px; }\n      .kge-python-button { min-height:40px; border:1px solid transparent; border-radius:8px; padding:9px 16px; cursor:pointer; font:700 13px Montserrat,Arial,sans-serif; transition:background .18s,border-color .18s,transform .18s; }\n      .kge-python-button:hover:not(:disabled) { transform:translateY(-1px); }\n      .kge-python-button:disabled { opacity:.45; cursor:not-allowed; }\n      .kge-run { min-width:128px; background:#3B7543; color:#fff; box-shadow:0 4px 14px rgba(59,117,67,.28); }\n      .kge-run:hover:not(:disabled) { background:#478b51; }\n      .kge-clear { background:#171d24; border-color:#3b4652; color:#d9dee5; }\n      .kge-clear:hover { background:#222b34; }\n      .kge-stop { background:#171d24; border-color:#653238; color:#ef8b8b; }\n      .kge-stop:hover:not(:disabled) { background:#352126; }\n\n      .kge-code-wrapper { --kge-code-width:66.666%; display:grid; grid-template-columns:minmax(260px,var(--kge-code-width)) 10px minmax(260px,1fr); min-height:480px; }\n      .kge-code-side,.kge-terminal-side { min-width:0; background:#0d1117; }\n      .kge-resizer { position:relative; z-index:5; width:10px; cursor:col-resize; touch-action:none; background:#18212a; border-left:1px solid #303944; border-right:1px solid #303944; outline:0; transition:background .16s,border-color .16s; }\n      .kge-resizer::after { content:\"\"; position:absolute; top:50%; left:50%; width:3px; height:34px; transform:translate(-50%,-50%); border-radius:3px; background:repeating-linear-gradient(to bottom,#84909d 0 3px,transparent 3px 7px); opacity:.75; }\n      .kge-resizer:hover,.kge-resizer:focus,.kge-code-wrapper.kge-is-resizing .kge-resizer { background:#214034; border-color:#3B7543; }\n      .kge-code-wrapper.kge-is-resizing,.kge-code-wrapper.kge-is-resizing * { cursor:col-resize!important; user-select:none!important; }\n      .kge-panel-label { display:flex; align-items:center; justify-content:space-between; height:42px; padding:0 18px; background:#111820; border-bottom:1px solid #28313b; color:#aeb7c2; font:700 12px Montserrat,Arial,sans-serif; letter-spacing:.04em; }\n      #kge-python-code { display:block; width:100%; height:438px; resize:vertical; border:0; outline:0; padding:17px 22px; background:#0d1117; color:#e7edf3; caret-color:#fff; font:14px\/1.75 Consolas,Monaco,\"Courier New\",monospace; tab-size:4; }\n      #kge-python-code:focus { box-shadow:inset 3px 0 #3B7543; }\n      #kge-python-code::selection { background:#284c58; }\n      #kge-python-terminal { width:100%; height:438px; overflow:auto; padding:17px 22px; background:#0a0f14; color:#e5e9ee; font:14px\/1.75 Consolas,Monaco,\"Courier New\",monospace; white-space:pre-wrap; word-break:break-word; }\n      .kge-terminal-error { color:#ff7b72; }\n      .kge-terminal-success { color:#56d364; }\n\n      .kge-python-tabs { display:flex; align-items:center; gap:4px; padding:0 14px; overflow-x:auto; background:#111820; border-top:1px solid #303944; border-bottom:1px solid #303944; }\n      .kge-python-tab { border:0; border-bottom:3px solid transparent; background:transparent; color:#98a3af; padding:13px 14px 11px; cursor:pointer; font:700 12px Montserrat,Arial,sans-serif; white-space:nowrap; }\n      .kge-python-tab:hover { color:#fff; }\n      .kge-python-tab.active { color:#E5C98D; border-bottom-color:#C5A059; }\n      .kge-python-panel { display:none; }\n      .kge-python-panel.active { display:block; }\n      .kge-secondary-panel { min-height:420px; padding:28px; background:#0d1117; }\n      .kge-secondary-panel h2 { margin:0 0 8px; color:#fff; font-size:19px; }\n      .kge-secondary-panel h3 { margin:22px 0 8px; color:#E5C98D; font-size:15px; }\n      .kge-secondary-panel p { max-width:800px; margin:0 0 16px; color:#b5bec8; font-size:13px; line-height:1.7; }\n      .kge-file-upload { border:1.5px dashed #485461; border-radius:10px; padding:30px; text-align:center; background:#111820; }\n      .kge-file-upload:hover { border-color:#C5A059; }\n      .kge-file-upload input { display:none; }\n      .kge-file-label { display:inline-block; padding:11px 18px; border-radius:8px; background:#C5A059; color:#17130a; font-size:13px; font-weight:800; cursor:pointer; }\n      .kge-file-hint { margin-top:12px; color:#8f9aa6; font-size:11px; }\n      .kge-file-list { margin-top:20px; }\n      .kge-file-item { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:8px; padding:12px 14px; border:1px solid #303944; border-radius:8px; background:#131a22; }\n      .kge-file-left,.kge-file-buttons { display:flex; align-items:center; gap:10px; }\n      .kge-file-name { color:#e1e6eb; font:13px Consolas,Monaco,monospace; word-break:break-all; }\n      .kge-file-size { color:#7f8a96; font-size:11px; white-space:nowrap; }\n      .kge-view-file,.kge-download-file,.kge-close-viewer { border:0; border-radius:6px; padding:8px 11px; cursor:pointer; font:700 11px Montserrat,Arial,sans-serif; }\n      .kge-view-file { background:#C5A059; color:#17130a; }\n      .kge-download-file { background:#34404c; color:#fff; }\n      .kge-file-viewer { display:none; margin-top:18px; overflow:hidden; border:1px solid #303944; border-radius:9px; background:#fff; }\n      .kge-file-viewer.active { display:block; }\n      .kge-file-viewer-header { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:10px 14px; border-bottom:1px solid #d5d9dd; background:#eef1f3; color:#111; }\n      .kge-file-viewer-title { font-size:12px; font-weight:800; }\n      .kge-close-viewer { background:#20262c; color:#fff; }\n      .kge-file-content { min-height:180px; max-height:420px; margin:0; padding:18px; overflow:auto; background:#fff; color:#111!important; font:13px\/1.6 Consolas,Monaco,monospace; white-space:pre-wrap; word-break:break-word; }\n      .kge-help-code { max-width:850px; overflow-x:auto; padding:15px; border:1px solid #303944; border-radius:8px; background:#131a22; color:#dce2e8; font:13px\/1.7 Consolas,Monaco,monospace; white-space:pre-wrap; }\n\n      .kge-info-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:20px; margin:24px 0 18px; }\n      .kge-info-card { min-height:138px; padding:22px; border:1px solid #dce2e5; border-radius:12px; background:#fff; box-shadow:0 5px 18px rgba(0,31,24,.06); }\n      .kge-info-card h2 { margin:0 0 12px; font-size:17px; color:#205d37; }\n      .kge-info-card:nth-child(2) h2 { color:#1C59A1; }\n      .kge-info-card:nth-child(3) h2 { color:#a87516; }\n      .kge-info-card p { margin:6px 0; color:#4d555d; font-size:13px; line-height:1.55; }\n      .kge-safe-note { padding:14px 17px; border:1px solid #cfe2d2; border-radius:10px; background:#F4F9F4; color:#285d35; font-size:12px; }\n      .kge-python-seo-content { max-width:900px; margin:28px 0 0; }\n      .kge-python-seo-content h2 { font-size:22px; color:#001F18; }\n      .kge-python-seo-content p { color:#515960; line-height:1.7; }\n\n      @media (max-width:900px) {\n        .kge-code-wrapper { grid-template-columns:1fr; }\n        .kge-resizer { display:none; }\n        .kge-code-side { border-right:0; border-bottom:1px solid #303944; }\n        .kge-info-grid { grid-template-columns:1fr; }\n      }\n      @media (max-width:620px) {\n        .kge-python-page { padding:0 10px; }\n        .kge-page-intro,.kge-workbench-bar { align-items:flex-start; flex-direction:column; }\n        .kge-top-actions { width:100%; flex-wrap:wrap; }\n        .kge-python-button { flex:1; }\n        #kge-python-code,#kge-python-terminal { height:330px; }\n        .kge-file-item { align-items:flex-start; flex-direction:column; }\n      }\n#kge-python-lab {\n    transform: scale(0.9);\n    transform-origin: top center;\n    width: 111.111%;\n    margin-left: -5.555%;\n}\n    <\/style>\n\n    <div class=\"kge-workbench-bar\">\n      <div class=\"kge-file-tab\">main.py<\/div>\n      <div class=\"kge-top-actions\">\n        <button type=\"button\" class=\"kge-python-button kge-run\" id=\"kge-python-run\" disabled=\"\">\u25b6 Run Code<\/button>\n        <button type=\"button\" class=\"kge-python-button kge-clear\" id=\"kge-python-clear\">\u21bb Reset Output<\/button>\n        <button type=\"button\" class=\"kge-python-button kge-stop\" id=\"kge-python-stop\" disabled=\"\">\u25a0 Stop<\/button>\n      <\/div>\n    <\/div>\n\n    <div class=\"kge-python-panel active\" id=\"kge-python-code-panel\">\n      <div class=\"kge-code-wrapper\">\n        <div class=\"kge-code-side\">\n          <div class=\"kge-panel-label\"><span>PYTHON CODE<\/span><span>Ctrl + Enter to run<\/span><\/div>\n          <textarea id=\"kge-python-code\" spellcheck=\"false\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\">from js import document, window\nfrom pyodide.ffi import create_proxy, to_js\n\n# Stop a previous copy of the animation\ntry:\n    window.clearInterval(window.kgeLogoInterval)\n    window.kgeLogoProxy.destroy()\nexcept:\n    pass\n\n# Create the canvas\ncanvas = document.createElement(&#8220;canvas&#8221;)\ncanvas.width = 420\ncanvas.height = 560\n\ncanvas.style.width = &#8220;100%&#8221;\ncanvas.style.maxWidth = &#8220;240px&#8221;\ncanvas.style.height = &#8220;auto&#8221;\ncanvas.style.display = &#8220;block&#8221;\ncanvas.style.margin = &#8220;10px auto&#8221;\ncanvas.style.borderRadius = &#8220;10px&#8221;\n\noutput = document.getElementById(&#8220;kge-python-terminal&#8221;)\noutput.appendChild(canvas)\n\nctx = canvas.getContext(&#8220;2d&#8221;)\n\nGREEN = &#8220;#00382B&#8221;\nDARK_GREEN = &#8220;#001F18&#8221;\nGOLD = &#8220;#E5C05B&#8221;\nLIGHT_GOLD = &#8220;#FFE59A&#8221;\nWHITE = &#8220;#FFFFFF&#8221;\n\n# SVG-style paths used to build the crest\npaths = [\n    # Outer shield\n    &#8220;&#8221;&#8221;\n    M 92 130\n    L 328 130\n    L 328 310\n    C 312 354 270 386 210 420\n    C 150 386 108 354 92 310\n    Z\n    &#8220;&#8221;&#8221;,\n\n    # Inner shield\n    &#8220;&#8221;&#8221;\n    M 108 148\n    L 312 148\n    L 312 300\n    C 292 338 257 365 210 393\n    C 163 365 128 338 108 300\n    Z\n    &#8220;&#8221;&#8221;,\n\n    # Top crossed decoration\n    &#8220;&#8221;&#8221;\n    M 110 126\n    C 143 123 166 102 190 78\n    C 201 68 208 62 210 53\n    &#8220;&#8221;&#8221;,\n\n    &#8220;&#8221;&#8221;\n    M 310 126\n    C 277 123 254 102 230 78\n    C 219 68 212 62 210 53\n    &#8220;&#8221;&#8221;,\n\n    # Top left curl\n    &#8220;&#8221;&#8221;\n    M 91 126\n    C 55 118 51 83 72 70\n    C 91 58 112 71 108 89\n    C 105 105 86 105 82 92\n    C 78 82 90 77 97 85\n    &#8220;&#8221;&#8221;,\n\n    # Top right curl\n    &#8220;&#8221;&#8221;\n    M 329 126\n    C 365 118 369 83 348 70\n    C 329 58 308 71 312 89\n    C 315 105 334 105 338 92\n    C 342 82 330 77 323 85\n    &#8220;&#8221;&#8221;,\n\n    # Left side decoration\n    &#8220;&#8221;&#8221;\n    M 92 165\n    C 66 141 38 153 42 181\n    C 45 204 72 210 82 192\n    C 91 176 74 163 62 173\n    C 53 181 63 191 72 184\n\n    M 92 206\n    C 67 196 49 217 57 239\n    C 66 263 86 271 94 288\n\n    M 92 250\n    C 67 245 53 261 58 278\n    C 63 295 80 304 93 313\n    &#8220;&#8221;&#8221;,\n\n    # Right side decoration\n    &#8220;&#8221;&#8221;\n    M 328 165\n    C 354 141 382 153 378 181\n    C 375 204 348 210 338 192\n    C 329 176 346 163 358 173\n    C 367 181 357 191 348 184\n\n    M 328 206\n    C 353 196 371 217 363 239\n    C 354 263 334 271 326 288\n\n    M 328 250\n    C 353 245 367 261 362 278\n    C 357 295 340 304 327 313\n    &#8220;&#8221;&#8221;,\n\n    # Bottom left flourish\n    &#8220;&#8221;&#8221;\n    M 92 312\n    C 67 326 45 319 38 302\n    C 27 278 52 266 69 278\n    C 84 289 75 308 61 304\n    C 49 300 50 288 60 287\n\n    M 92 319\n    C 112 344 134 365 174 390\n\n    M 116 346\n    C 93 345 83 367 98 380\n    C 111 392 132 380 126 365\n    &#8220;&#8221;&#8221;,\n\n    # Bottom right flourish\n    &#8220;&#8221;&#8221;\n    M 328 312\n    C 353 326 375 319 382 302\n    C 393 278 368 266 351 278\n    C 336 289 345 308 359 304\n    C 371 300 370 288 360 287\n\n    M 328 319\n    C 308 344 286 365 246 390\n\n    M 304 346\n    C 327 345 337 367 322 380\n    C 309 392 288 380 294 365\n    &#8220;&#8221;&#8221;,\n\n    # Fleur-de-lis\n    &#8220;&#8221;&#8221;\n    M 210 52\n    C 195 39 194 24 210 3\n    C 226 24 225 39 210 52\n\n    M 210 34\n    C 194 28 187 39 196 49\n\n    M 210 34\n    C 226 28 233 39 224 49\n\n    M 199 52\n    L 221 52\n    L 210 72\n    Z\n    &#8220;&#8221;&#8221;,\n\n    # Divider lines\n    &#8220;M 52 438 L 368 438&#8221;,\n    &#8220;M 52 522 L 368 522&#8221;\n]\n\nPath2D = window.Path2D\ncanvas_paths = [Path2D.new(path) for path in paths]\n\ndash_pattern = to_js([2400, 2400])\n\nframe = 0\ndrawing_frames = 170\npause_frames = 75\n\n\ndef draw_animated_path(path, progress, width=3):\n    progress = max(0, min(1, progress))\n\n    ctx.save()\n    ctx.strokeStyle = GOLD\n    ctx.lineWidth = width\n    ctx.lineCap = &#8220;round&#8221;\n    ctx.lineJoin = &#8220;round&#8221;\n\n    ctx.setLineDash(dash_pattern)\n    ctx.lineDashOffset = 2400 * (1 &#8211; progress)\n\n    ctx.stroke(path)\n    ctx.restore()\n\n\ndef show_text(text, x, y, size, colour, progress, spacing=False):\n    if progress &lt;= 0:\n        return\n\n    ctx.save()\n    ctx.globalAlpha = min(1, progress)\n    ctx.fillStyle = colour\n    ctx.textAlign = &#8220;center&#8221;\n    ctx.textBaseline = &#8220;middle&#8221;\n\n    if spacing:\n        ctx.font = f&#8221;{size}px Georgia, serif&#8221;\n    else:\n        ctx.font = f&#8221;bold {size}px Georgia, serif&#8221;\n\n    ctx.fillText(text, x, y)\n    ctx.restore()\n\n\ndef animate_logo():\n    global frame\n\n    ctx.fillStyle = DARK_GREEN\n    ctx.fillRect(0, 0, canvas.width, canvas.height)\n\n    progress = min(1, frame \/ drawing_frames)\n\n    # Draw each path at a slightly different time\n    path_count = len(canvas_paths)\n\n    for index, path in enumerate(canvas_paths):\n        start = index \/ (path_count + 5)\n        local_progress = (progress &#8211; start) * 2.7\n\n        width = 5 if index == 0 else 2.5\n        draw_animated_path(path, local_progress, width)\n\n    # Gold highlights around the shield\n    if progress &gt; 0.48:\n        highlight = min(1, (progress &#8211; 0.48) * 4)\n\n        ctx.save()\n        ctx.globalAlpha = highlight * 0.45\n        ctx.strokeStyle = LIGHT_GOLD\n        ctx.lineWidth = 1\n        ctx.stroke(canvas_paths[0])\n        ctx.restore()\n\n    # KG lettering\n    show_text(\n        &#8220;KG&#8221;,\n        210,\n        238,\n        108,\n        WHITE,\n        (progress &#8211; 0.48) * 4\n    )\n\n    # Company wording\n    show_text(\n        &#8220;KNIGHTON&#8221;,\n        210,\n        466,\n        32,\n        WHITE,\n        (progress &#8211; 0.68) * 4\n    )\n\n    show_text(\n        &#8220;GRANGE&#8221;,\n        210,\n        503,\n        29,\n        GOLD,\n        (progress &#8211; 0.76) * 4\n    )\n\n    show_text(\n        &#8220;E D U C A T I O N&#8221;,\n        210,\n        543,\n        15,\n        GOLD,\n        (progress &#8211; 0.86) * 5,\n        True\n    )\n\n    frame += 1\n\n    # Pause and restart\n    if frame &gt; drawing_frames + pause_frames:\n        frame = 0\n\n\nanimation_proxy = create_proxy(animate_logo)\n\nwindow.kgeLogoProxy = animation_proxy\nwindow.kgeLogoInterval = window.setInterval(\n    animation_proxy,\n    25\n)<\/textarea>\n        <\/div>\n        <div class=\"kge-resizer\" id=\"kge-python-resizer\" role=\"separator\" aria-label=\"Resize code and output panels\" aria-orientation=\"vertical\" aria-valuemin=\"25\" aria-valuemax=\"75\" aria-valuenow=\"67\" tabindex=\"0\"><\/div>\n        <div class=\"kge-terminal-side\">\n          <div class=\"kge-panel-label\"><span>OUTPUT<\/span><span>Python 3<\/span><\/div>\n          <div id=\"kge-python-terminal\" tabindex=\"0\"><div class=\"kge-terminal-line\">Python Coding Lab<\/div><div class=\"kge-terminal-line\">Loading Python&#8230;<\/div><\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"kge-python-tabs\" role=\"tablist\">\n      <button type=\"button\" class=\"kge-python-tab active\" data-tab=\"code\">Code<\/button>\n      <button type=\"button\" class=\"kge-python-tab\" data-tab=\"files\">Files<\/button>\n      <button type=\"button\" class=\"kge-python-tab\" data-tab=\"help\">Help<\/button>\n    <\/div>\n\n    <div class=\"kge-python-panel\" id=\"kge-python-files-panel\">\n      <div class=\"kge-secondary-panel\">\n        <h2>Python Files<\/h2>\n        <p>Upload files that your Python program can work with. Changes made by Python are available when you view or download the file.<\/p>\n        <div class=\"kge-file-upload\">\n          <label for=\"kge-python-file-input\" class=\"kge-file-label\">Choose Files<\/label>\n          <input id=\"kge-python-file-input\" type=\"file\" multiple=\"\">\n          <div class=\"kge-file-hint\">Files stay in your browser and are not uploaded to the website server.<\/div>\n        <\/div>\n        <div class=\"kge-file-list\" id=\"kge-python-file-list\"><\/div>\n        <div class=\"kge-file-viewer\" id=\"kge-python-file-viewer\">\n          <div class=\"kge-file-viewer-header\"><div class=\"kge-file-viewer-title\" id=\"kge-python-file-viewer-title\">File<\/div><button type=\"button\" class=\"kge-close-viewer\" id=\"kge-python-close-viewer\">Close<\/button><\/div>\n          <pre class=\"kge-file-content\" id=\"kge-python-file-content\"><\/pre>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"kge-python-panel\" id=\"kge-python-help-panel\">\n      <div class=\"kge-secondary-panel\">\n        <h2>Using the Python Lab<\/h2>\n        <p>Write your program in the Code panel and select Run Code. Programs using input() display the prompt written in your Python program.<\/p>\n        <h3>Example<\/h3>\n        <div class=\"kge-help-code\">name = input(&#8220;Enter your name: &#8220;)\nprint(&#8220;Hello&#8221;, name)\n\nage = int(input(&#8220;Enter your age: &#8220;))\n\nif age &gt;= 18:\n    print(&#8220;You are an adult.&#8221;)\nelse:\n    print(&#8220;You are under 18.&#8221;)<\/div>\n        <h3>Python libraries<\/h3>\n        <div class=\"kge-help-code\">import random\nimport math\nimport csv\nimport json\nimport statistics\nimport datetime\n\nprint(random.randint(1, 10))\nprint(math.sqrt(25))<\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div class=\"kge-info-grid\">\n    <article class=\"kge-info-card\"><h2>How to use<\/h2><p>Write your Python code in the editor.<\/p><p>Select <strong>Run Code<\/strong> to execute it.<\/p><p>View the result in the output panel.<\/p><\/article>\n    <article class=\"kge-info-card\"><h2>Keyboard shortcuts<\/h2><p><strong>Ctrl + Enter<\/strong> &nbsp; Run code<\/p><p><strong>Tab<\/strong> &nbsp; Indent your code<\/p><\/article>\n    <article class=\"kge-info-card\"><h2>Try a challenge<\/h2><p>Test your skills using short Python challenges designed for GCSE students.<\/p><\/article>\n  <\/div>\n  <div class=\"kge-safe-note\">Your code runs in a secure browser environment. Files stay on your device and are not uploaded to the website server.<\/div>\n  <div class=\"kge-python-seo-content\">\n    <h2>Free Online Python Compiler<\/h2>\n    <p>Use this online Python compiler and coding lab to write, run and test Python code directly in your browser. It supports user input, standard Python libraries and browser-based file handling, including CSV files.<\/p>\n  <\/div>\n<\/section>\n\n<script src=\"https:\/\/cdn.jsdelivr.net\/pyodide\/v0.29.3\/full\/pyodide.js\"><\/script>\n<script>\n(function () {\n  \"use strict\";\n  const lab=document.getElementById(\"kge-python-lab\"); if(!lab)return;\n  const status=document.getElementById(\"kge-python-status\"),code=document.getElementById(\"kge-python-code\"),terminal=document.getElementById(\"kge-python-terminal\"),runButton=document.getElementById(\"kge-python-run\"),clearButton=document.getElementById(\"kge-python-clear\"),stopButton=document.getElementById(\"kge-python-stop\"),fileInput=document.getElementById(\"kge-python-file-input\"),fileList=document.getElementById(\"kge-python-file-list\"),fileViewer=document.getElementById(\"kge-python-file-viewer\"),fileViewerTitle=document.getElementById(\"kge-python-file-viewer-title\"),fileViewerContent=document.getElementById(\"kge-python-file-content\"),closeViewer=document.getElementById(\"kge-python-close-viewer\");\n  let pyodide=null,pythonReady=false,running=false; const uploadedFiles={};\n  const KGE_WELCOME_LOGO_CODE=\"from js import document, window\\nfrom pyodide.ffi import create_proxy, to_js\\n\\ntry:\\n    window.clearInterval(window.kgeLogoInterval)\\n    window.kgeLogoProxy.destroy()\\nexcept:\\n    pass\\n\\ncanvas = document.createElement(\\\"canvas\\\")\\ncanvas.width = 420\\ncanvas.height = 560\\ncanvas.style.width = \\\"100%\\\"\\ncanvas.style.maxWidth = \\\"240px\\\"\\ncanvas.style.height = \\\"auto\\\"\\ncanvas.style.display = \\\"block\\\"\\ncanvas.style.margin = \\\"10px auto\\\"\\ncanvas.style.borderRadius = \\\"10px\\\"\\n\\noutput = document.getElementById(\\\"kge-python-terminal\\\")\\noutput.appendChild(canvas)\\nctx = canvas.getContext(\\\"2d\\\")\\n\\nDARK_GREEN = \\\"#001F18\\\"\\nGOLD = \\\"#E5C05B\\\"\\nLIGHT_GOLD = \\\"#FFE59A\\\"\\nWHITE = \\\"#FFFFFF\\\"\\n\\npaths = [\\n\\\"M 92 130 L 328 130 L 328 310 C 312 354 270 386 210 420 C 150 386 108 354 92 310 Z\\\",\\n\\\"M 108 148 L 312 148 L 312 300 C 292 338 257 365 210 393 C 163 365 128 338 108 300 Z\\\",\\n\\\"M 110 126 C 143 123 166 102 190 78 C 201 68 208 62 210 53\\\",\\n\\\"M 310 126 C 277 123 254 102 230 78 C 219 68 212 62 210 53\\\",\\n\\\"M 91 126 C 55 118 51 83 72 70 C 91 58 112 71 108 89 C 105 105 86 105 82 92 C 78 82 90 77 97 85\\\",\\n\\\"M 329 126 C 365 118 369 83 348 70 C 329 58 308 71 312 89 C 315 105 334 105 338 92 C 342 82 330 77 323 85\\\",\\n\\\"M 92 165 C 66 141 38 153 42 181 C 45 204 72 210 82 192 C 91 176 74 163 62 173 C 53 181 63 191 72 184 M 92 206 C 67 196 49 217 57 239 C 66 263 86 271 94 288\\\",\\n\\\"M 328 165 C 354 141 382 153 378 181 C 375 204 348 210 338 192 C 329 176 346 163 358 173 C 367 181 357 191 348 184 M 328 206 C 353 196 371 217 363 239 C 354 263 334 271 326 288\\\",\\n\\\"M 92 312 C 67 326 45 319 38 302 C 27 278 52 266 69 278 C 84 289 75 308 61 304 M 92 319 C 112 344 134 365 174 390\\\",\\n\\\"M 328 312 C 353 326 375 319 382 302 C 393 278 368 266 351 278 C 336 289 345 308 359 304 M 328 319 C 308 344 286 365 246 390\\\",\\n\\\"M 210 52 C 195 39 194 24 210 3 C 226 24 225 39 210 52 M 210 34 C 194 28 187 39 196 49 M 210 34 C 226 28 233 39 224 49 M 199 52 L 221 52 L 210 72 Z\\\",\\n\\\"M 52 438 L 368 438\\\",\\n\\\"M 52 522 L 368 522\\\"\\n]\\n\\nPath2D = window.Path2D\\ncanvas_paths = [Path2D.new(path) for path in paths]\\ndash_pattern = to_js([2400, 2400])\\nframe = 0\\ndrawing_frames = 170\\npause_frames = 75\\n\\ndef draw_path(path, progress, width=3):\\n    progress = max(0, min(1, progress))\\n    ctx.save()\\n    ctx.strokeStyle = GOLD\\n    ctx.lineWidth = width\\n    ctx.lineCap = \\\"round\\\"\\n    ctx.lineJoin = \\\"round\\\"\\n    ctx.setLineDash(dash_pattern)\\n    ctx.lineDashOffset = 2400 * (1 - progress)\\n    ctx.stroke(path)\\n    ctx.restore()\\n\\ndef show_text(text, x, y, size, colour, progress):\\n    if progress <= 0:\\n        return\\n    ctx.save()\\n    ctx.globalAlpha = min(1, progress)\\n    ctx.fillStyle = colour\\n    ctx.textAlign = \\\"center\\\"\\n    ctx.textBaseline = \\\"middle\\\"\\n    ctx.font = f\\\"bold {size}px Georgia, serif\\\"\\n    ctx.fillText(text, x, y)\\n    ctx.restore()\\n\\ndef animate_logo():\\n    global frame\\n    ctx.fillStyle = DARK_GREEN\\n    ctx.fillRect(0, 0, canvas.width, canvas.height)\\n    progress = min(1, frame \/ drawing_frames)\\n    count = len(canvas_paths)\\n    for index, path in enumerate(canvas_paths):\\n        local_progress = (progress - index \/ (count + 5)) * 2.7\\n        draw_path(path, local_progress, 5 if index == 0 else 2.5)\\n    show_text(\\\"KG\\\", 210, 238, 108, WHITE, (progress - 0.48) * 4)\\n    show_text(\\\"KNIGHTON\\\", 210, 466, 32, WHITE, (progress - 0.68) * 4)\\n    show_text(\\\"GRANGE\\\", 210, 503, 29, GOLD, (progress - 0.76) * 4)\\n    show_text(\\\"E D U C A T I O N\\\", 210, 543, 15, GOLD, (progress - 0.86) * 5)\\n    frame += 1\\n    if frame > drawing_frames + pause_frames:\\n        frame = 0\\n\\nanimation_proxy = create_proxy(animate_logo)\\nwindow.kgeLogoProxy = animation_proxy\\nwindow.kgeLogoInterval = window.setInterval(animation_proxy, 25)\\n\";\n\n  function stopWelcomeLogo(){\n    try{if(window.kgeLogoInterval)window.clearInterval(window.kgeLogoInterval);}catch(error){}\n    try{if(window.kgeLogoProxy)window.kgeLogoProxy.destroy();}catch(error){}\n    try{delete window.kgeLogoInterval;delete window.kgeLogoProxy;}catch(error){}\n  }\n\n  async function startWelcomeLogo(){\n    stopWelcomeLogo();\n    clearTerminal();\n    await pyodide.runPythonAsync(KGE_WELCOME_LOGO_CODE);\n  }\n  const codeWrapper=lab.querySelector(\".kge-code-wrapper\");\n  const resizer=document.getElementById(\"kge-python-resizer\");\n\n  function setPanelSplit(percent){\n    const safePercent=Math.max(25,Math.min(75,percent));\n    codeWrapper.style.setProperty(\"--kge-code-width\",safePercent+\"%\");\n    resizer.setAttribute(\"aria-valuenow\",String(Math.round(safePercent)));\n  }\n\n  resizer.addEventListener(\"pointerdown\",function(event){\n    if(window.matchMedia(\"(max-width: 900px)\").matches)return;\n    resizer.setPointerCapture(event.pointerId);\n    codeWrapper.classList.add(\"kge-is-resizing\");\n  });\n\n  resizer.addEventListener(\"pointermove\",function(event){\n    if(!resizer.hasPointerCapture(event.pointerId))return;\n    const bounds=codeWrapper.getBoundingClientRect();\n    setPanelSplit(((event.clientX-bounds.left)\/bounds.width)*100);\n  });\n\n  function finishResize(event){\n    if(resizer.hasPointerCapture(event.pointerId))resizer.releasePointerCapture(event.pointerId);\n    codeWrapper.classList.remove(\"kge-is-resizing\");\n  }\n\n  resizer.addEventListener(\"pointerup\",finishResize);\n  resizer.addEventListener(\"pointercancel\",finishResize);\n  resizer.addEventListener(\"dblclick\",function(){setPanelSplit(66.666);});\n  resizer.addEventListener(\"keydown\",function(event){\n    if(event.key!==\"ArrowLeft\"&&event.key!==\"ArrowRight\")return;\n    event.preventDefault();\n    const current=parseFloat(getComputedStyle(codeWrapper).getPropertyValue(\"--kge-code-width\"))||66.666;\n    setPanelSplit(current+(event.key===\"ArrowRight\"?2:-2));\n  });\n\n  function terminalScroll(){terminal.scrollTop=terminal.scrollHeight;}\n  function clearTerminal(){terminal.innerHTML=\"\";terminalScroll();}\n  function addTerminalLine(text,className){const line=document.createElement(\"div\");line.className=\"kge-terminal-line \"+(className||\"\");line.textContent=text;terminal.appendChild(line);terminalScroll();}\n  async function pythonInput(prompt){const cleanPrompt=String(prompt||\"\").replace(\/^[\\\"']|[\\\"']$\/g,\"\").trim();const answer=window.prompt(cleanPrompt||\"Python Input\",\"\");return answer===null?\"\":answer;}\n  async function startPython(){\n    try{\n      status.textContent=\"Loading Python...\";status.style.color=\"#C5A059\";clearTerminal();addTerminalLine(\"Python Coding Lab\");addTerminalLine(\"Loading Python runtime...\");addTerminalLine(\"The first load may take a little while.\");\n      if(typeof loadPyodide!==\"function\")throw new Error(\"Pyodide JavaScript did not load.\");\n      pyodide=await loadPyodide({indexURL:\"https:\/\/cdn.jsdelivr.net\/pyodide\/v0.29.3\/full\/\"});\nstatus.textContent = \"Loading Python libraries...\";\n\n\/\/ Set the chart destination before Matplotlib is loaded.\ndocument.pyodideMplTarget = terminal;\n\n\/\/ Main data-science libraries available to student programs.\nawait pyodide.loadPackage([\n  \"numpy\",\n  \"pandas\",\n  \"matplotlib\",\n  \"scipy\",\n  \"scikit-learn\"\n]);\n      pyodide.globals.set(\"kge_browser_input\",pythonInput);\n      await pyodide.runPythonAsync(`\nimport builtins\nimport asyncio\nasync def _kge_async_input(prompt=\"\"):\n    return await kge_browser_input(prompt)\ndef _kge_input(prompt=\"\"):\n    loop = asyncio.get_event_loop()\n    return loop.run_until_complete(_kge_async_input(prompt))\nbuiltins.input = _kge_input\n`);\n      pythonReady=true;status.textContent=\"Python ready\";status.style.color=\"#4dcc72\";runButton.disabled=false;await startWelcomeLogo();\n    }catch(error){console.error(error);status.textContent=\"Python failed to load\";status.style.color=\"#ef6666\";clearTerminal();addTerminalLine(\"PYTHON COULD NOT BE LOADED\",\"kge-terminal-error\");addTerminalLine(\"\");addTerminalLine(String(error),\"kge-terminal-error\");}\n  }\n  function normalisePythonQuotes(source){\n    return source\n      .replace(\/[\u201c\u201d]\/g,'\"')\n      .replace(\/[\u2018\u2019]\/g,\"'\")\n      .replace(\/[\\u2013\\u2014\\u2212]\/g,\"-\");\n  }\n  async function runPython(){\n    if(!pythonReady||!pyodide||running)return;stopWelcomeLogo();running=true;runButton.disabled=true;stopButton.disabled=false;clearTerminal();addTerminalLine(\">>> Running Python...\");addTerminalLine(\"\");let outputBuffer=\"\";\n    pyodide.setStdout({batched:function(text){outputBuffer+=text;addTerminalLine(text);}});pyodide.setStderr({batched:function(text){outputBuffer+=text;addTerminalLine(text,\"kge-terminal-error\");}});\n    try{\n      await pyodide.runPythonAsync('import os\\nos.makedirs(\"\/home\/pyodide\", exist_ok=True)');\n\n      \/\/ Re-apply the output target before every run.\n      document.pyodideMplTarget = terminal;\n      await pyodide.runPythonAsync(`\nimport sys\nif \"matplotlib.pyplot\" in sys.modules:\n    import matplotlib.pyplot as plt\n    plt.close(\"all\")\n`);\n\n      await pyodide.runPythonAsync(normalisePythonQuotes(code.value));\n      if(outputBuffer.trim()===\"\")addTerminalLine(\"Program finished successfully.\",\"kge-terminal-success\");\n      addTerminalLine(\"\");addTerminalLine(\">>> Program finished.\",\"kge-terminal-success\");status.textContent=\"Program finished\";status.style.color=\"#4dcc72\";\n    }\n    catch(error){console.error(error);addTerminalLine(\"\");const errorText=String(error);if(errorText.includes(\"invalid character '\u201c'\")||errorText.includes(\"invalid character '\u201d'\")){addTerminalLine(\"Python contains curly quotation marks.\",\"kge-terminal-error\");addTerminalLine('Use normal quotes like: input(\"What is your name? \")',\"kge-terminal-error\");}else addTerminalLine(errorText,\"kge-terminal-error\");status.textContent=\"Python error\";status.style.color=\"#ef6666\";}\n    running=false;runButton.disabled=false;stopButton.disabled=true;\n  }\n  clearButton.addEventListener(\"click\",function(){stopWelcomeLogo();clearTerminal();if(pythonReady)addTerminalLine(\"Output cleared.\");});\n  runButton.addEventListener(\"click\",runPython);\n  stopButton.addEventListener(\"click\",function(){running=false;stopButton.disabled=true;runButton.disabled=false;addTerminalLine(\"\");addTerminalLine(\"Execution stopped.\",\"kge-terminal-error\");status.textContent=\"Ready\";status.style.color=\"#C5A059\";});\n  code.addEventListener(\"keydown\",function(event){if(event.key===\"Enter\"&&(event.ctrlKey||event.metaKey)){event.preventDefault();runPython();return;}if(event.key===\"Tab\"){event.preventDefault();const start=code.selectionStart,end=code.selectionEnd;code.value=code.value.substring(0,start)+\"    \"+code.value.substring(end);code.selectionStart=code.selectionEnd=start+4;}});\n  const tabs=lab.querySelectorAll(\".kge-python-tab\");tabs.forEach(function(tab){tab.addEventListener(\"click\",function(){const selected=tab.getAttribute(\"data-tab\");tabs.forEach(item=>item.classList.remove(\"active\"));tab.classList.add(\"active\");lab.querySelectorAll(\".kge-python-panel\").forEach(panel=>panel.classList.remove(\"active\"));const panel=document.getElementById(\"kge-python-\"+selected+\"-panel\");if(panel)panel.classList.add(\"active\");});});\n  fileInput.addEventListener(\"change\",async function(){\n    const files=Array.from(fileInput.files);if(!files.length)return;if(!pyodide){alert(\"Please wait for Python to finish loading.\");return;}\n    for(const file of files){try{const bytes=new Uint8Array(await file.arrayBuffer()),safeName=file.name.replace(\/\\\\\/g,\"\/\").replace(\/^\\\/+\/,\"\"),pyodidePath=\"\/home\/pyodide\/\"+safeName;pyodide.FS.writeFile(pyodidePath,bytes);uploadedFiles[file.name]={path:pyodidePath};\n      const item=document.createElement(\"div\"),left=document.createElement(\"div\"),name=document.createElement(\"span\"),size=document.createElement(\"span\"),buttons=document.createElement(\"div\"),viewButton=document.createElement(\"button\"),downloadButton=document.createElement(\"button\");\n      item.className=\"kge-file-item\";left.className=\"kge-file-left\";name.className=\"kge-file-name\";name.textContent=file.name;size.className=\"kge-file-size\";size.textContent=formatBytes(file.size);buttons.className=\"kge-file-buttons\";viewButton.type=\"button\";viewButton.className=\"kge-view-file\";viewButton.textContent=\"View File\";viewButton.addEventListener(\"click\",()=>viewFile(file.name));downloadButton.type=\"button\";downloadButton.className=\"kge-download-file\";downloadButton.textContent=\"Download\";downloadButton.addEventListener(\"click\",()=>downloadFile(file.name));left.append(name,size);buttons.append(viewButton,downloadButton);item.append(left,buttons);fileList.appendChild(item);\n    }catch(error){console.error(\"File error:\",error);alert(\"Could not load \"+file.name);}}fileInput.value=\"\";\n  });\n  async function viewFile(fileName){try{const fileInfo=uploadedFiles[fileName];if(!fileInfo)throw new Error(\"File is not available.\");if(!pyodide||!pyodide.FS)throw new Error(\"Python filesystem is not ready.\");const content=new TextDecoder(\"utf-8\").decode(pyodide.FS.readFile(fileInfo.path));fileViewerTitle.textContent=fileName;fileViewerContent.textContent=content;fileViewer.classList.add(\"active\");fileViewer.scrollIntoView({behavior:\"smooth\",block:\"nearest\"});}catch(error){console.error(\"View file error:\",error);fileViewerTitle.textContent=fileName;fileViewerContent.textContent=\"This file could not be displayed.\\n\\n\"+String(error);fileViewer.classList.add(\"active\");}}\n  function downloadFile(fileName){try{const fileInfo=uploadedFiles[fileName];if(!fileInfo)throw new Error(\"File is not available.\");if(!pyodide||!pyodide.FS)throw new Error(\"Python filesystem is not ready.\");const data=pyodide.FS.readFile(fileInfo.path),blob=new Blob([data],{type:getMimeType(fileName)}),url=URL.createObjectURL(blob),link=document.createElement(\"a\");link.href=url;link.download=fileName;link.style.display=\"none\";document.body.appendChild(link);link.click();document.body.removeChild(link);setTimeout(()=>URL.revokeObjectURL(url),1000);}catch(error){console.error(\"Download error:\",error);alert(\"Could not download \"+fileName+\"\\n\\n\"+String(error));}}\n  function getMimeType(fileName){const lower=fileName.toLowerCase();if(lower.endsWith(\".csv\"))return \"text\/csv;charset=utf-8\";if(lower.endsWith(\".json\"))return \"application\/json;charset=utf-8\";if(lower.endsWith(\".txt\")||lower.endsWith(\".py\"))return \"text\/plain;charset=utf-8\";if(lower.endsWith(\".html\"))return \"text\/html;charset=utf-8\";return \"application\/octet-stream\";}\n  closeViewer.addEventListener(\"click\",function(){fileViewer.classList.remove(\"active\");fileViewerContent.textContent=\"\";});\n  function formatBytes(bytes){if(bytes===0)return \"0 Bytes\";const units=[\"Bytes\",\"KB\",\"MB\",\"GB\"],index=Math.min(Math.floor(Math.log(bytes)\/Math.log(1024)),units.length-1);return parseFloat((bytes\/Math.pow(1024,index)).toFixed(2))+\" \"+units[index];}\n  function begin(){setTimeout(startPython,100);}if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",begin);else begin();\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Online Python &#8211; IDE, Editor, Compiler, Interpreter Write, run and test Python code in your browser. Starting Python&#8230; main.py \u25b6 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"pmpro_default_level":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-901191","page","type-page","status-publish","hentry","pmpro-has-access"],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/pages\/901191","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/comments?post=901191"}],"version-history":[{"count":81,"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/pages\/901191\/revisions"}],"predecessor-version":[{"id":901279,"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/pages\/901191\/revisions\/901279"}],"wp:attachment":[{"href":"https:\/\/knightongrange.co.uk\/portal\/wp-json\/wp\/v2\/media?parent=901191"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}