2026-01-23 23:30:29 +01:00
# include "amduatd_ui.h"
2026-01-24 06:50:53 +01:00
# include "amduatd_http.h"
2026-01-23 23:30:29 +01:00
# include "amduat/asl/artifact_io.h"
# include "amduat/asl/asl_store_fs.h"
# include "amduat/asl/asl_store_fs_meta.h"
# include "amduat/asl/ref_derive.h"
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <string.h>
static const char k_amduatd_ui_html [ ] =
" <!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>amduatd — Concept editor</title> \n "
" <style> \n "
" :root{ \n "
" --bg:#0b1220;--card:#111a2e;--text:#eaf0ff;--muted:#b7c3e6;--border:rgba(255,255,255,.10); \n "
" --shadow:0 10px 30px rgba(0,0,0,.35);--radius:18px;--max:980px;--pad:clamp(16px,3.5vw,28px); \n "
" } \n "
" *{box-sizing:border-box;} \n "
" html,body{min-height:100%;} \n "
" html{background:var(--bg);} \n "
" body{margin:0;min-height:100vh;font-family: \" Avenir Next \" , \" Avenir \" , \" Trebuchet MS \" , \" Segoe UI \" ,sans-serif;color:var(--text);line-height:1.55; "
" background:radial-gradient(900px 400px at 15% 10%,rgba(95,145,255,.35),transparent 60%), "
" radial-gradient(800px 450px at 85% 20%,rgba(255,140,92,.25),transparent 60%), "
" radial-gradient(700px 500px at 50% 95%,rgba(56,220,181,.18),transparent 60%),var(--bg);} \n "
" a{color:inherit;text-decoration:none;} \n "
" a:hover{text-decoration:underline;text-underline-offset:4px;} \n "
" .wrap{max-width:var(--max);margin:0 auto;padding:26px var(--pad) 70px;min-height:100vh;} \n "
" header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 0 22px;} \n "
" .brand{display:flex;align-items:center;gap:10px;font-weight:700;letter-spacing:.2px;} \n "
" .logo{width:38px;height:38px;border-radius:12px;border:1px solid var(--border); "
" background:linear-gradient(135deg,rgba(95,145,255,.9),rgba(56,220,181,.8));box-shadow:var(--shadow);} \n "
" nav{display:flex;gap:14px;flex-wrap:wrap;color:var(--muted);font-size:14px;} \n "
" nav a{padding:6px 10px;border-radius:10px;} \n "
" nav a:hover{background:rgba(255,255,255,.06);text-decoration:none;} \n "
" .hero{border:1px solid var(--border);background:rgba(17,26,46,.72);border-radius:var(--radius);box-shadow:var(--shadow); "
" padding:clamp(22px,4.5vw,42px);backdrop-filter:blur(10px);} \n "
" h1{margin:0 0 10px;font-size:clamp(28px,3.6vw,40px);line-height:1.1;letter-spacing:-0.6px;} \n "
" .lead{margin:0 0 18px;color:var(--muted);font-size:clamp(14px,2vw,17px);max-width:70ch;} \n "
" .cta-row{display:flex;flex-wrap:wrap;gap:12px;margin-top:10px;} \n "
" .grid{display:grid;grid-template-columns:repeat(12,1fr);gap:14px;margin-top:16px;} \n "
" .card{grid-column:span 12;border:1px solid var(--border);background:rgba(17,26,46,.62);border-radius:16px;padding:16px; "
" box-shadow:0 8px 22px rgba(0,0,0,.25);backdrop-filter:blur(10px);} \n "
" .card h2{margin:2px 0 6px;font-size:16px;letter-spacing:.1px;} \n "
" .muted{color:var(--muted);font-size:13px;} \n "
" .span-7{grid-column:span 12;} \n "
" .span-5{grid-column:span 12;} \n "
" .span-6{grid-column:span 12;} \n "
" .stack{display:grid;gap:14px;} \n "
" @media (min-width: 980px){.span-7{grid-column:span 7;}.span-5{grid-column:span 5;}.span-6{grid-column:span 6;}} \n "
" textarea,input,select{width:100%;box-sizing:border-box;border-radius:12px;padding:10px;border:1px solid var(--border); "
" background:rgba(0,0,0,.12);color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace; "
" font-size:12.5px;} \n "
" textarea{min-height:420px;resize:vertical;} \n "
" .btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;padding:10px 14px;border-radius:12px;border:1px solid var(--border); "
" background:rgba(255,255,255,.06);color:var(--text);font-weight:600;font-size:14px;cursor:pointer;} \n "
" .btn:hover{background:rgba(255,255,255,.10);} \n "
" .btn.primary{background:linear-gradient(135deg,rgba(95,145,255,.95),rgba(56,220,181,.85));border-color:rgba(255,255,255,.18);} \n "
" .btn.primary:hover{filter:brightness(1.05);} \n "
" .row{display:flex;gap:10px;flex-wrap:wrap;align-items:center;} \n "
" .row > *{flex:1 1 auto;} \n "
" .row .btn{flex:0 0 auto;} \n "
" pre{white-space:pre-wrap;word-break:break-word;margin:0;padding:10px;border-radius:12px;border:1px solid var(--border); "
" background:rgba(0,0,0,.2);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace; "
" font-size:12.5px;min-height:120px;color:var(--text);} \n "
" footer{margin-top:26px;color:var(--muted);font-size:13px;display:flex;gap:10px;justify-content:space-between;flex-wrap:wrap;} \n "
" .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;} \n "
" </style> \n "
" </head> \n "
" <body> \n "
" <div class= \" wrap \" > \n "
" <header> \n "
" <div class= \" brand \" aria-label= \" Site brand \" > \n "
" <div class= \" logo \" aria-hidden= \" true \" ></div> \n "
" <span>amduatd</span> \n "
" </div> \n "
" <nav aria-label= \" Primary \" > \n "
" <a href= \" #editor \" >Editor</a> \n "
" <a href= \" #runner \" >Run</a> \n "
" <a href= \" #relations \" >Relations</a> \n "
" <a href= \" #about \" >About</a> \n "
" </nav> \n "
" </header> \n "
" <main> \n "
" <section class= \" hero \" aria-labelledby= \" title \" > \n "
" <h1 id= \" title \" >Concept editor + PEL runner</h1> \n "
" <p class= \" lead \" >Load shows the latest materialized bytes; Save uploads a new artifact and publishes a new version. Use the runner to execute PEL programs against stored artifacts.</p> \n "
" <div class= \" cta-row \" > \n "
" <a class= \" btn primary \" href= \" #editor \" role= \" button \" >Open editor</a> \n "
" <a class= \" btn \" href= \" #runner \" role= \" button \" >Run program</a> \n "
" </div> \n "
" </section> \n "
" <section class= \" grid \" style= \" margin-top:16px; \" > \n "
" <div class= \" card span-7 \" id= \" editor \" > \n "
" <div class= \" row \" > \n "
" <input id= \" conceptName \" placeholder= \" concept name (e.g. hello) \" /> \n "
" <button class= \" btn \" id= \" btnConceptCreate \" type= \" button \" >Create</button> \n "
" <button class= \" btn \" id= \" btnLoad \" type= \" button \" >Load</button> \n "
" <button class= \" btn \" id= \" btnSave \" type= \" button \" >Save</button> \n "
" </div> \n "
" <div class= \" row \" style= \" margin-top:10px; \" > \n "
" <select id= \" mode \" > \n "
" <option value= \" text \" >bytes: text (utf-8)</option> \n "
" <option value= \" base64 \" >bytes: base64</option> \n "
" <option value= \" hex \" >bytes: hex</option> \n "
" <option value= \" pel_program \" >PEL program: JSON</option> \n "
" </select> \n "
" <input id= \" typeTag \" placeholder= \" X-Amduat-Type-Tag (optional) \" /> \n "
" <input id= \" latestRef \" placeholder= \" latest_ref \" readonly /> \n "
" </div> \n "
" <textarea id= \" editor \" spellcheck= \" false \" placeholder= \" (bytes or PEL program authoring JSON) \" ></textarea> \n "
" <div class= \" row \" style= \" margin-top:10px; \" > \n "
" <button class= \" btn \" id= \" btnProgramTemplate \" type= \" button \" >Insert identity program</button> \n "
" </div> \n "
" <div class= \" row \" style= \" margin-top:10px; \" > \n "
" <input id= \" publishRef \" placeholder= \" publish existing ref \" /> \n "
" <button class= \" btn \" id= \" btnPublishRef \" type= \" button \" >Publish ref</button> \n "
" </div> \n "
" </div> \n "
" \n "
" <div class= \" stack span-5 \" > \n "
" <div class= \" card \" id= \" runner \" > \n "
" <div class= \" muted \" style= \" margin-bottom:8px; \" >Upload bytes (sets program_ref)</div> \n "
" <div class= \" row \" > \n "
" <input id= \" uploadFile \" type= \" file \" /> \n "
" <button class= \" btn \" id= \" btnUpload \" type= \" button \" >Upload</button> \n "
" </div> \n "
" <hr style= \" border:none;border-top:1px solid rgba(255,255,255,.10);margin:14px 0; \" /> \n "
" <div class= \" muted \" style= \" margin-bottom:8px; \" >Run</div> \n "
" <input id= \" programRef \" placeholder= \" program_ref (hex ref or concept name) \" /> \n "
" <div class= \" muted \" style= \" margin:10px 0 8px; \" >input_refs (comma-separated hex refs or names)</div> \n "
" <input id= \" inputRefs \" placeholder= \" in0,in1,... \" /> \n "
" <div class= \" muted \" style= \" margin:10px 0 8px; \" >params_ref (optional)</div> \n "
" <input id= \" paramsRef \" placeholder= \" params \" /> \n "
" <div class= \" muted \" style= \" margin:10px 0 8px; \" >scheme_ref (optional, default dag)</div> \n "
" <input id= \" schemeRef \" placeholder= \" dag \" /> \n "
" <div class= \" row \" style= \" margin-top:12px; \" > \n "
" <button class= \" btn primary \" id= \" btnRun \" type= \" button \" >Run</button> \n "
" <a class= \" muted \" href= \" /v1/contract \" >/v1/contract</a> \n "
" <a class= \" muted \" href= \" /v1/meta \" >/v1/meta</a> \n "
" </div> \n "
" <div class= \" muted \" style= \" margin:14px 0 8px; \" >Response</div> \n "
" <pre id= \" out \" ></pre> \n "
" </div> \n "
" <div class= \" card \" id= \" relations \" > \n "
" <div class= \" muted \" style= \" margin-bottom:8px; \" >Relations</div> \n "
" <div class= \" row \" style= \" margin-top:10px; \" > \n "
" <button class= \" btn \" id= \" btnRelations \" type= \" button \" >Refresh</button> \n "
" </div> \n "
" <pre id= \" relationsOut \" ></pre> \n "
" </div> \n "
" </div> \n "
" </section> \n "
" <section id= \" about \" class= \" grid \" style= \" margin-top:16px; \" > \n "
" <article class= \" card span-6 \" > \n "
" <h2>About</h2> \n "
" <p class= \" muted \" >amduatd is a local-first mapping surface over a single ASL store root. This UI is a lightweight editor and runner for concepts and PEL programs.</p> \n "
" </article> \n "
" <article class= \" card span-6 \" > \n "
" <h2>Links</h2> \n "
" <p class= \" muted \" ><a href= \" /v1/contract \" >/v1/contract</a> • <a href= \" /v1/meta \" >/v1/meta</a> • <a href= \" /v1/relations \" >/v1/relations</a></p> \n "
" </article> \n "
" </section> \n "
" </main> \n "
" <footer> \n "
" <span>© 2025 Niklas Rydberg.</span> \n "
" <span><a href= \" #title \" >Back to top</a></span> \n "
" </footer> \n "
" </div> \n "
" \n "
" <script> \n "
" const el = (id) => document.getElementById(id); \n "
" const out = (v) => { el('out').textContent = typeof v === 'string' ? v : JSON.stringify(v, null, 2); }; \n "
" const td = new TextDecoder('utf-8'); \n "
" const te = new TextEncoder(); \n "
" const toHex = (u8) => Array.from(u8).map(b => b.toString(16).padStart(2,'0')).join(''); \n "
" const fromHex = (s) => { const t=(s||'').trim(); if(t.length%2) throw new Error('hex length must be even'); const o=new Uint8Array(t.length/2); for(let i=0;i<o.length;i++){o[i]=parseInt(t.slice(i*2,i*2+2),16);} return o; }; \n "
" const toB64 = (u8) => { let bin=''; for(let i=0;i<u8.length;i++) bin += String.fromCharCode(u8[i]); return btoa(bin); }; \n "
" const fromB64 = (s) => { const bin=atob((s||'').trim()); const o=new Uint8Array(bin.length); for(let i=0;i<bin.length;i++) o[i]=bin.charCodeAt(i); return o; }; \n "
" \n "
" async function ensureConcept(name){ \n "
" const resp = await fetch('/v1/concepts',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name})}); \n "
" if(resp.status === 409) return; // already exists \n "
" if(!resp.ok) throw new Error(await resp.text()); \n "
" } \n "
" \n "
" async function loadConcept(){ \n "
" const name = el('conceptName').value.trim(); \n "
" if(!name){ out('missing concept name'); return; } \n "
" const resp = await fetch(`/v1/concepts/${encodeURIComponent(name)}`); \n "
" const text = await resp.text(); \n "
" if(!resp.ok){ out(text); return; } \n "
" const j = JSON.parse(text); \n "
" el('latestRef').value = j.latest_ref || ''; \n "
" el('programRef').value = name; \n "
" if(!j.latest_ref){ el('editor').value=''; out(text); return; } \n "
" const mode = el('mode').value; \n "
" const infoResp = await fetch(`/v1/artifacts/${j.latest_ref}?format=info`); \n "
" if(infoResp.ok){ const info = JSON.parse(await infoResp.text()); el('typeTag').value = info.has_type_tag ? info.type_tag : ''; } \n "
" if(mode === 'pel_program'){ \n "
" if(!el('editor').value.trim()){ \n "
" el('editor').value = JSON.stringify({ \n "
" nodes:[{id:1,op:{name:'pel.bytes.concat',version:1},inputs:[{external:{input_index:0}}],params_hex:''}], \n "
" roots:[{node_id:1,output_index:0}] \n "
" }, null, 2); \n "
" } \n "
" out(text); \n "
" return; \n "
" } \n "
" const aResp = await fetch(`/v1/artifacts/${j.latest_ref}`); \n "
" if(!aResp.ok){ out(await aResp.text()); return; } \n "
" const u8 = new Uint8Array(await aResp.arrayBuffer()); \n "
" if(mode==='hex') el('editor').value = toHex(u8); \n "
" else if(mode==='base64') el('editor').value = toB64(u8); \n "
" else el('editor').value = td.decode(u8); \n "
" out(text); \n "
" } \n "
" \n "
" async function saveConcept(){ \n "
" const name = el('conceptName').value.trim(); \n "
" if(!name){ out('missing concept name'); return; } \n "
" await ensureConcept(name); \n "
" const mode = el('mode').value; \n "
" if(mode === 'pel_program'){ \n "
" const body = JSON.parse(el('editor').value || '{}'); \n "
" const mkResp = await fetch('/v1/pel/programs',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}); \n "
" const mkText = await mkResp.text(); \n "
" if(!mkResp.ok){ out(mkText); return; } \n "
" const mk = JSON.parse(mkText); \n "
" const pref = mk.program_ref; \n "
" const pubResp = await fetch(`/v1/concepts/${encodeURIComponent(name)}/publish`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({ref:pref})}); \n "
" const pubText = await pubResp.text(); \n "
" out(pubText); \n "
" if(pubResp.ok){ el('typeTag').value = '0x00000101'; await loadConcept(); } \n "
" return; \n "
" } \n "
" let u8; \n "
" if(mode==='hex') u8 = fromHex(el('editor').value); \n "
" else if(mode==='base64') u8 = fromB64(el('editor').value); \n "
" else u8 = te.encode(el('editor').value); \n "
" const headers = {'Content-Type':'application/octet-stream'}; \n "
" const typeTag = el('typeTag').value.trim(); \n "
" if(typeTag) headers['X-Amduat-Type-Tag'] = typeTag; \n "
" const putResp = await fetch('/v1/artifacts',{method:'POST',headers,body:u8}); \n "
" const putText = await putResp.text(); \n "
" if(!putResp.ok){ out(putText); return; } \n "
" const put = JSON.parse(putText); \n "
" const pubResp = await fetch(`/v1/concepts/${encodeURIComponent(name)}/publish`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({ref:put.ref})}); \n "
" const pubText = await pubResp.text(); \n "
" out(pubText); \n "
" if(pubResp.ok) await loadConcept(); \n "
" } \n "
" \n "
" el('btnConceptCreate').addEventListener('click', async () => { try{ await ensureConcept(el('conceptName').value.trim()); out('{ \" ok \" :true} \\ n'); }catch(e){ out(String(e)); } }); \n "
" el('btnLoad').addEventListener('click', () => loadConcept().catch(e => out(String(e)))); \n "
" el('btnSave').addEventListener('click', () => saveConcept().catch(e => out(String(e)))); \n "
" el('mode').addEventListener('change', () => { \n "
" if(el('mode').value === 'pel_program'){ \n "
" el('typeTag').value = '0x00000101'; \n "
" } \n "
" loadConcept().catch(() => {}); \n "
" }); \n "
" \n "
" el('btnProgramTemplate').addEventListener('click', () => { \n "
" el('mode').value = 'pel_program'; \n "
" el('typeTag').value = '0x00000101'; \n "
" el('editor').value = JSON.stringify({ \n "
" nodes:[{id:1,op:{name:'pel.bytes.concat',version:1},inputs:[{external:{input_index:0}}],params_hex:''}], \n "
" roots:[{node_id:1,output_index:0}] \n "
" }, null, 2); \n "
" }); \n "
" \n "
" el('btnPublishRef').addEventListener('click', async () => { \n "
" try{ \n "
" const name = el('conceptName').value.trim(); \n "
" const ref = el('publishRef').value.trim(); \n "
" if(!name||!ref){ out('missing name/ref'); return; } \n "
" await ensureConcept(name); \n "
" const resp = await fetch(`/v1/concepts/${encodeURIComponent(name)}/publish`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({ref})}); \n "
" out(await resp.text()); \n "
" }catch(e){ out(String(e)); } \n "
" }); \n "
" \n "
" el('btnUpload').addEventListener('click', async () => { \n "
" try { \n "
" const file = el('uploadFile').files && el('uploadFile').files[0]; \n "
" if (!file) { out('no file selected'); return; } \n "
" const resp = await fetch('/v1/artifacts', { method:'POST', headers:{'Content-Type':'application/octet-stream'}, body:file }); \n "
" const text = await resp.text(); \n "
" out(text); \n "
" if (resp.ok) { const j = JSON.parse(text); if (j && j.ref) el('programRef').value = j.ref; } \n "
" } catch (e) { out(String(e)); } \n "
" }); \n "
" \n "
" el('btnRun').addEventListener('click', async () => { \n "
" try { \n "
" const program_ref = el('programRef').value.trim(); \n "
" const input_refs = (el('inputRefs').value || '').split(',').map(s => s.trim()).filter(Boolean); \n "
" const params_ref = el('paramsRef').value.trim(); \n "
" const scheme_ref = el('schemeRef').value.trim(); \n "
" const body = { program_ref, input_refs }; \n "
" if (params_ref) body.params_ref = params_ref; \n "
" if (scheme_ref) body.scheme_ref = scheme_ref; \n "
" const resp = await fetch('/v1/pel/run', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body) }); \n "
" out(await resp.text()); \n "
" } catch (e) { out(String(e)); } \n "
" }); \n "
" \n "
" async function loadRelations(){ \n "
" const resp = await fetch('/v1/relations'); \n "
" const text = await resp.text(); \n "
" el('relationsOut').textContent = text; \n "
" } \n "
" el('btnRelations').addEventListener('click', () => loadRelations().catch(e => out(String(e)))); \n "
" loadRelations().catch(() => {}); \n "
" </script> \n "
" </body> \n "
" </html> \n " ;
bool amduatd_ui_can_handle ( const amduatd_http_req_t * req ) {
char no_query [ 1024 ] ;
if ( req = = NULL ) {
return false ;
}
if ( strcmp ( req - > method , " GET " ) ! = 0 ) {
return false ;
}
2026-01-24 06:50:53 +01:00
amduatd_path_without_query ( req - > path , no_query , sizeof ( no_query ) ) ;
2026-01-23 23:30:29 +01:00
return strcmp ( no_query , " /v1/ui " ) = = 0 ;
}
bool amduatd_ui_handle ( amduatd_ctx_t * ctx ,
const amduatd_http_req_t * req ,
amduatd_http_resp_t * resp ) {
amduat_artifact_t artifact ;
amduat_asl_store_error_t err ;
if ( ctx = = NULL | | req = = NULL | | resp = = NULL ) {
return false ;
}
if ( ! amduatd_ui_can_handle ( req ) ) {
return false ;
}
if ( ctx - > store = = NULL | | ctx - > ui_ref . hash_id = = 0 | |
ctx - > ui_ref . digest . data = = NULL | | ctx - > ui_ref . digest . len = = 0 ) {
resp - > ok = amduatd_http_send_text ( resp - > fd ,
500 ,
" Internal Server Error " ,
" ui not available \n " ,
false ) ;
return true ;
}
memset ( & artifact , 0 , sizeof ( artifact ) ) ;
err = amduat_asl_store_get ( ctx - > store , ctx - > ui_ref , & artifact ) ;
if ( err = = AMDUAT_ASL_STORE_ERR_NOT_FOUND ) {
resp - > ok = amduatd_http_send_text ( resp - > fd ,
404 ,
" Not Found " ,
" not found \n " ,
false ) ;
return true ;
}
if ( err ! = AMDUAT_ASL_STORE_OK ) {
amduat_asl_artifact_free ( & artifact ) ;
resp - > ok = amduatd_http_send_text ( resp - > fd ,
500 ,
" Internal Server Error " ,
" store error \n " ,
false ) ;
return true ;
}
if ( artifact . bytes . len ! = 0 & & artifact . bytes . data = = NULL ) {
amduat_asl_artifact_free ( & artifact ) ;
resp - > ok = amduatd_http_send_text ( resp - > fd ,
500 ,
" Internal Server Error " ,
" store error \n " ,
false ) ;
return true ;
}
resp - > ok = amduatd_http_send_status ( resp - > fd ,
200 ,
" OK " ,
" text/html; charset=utf-8 " ,
artifact . bytes . data ,
artifact . bytes . len ,
false ) ;
amduat_asl_artifact_free ( & artifact ) ;
return true ;
}
bool amduatd_seed_ui_html ( amduat_asl_store_t * store ,
const amduat_asl_store_fs_config_t * cfg ,
amduat_reference_t * out_ref ) {
amduat_artifact_t artifact ;
amduat_asl_store_error_t err ;
if ( out_ref ! = NULL ) {
memset ( out_ref , 0 , sizeof ( * out_ref ) ) ;
}
if ( store = = NULL | | cfg = = NULL | | out_ref = = NULL ) {
return false ;
}
artifact = amduat_artifact ( amduat_octets ( k_amduatd_ui_html ,
strlen ( k_amduatd_ui_html ) ) ) ;
( void ) amduat_asl_ref_derive ( artifact ,
cfg - > config . encoding_profile_id ,
cfg - > config . hash_id ,
out_ref ,
NULL ) ;
err = amduat_asl_store_put ( store , artifact , out_ref ) ;
if ( err ! = AMDUAT_ASL_STORE_OK ) {
return false ;
}
return true ;
}