SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "js1.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "199b96d2879c9f1857ed6163bb31b8e3c029faf45eb4c537cc8cb6b535777710")
37 STORE("fileCheckS", "1dd421b641d2fee44954fcde65c3b8cea0ec4fe5ed8bdc9a2a922f308963521f")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
const { useState, useEffect, useRef, useMemo, useCallback, createElement: h } = React;
// -- HOLOGRAM ADAPTER --
// Detecteer of we in Hologram/TELA draaien; gebruik telaHost API indien beschikbaar
const HOLOGRAM = typeof window !== 'undefined' && typeof window.telaHost !== 'undefined';
const UI = {
bgTop: '#0a1628', bgBot: '#040d1a',
orange: '#e07b39', orangeDim: 'rgba(224,123,57,0.20)',
blue: '#3B82F6', panelBg: 'rgba(4,7,21,0.96)',
cardBg: 'rgba(255,255,255,0.055)', cardBgHover: 'rgba(255,255,255,0.09)',
cardBorder: 'rgba(255,255,255,0.11)', cardBorderHover: 'rgba(255,255,255,0.22)',
textPrimary: 'rgba(255,255,255,0.93)', textSecondary: 'rgba(255,255,255,0.62)',
textMuted: 'rgba(255,255,255,0.38)',
};
const CARD_W=176, CARD_H=164, CARD_PAD=20, PANEL_W=400, HEADER_H=88, AXIS_BOTTOM=110;
// -- SAFE STORAGE (werkt ook in Hologram sandbox) --
const storage = {
_m: {},
get(k){ try{return localStorage.getItem(k)}catch{return this._m[k]||null} },
set(k,v){ try{localStorage.setItem(k,v)}catch{this._m[k]=v} },
remove(k){ try{localStorage.removeItem(k)}catch{delete this._m[k]} }
};
// -- DATA --
const DOSSIERS = [
{
id:'rob-de-wijk', title:'Rob de Wijk', subtitle:'Netwerk & Connecties',
nodes:[
{id:'rdw',name:'Rob de Wijk',type:'Person',role:'Defensie-expert',x:50,y:50,description:'Nederlandse defensie- en veiligheidsexpert, oprichter van het HCSS en hoogleraar aan de Universiteit Leiden.'},
{id:'hcss',name:'HCSS',type:'Org',role:'Think Tank',x:25,y:30,description:'The Hague Centre for Strategic Studies -- een invloedrijke geopolitieke denktank in Den Haag, opgericht in 2007.'},
{id:'leiden',name:'Universiteit Leiden',type:'Org',role:'Academisch',x:75,y:30,description:'Oudste universiteit van Nederland, waar Rob de Wijk als hoogleraar verbonden is.'},
{id:'navo',name:'NAVO',type:'Org',role:'Militaire Alliantie',x:20,y:70,description:'Noord-Atlantische Verdragsorganisatie -- HCSS en De Wijk hebben aantoonbare banden via onderzoek en advies.'},
{id:'media',name:'Nederlandse Media',type:'Concept',role:'Publieke optredens',x:80,y:70,description:'NOS, RTL, NPO Radio 1 -- regelmatige optredens als defensie-analist.'},
{id:'def',name:'Min. van Defensie',type:'Government',role:'Opdrachtgever',x:50,y:85,description:'Het Ministerie van Defensie Nederland ontvangt beleidsadviezen van HCSS.'},
],
edges:[
{id:'e1',from:'rdw',to:'hcss',label:'Oprichter & Directeur',status:'verified',confidence:95,description:'Rob de Wijk richtte HCSS op in 2007.',sources:[{id:'s1',title:'HCSS Over Ons',publisher:'HCSS.nl',date:'2007-01-01',tier:'A'}]},
{id:'e2',from:'rdw',to:'leiden',label:'Hoogleraar',status:'verified',confidence:90,description:'Verbonden als hoogleraar Internationale Betrekkingen.',sources:[{id:'s2',title:'Staffpagina Leiden',publisher:'Universiteit Leiden',date:'2010-09-01',tier:'A'}]},
{id:'e3',from:'rdw',to:'media',label:'Analyst & Commentator',status:'verified',confidence:85,description:'Frequente media-optredens bij NOS, RTL en andere nationale media.',sources:[{id:'s3',title:'NOS Nieuwsarchief',publisher:'NOS',date:'2022-03-01',tier:'B'}]},
{id:'e4',from:'hcss',to:'navo',label:'Onderzoeksrelatie',status:'contested',confidence:55,description:'HCSS ontvangt (deels) NAVO-gerelateerde onderzoeksfinanciering.',sources:[{id:'s4',title:'HCSS Projectoverzicht',publisher:'HCSS',date:'2021-01-01',tier:'B'}]},
{id:'e5',from:'hcss',to:'def',label:'Beleidsadvies',status:'verified',confidence:70,description:'HCSS levert structurele beleidsadviezen aan het Ministerie van Defensie.',sources:[{id:'s5',title:'Kamerstuk 2021D12345',publisher:'Rijksoverheid',date:'2021-06-01',tier:'A'}]},
{id:'e6',from:'rdw',to:'navo',label:'Adviseur (historisch)',status:'unverified',confidence:35,description:'Mogelijke historische adviesrol -- nog niet onafhankelijk geverifieerd.',sources:[]},
],
},
{
id:'michael-jackson', title:'Michael Jackson', subtitle:'Dossier: Omgeving & Overlijden',
nodes:[
{id:'mj',name:'Michael Jackson',type:'Person',role:'Artiest',x:50,y:50,description:'King of Pop (1958?2009). Wereldberoemde artiest wiens overlijden op 25 juni 2009 wereldwijd schok teweegbracht.'},
{id:'sony',name:'Sony Music',type:'Org',role:'Platenmaatschappij',x:25,y:25,description:'Langdurige zakelijke relatie gevolgd door juridische conflicten over rechten en controle.'},
{id:'neverland',name:'Neverland Ranch',type:'Concept',role:'Privebezit',x:75,y:25,description:'Iconische ranch in Californie -- symbool van Jacksons wereld.'},
{id:'beatles',name:'Beatles Catalogus',type:'Concept',role:'Muziekrechten',x:20,y:70,description:'ATV Music Publishing -- Jackson kocht de Beatles-rechten in 1985 voor $47,5 miljoen.'},
{id:'murray',name:'Conrad Murray',type:'Person',role:'Persoonlijk arts',x:80,y:70,description:'Arts die Propofol toediende de nacht van Jacksons overlijden. Veroordeeld in 2011.'},
{id:'aeg',name:'AEG Live',type:'Org',role:'Concertpromotor',x:50,y:85,description:'Organisator van de "This Is It" concerttour.'},
],
edges:[
{id:'e1',from:'mj',to:'sony',label:'Artiest -- Conflict',status:'verified',confidence:90,description:'Decennialange zakelijke relatie die uitmondde in publieke conflicten.',sources:[{id:'s1',title:'Sony/MJ History',publisher:'Rolling Stone',date:'2003-07-01',tier:'B'}]},
{id:'e2',from:'mj',to:'neverland',label:'Eigenaar',status:'verified',confidence:95,description:'Jackson kocht Neverland in 1988. Raakte het kwijt in 2008.',sources:[{id:'s2',title:'County Records',publisher:'Santa Barbara County',date:'1988-01-01',tier:'A'}]},
{id:'e3',from:'mj',to:'beatles',label:'Eigenaar rechten',status:'verified',confidence:88,description:'Aankoop van ATV Music Publishing in 1985 voor $47,5 miljoen.',sources:[{id:'s3',title:'ATV Acquisition Deal',publisher:'New York Times',date:'1985-08-10',tier:'A'}]},
{id:'e4',from:'mj',to:'murray',label:'Arts-patient',status:'verified',confidence:92,description:'Murray was Jacksons persoonlijke arts en diende Propofol toe als slaapmiddel.',sources:[{id:'s4',title:'Trial Court Documents',publisher:'LA Superior Court',date:'2011-10-03',tier:'A'}]},
{id:'e5',from:'mj',to:'aeg',label:'Tour Contract',status:'verified',confidence:85,description:'Contract voor 50 shows in de O2 Arena -- de "This Is It" tour.',sources:[{id:'s5',title:'AEG v Jackson Estate',publisher:'LA Court',date:'2013-04-01',tier:'A'}]},
{id:'e6',from:'murray',to:'aeg',label:'Betaald door AEG?',status:'contested',confidence:60,description:'Centrale vraag in de civiele zaak: wie had controle over Murray?',sources:[{id:'s6',title:'Getuigenverklaring Dr. Murray',publisher:'Court Records',date:'2013-05-01',tier:'B'}]},
],
},
];
// -- UTILS --
function clamp(n,a,b){return Math.max(a,Math.min(b,n))}
function lerp(a,b,t){return a+(b-a)*t}
function initials(name){const p=name.split(' ').filter(Boolean);return((p[0]?.[0]??'')+(p[1]?.[0]??'')).toUpperCase()||'??'}
function slugify(s){return s.toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/(^-|-$)/g,'')}
function getEdgeColor(status,confidence,alpha=1){
const base={verified:[34,197,94],contested:[245,158,11],unverified:[239,68,68]}[status];
const t=clamp(confidence/100,0,1),fog=80;
return `rgba(${Math.round(lerp(fog,base[0],t))},${Math.round(lerp(fog,base[1],t))},${Math.round(lerp(fog,base[2],t))},${clamp(alpha*(0.35+t*0.65),0,1)})`;
}
function getEdgeWidth(c){return 1.8+(c/100)*2.8}
function getStatusStyle(s){return{verified:'rgba(34,197,94,0.12)',contested:'rgba(245,158,11,0.12)',unverified:'rgba(239,68,68,0.12)'}[s]}
function getStatusBorder(s){return{verified:'rgba(34,197,94,0.4)',contested:'rgba(245,158,11,0.4)',unverified:'rgba(239,68,68,0.4)'}[s]}
function getStatusLabel(s){return{verified:'Geverifieerd',contested:'Betwist',unverified:'Niet geverifieerd'}[s]}
function getStatusText(s){return{verified:'rgba(34,197,94,0.9)',contested:'rgba(245,158,11,0.9)',unverified:'rgba(239,68,68,0.9)'}[s]}
function getTierBg(t){return{A:'rgba(34,197,94,0.12)',B:'rgba(59,130,246,0.12)',C:'rgba(245,158,11,0.12)',D:'rgba(239,68,68,0.12)'}[t]||'rgba(255,255,255,0.05)'}
function getTierBorder(t){return{A:'rgba(34,197,94,0.4)',B:'rgba(59,130,246,0.4)',C:'rgba(245,158,11,0.4)',D:'rgba(239,68,68,0.4)'}[t]||'rgba(255,255,255,0.1)'}
function getTierText(t){return{A:'rgba(34,197,94,0.9)',B:'rgba(59,130,246,0.9)',C:'rgba(245,158,11,0.9)',D:'rgba(239,68,68,0.9)'}[t]||'rgba(255,255,255,0.5)'}
function findFreeSpot(cx,cy,maxW,maxH,existing){
const phi=2.399963229728653;
for(let i=0;i<80;i++){
const r=90+i*20,angle=i*phi;
const x=clamp(cx+Math.cos(angle)*r,24,maxW-CARD_W-24);
const y=clamp(cy+Math.sin(angle)*r,110,maxH-CARD_H-24);
if(!existing.some(e=>Math.abs(e.x-x)<CARD_W+CARD_PAD&&Math.abs(e.y-y)<CARD_H+CARD_PAD)) return {x,y};
}
return {x:cx+existing.length*22,y:cy+existing.length*16};
}
// -- CRYPTO --
async function generateKeypair(){
const key=await window.crypto.subtle.generateKey({name:'ECDSA',namedCurve:'P-256'},true,['sign','verify']);
const privRaw=await window.crypto.subtle.exportKey('pkcs8',key.privateKey);
const pubRaw=await window.crypto.subtle.exportKey('raw',key.publicKey);
const toHex=b=>Array.from(new Uint8Array(b)).map(x=>x.toString(16).padStart(2,'0')).join('');
return{privHex:toHex(privRaw),pubHex:toHex(pubRaw)};
}
async function signContent(privHex,content){
try{
const privBytes=new Uint8Array(privHex.match(/.{2}/g).map(h=>parseInt(h,16)));
const key=await window.crypto.subtle.importKey('pkcs8',privBytes,{name:'ECDSA',namedCurve:'P-256'},false,['sign']);
const sig=await window.crypto.subtle.sign({name:'ECDSA',hash:'SHA-256'},key,new TextEncoder().encode(content));
return Array.from(new Uint8Array(sig)).map(b=>b.toString(16).padStart(2,'0')).join('');
}catch{return ''}
}
function shortPub(pub){return pub.slice(0,6)+'...'+pub.slice(-4)}
// Membership
const DEMO_CODES={'SUP-DEMO-2026':{tier:'supporter',daysValid:365},'INV-DEMO-2026':{tier:'investigator',daysValid:365},'RED-DEMO-2026':{tier:'redactie',daysValid:365}};
async function hashCode(code){const buf=await window.crypto.subtle.digest('SHA-256',new TextEncoder().encode(code.toUpperCase().trim()));return Array.from(new Uint8Array(buf)).map(b=>b.toString(16).padStart(2,'0')).join('')}
async function validateActivationCode(code){const n=code.toUpperCase().trim();const e=DEMO_CODES[n];if(!e)return null;const codeHash=await hashCode(n);return{tier:e.tier,validUntil:Date.now()+e.daysValid*86400000,activatedAt:Date.now(),codeHash}}
function isMembershipValid(proof){return!!proof&&proof.validUntil>Date.now()}
const TIER_COLORS={supporter:{bg:'rgba(59,130,246,0.12)',border:'rgba(59,130,246,0.35)',text:'#93c5fd'},investigator:{bg:'rgba(224,123,57,0.12)',border:'rgba(224,123,57,0.40)',text:'#fdba74'},redactie:{bg:'rgba(167,139,250,0.12)',border:'rgba(167,139,250,0.40)',text:'#c4b5fd'}};
const TIER_LABELS={supporter:'Supporter',investigator:'Investigator',redactie:'Redactie'};
// -- SVG ICONS (subset via lucide globals) --
function Icon({name, size=16, color='currentColor', ...rest}){
const icons={
search:'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm5-5 4 4',
x:'M18 6 6 18M6 6l12 12',
'rotate-ccw':'M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8',
briefcase:'M20 7H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2',
film:'M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z',
users:'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8',
shield:'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z',
zap:'M13 2 3 14h9l-1 8 10-12h-9l1-8z',
send:'M22 2 11 13M22 2 15 22 11 13 2 9l20-7z',
'file-text':'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M16 13H8M16 17H8M10 9H8',
award:'M12 15a7 7 0 1 0 0-14 7 7 0 0 0 0 14zM8.21 13.89 7 23l5-3 5 3-1.21-9.12',
activity:'M22 12h-4l-3 9L9 3l-3 9H2',
'bar-chart-2':'M18 20V10M12 20V4M6 20v-6',
eye:'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 12a3 3 0 1 0 0-6 3 3 0 0 0 0 6',
lock:'M19 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2zM7 11V7a5 5 0 0 1 10 0v4',
plus:'M12 5v14M5 12h14',
'chevron-right':'M9 18l6-6-6-6',
'chevron-down':'M6 9l6 6 6-6',
'more-horizontal':'M3 12h.01M12 12h.01M21 12h.01',
paperclip:'M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48',
clock:'M12 2a10 10 0 1 0 0 20A10 10 0 0 0 12 2zM12 6v6l4 2',
'check-circle':'M22 11.08V12a10 10 0 1 1-5.93-9.14M22 4 12 14.01l-3-3',
'arrow-left':'M19 12H5M12 19l-7-7 7-7',
list:'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01',
'play-circle':'M12 2a10 10 0 1 0 0 20A10 10 0 0 0 12 2zM10 8l6 4-6 4V8z',
'alert-triangle':'M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0zM12 9v4M12 17h.01',
};
const d=icons[name];
if(!d) return null;
return h('svg',{xmlns:'http://www.w3.org/2000/svg',width:size,height:size,viewBox:'0 0 24 24',fill:'none',stroke:color,strokeWidth:1.8,strokeLinecap:'round',strokeLinejoin:'round',...rest},
d.split('M').filter(Boolean).map((seg,i)=>h('path',{key:i,d:'M'+seg}))
);
}
// -- BACKGROUND --
function MovingAtomsBG({w,h}){
const [pts,setPts]=useState([]);
const ref=useRef([]);
const raf=useRef(null);
useEffect(()=>{
if(!w||!h)return;
const seed=Array.from({length:14},(_,i)=>({x:(((i*151)%997)/997)*w,y:(((i*241)%997)/997)*h,vx:(0.07+((i*7%10)/130))*(i%2?1:-1),vy:(0.055+((i*11%10)/145))*(i%3?1:-1),r:0.8+((i*5%10)/15)}));
ref.current=seed;setPts(seed);
let last=performance.now();
const tick=t=>{
const dt=Math.min(34,t-last);last=t;
const next=ref.current.map(p=>{let{x,y,vx,vy}=p;x+=vx*dt*0.055;y+=vy*dt*0.055;if(x<0||x>w)vx=-vx;if(y<0||y>h)vy=-vy;return{...p,x:clamp(x,0,w),y:clamp(y,0,h),vx,vy}});
ref.current=next;
if(Math.floor(t/50)%2===0)setPts(next);
raf.current=requestAnimationFrame(tick);
};
raf.current=requestAnimationFrame(tick);
return()=>{if(raf.current)cancelAnimationFrame(raf.current)};
},[w,h]);
const lines=useMemo(()=>{
const out=[];
for(let i=0;i<pts.length;i++)for(let j=i+1;j<pts.length;j++){const d=Math.hypot(pts[i].x-pts[j].x,pts[i].y-pts[j].y);if(d<310)out.push({x1:pts[i].x,y1:pts[i].y,x2:pts[j].x,y2:pts[j].y,o:clamp(0.11-d/2900,0.02,0.09)})}
return out;
},[pts]);
return h('svg',{width:w,height:h,style:{position:'absolute',inset:0,pointerEvents:'none'},'aria-hidden':true},
h('defs',null,
h('radialGradient',{id:'nb1',cx:'32%',cy:'38%',r:'60%'},h('stop',{offset:'0%',stopColor:'rgba(59,130,246,0.20)'}),h('stop',{offset:'100%',stopColor:'transparent'})),
h('radialGradient',{id:'nb2',cx:'72%',cy:'62%',r:'55%'},h('stop',{offset:'0%',stopColor:'rgba(245,158,11,0.14)'}),h('stop',{offset:'100%',stopColor:'transparent'})),
),
h('rect',{width:w,height:h,fill:'url(#nb1)'}),h('rect',{width:w,height:h,fill:'url(#nb2)'}),
lines.map((l,i)=>h('line',{key:i,x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,stroke:'rgba(255,255,255,0.6)',strokeOpacity:l.o,strokeWidth:1})),
pts.map((p,i)=>h('circle',{key:i,cx:p.x,cy:p.y,r:p.r,fill:'white',opacity:0.12}))
);
}
// -- PORTRAIT --
function SmartPortrait({name,image}){
const [err,setErr]=useState(false);
const src=image||`/portraits/${slugify(name)}.jpg`;
if(err) return h('div',{style:{display:'flex',height:'100%',width:'100%',alignItems:'center',justifyContent:'center',background:'linear-gradient(135deg,#1e2a3a,#0f1a2e)'}},
h('span',{style:{fontSize:18,fontWeight:700,color:'rgba(255,255,255,0.5)',fontFamily:'Syne,sans-serif'}},...[initials(name)])
);
return h('img',{src,alt:name,style:{height:'100%',width:'100%',objectFit:'cover',filter:'grayscale(1)',transition:'filter 0.5s'},onError:()=>setErr(true),loading:'lazy',draggable:false,onMouseEnter:e=>e.target.style.filter='grayscale(0)',onMouseLeave:e=>e.target.style.filter='grayscale(1)'});
}
// -- ENTITY CARD --
function EntityCard({node,isSelected,isCentral,onSelect,onExpand,onAddConnection,onRemove}){
const [hov,setHov]=useState(false);
const cardBg=isSelected?'rgba(224,123,57,0.10)':hov?UI.cardBgHover:UI.cardBg;
const cardBorder=isSelected?'rgba(224,123,57,0.40)':hov?UI.cardBorderHover:UI.cardBorder;
return h('div',{style:{position:'absolute',left:node.x,top:node.y,width:CARD_W,userSelect:'none',zIndex:isSelected?30:10}},'data-node','true',
h('div',{'data-node':'true',style:{width:CARD_W,height:CARD_H,borderRadius:10,overflow:'hidden',border:`1px solid ${cardBorder}`,background:cardBg,cursor:'pointer',transition:'border-color 0.2s,background 0.2s',position:'relative'},
*/ |
| SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "js1.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "199b96d2879c9f1857ed6163bb31b8e3c029faf45eb4c537cc8cb6b535777710")
37 STORE("fileCheckS", "1dd421b641d2fee44954fcde65c3b8cea0ec4fe5ed8bdc9a2a922f308963521f")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
const { useState, useEffect, useRef, useMemo, useCallback, createElement: h } = React;
// -- HOLOGRAM ADAPTER --
// Detecteer of we in Hologram/TELA draaien; gebruik telaHost API indien beschikbaar
const HOLOGRAM = typeof window !== 'undefined' && typeof window.telaHost !== 'undefined';
const UI = {
bgTop: '#0a1628', bgBot: '#040d1a',
orange: '#e07b39', orangeDim: 'rgba(224,123,57,0.20)',
blue: '#3B82F6', panelBg: 'rgba(4,7,21,0.96)',
cardBg: 'rgba(255,255,255,0.055)', cardBgHover: 'rgba(255,255,255,0.09)',
cardBorder: 'rgba(255,255,255,0.11)', cardBorderHover: 'rgba(255,255,255,0.22)',
textPrimary: 'rgba(255,255,255,0.93)', textSecondary: 'rgba(255,255,255,0.62)',
textMuted: 'rgba(255,255,255,0.38)',
};
const CARD_W=176, CARD_H=164, CARD_PAD=20, PANEL_W=400, HEADER_H=88, AXIS_BOTTOM=110;
// -- SAFE STORAGE (werkt ook in Hologram sandbox) --
const storage = {
_m: {},
get(k){ try{return localStorage.getItem(k)}catch{return this._m[k]||null} },
set(k,v){ try{localStorage.setItem(k,v)}catch{this._m[k]=v} },
remove(k){ try{localStorage.removeItem(k)}catch{delete this._m[k]} }
};
// -- DATA --
const DOSSIERS = [
{
id:'rob-de-wijk', title:'Rob de Wijk', subtitle:'Netwerk & Connecties',
nodes:[
{id:'rdw',name:'Rob de Wijk',type:'Person',role:'Defensie-expert',x:50,y:50,description:'Nederlandse defensie- en veiligheidsexpert, oprichter van het HCSS en hoogleraar aan de Universiteit Leiden.'},
{id:'hcss',name:'HCSS',type:'Org',role:'Think Tank',x:25,y:30,description:'The Hague Centre for Strategic Studies -- een invloedrijke geopolitieke denktank in Den Haag, opgericht in 2007.'},
{id:'leiden',name:'Universiteit Leiden',type:'Org',role:'Academisch',x:75,y:30,description:'Oudste universiteit van Nederland, waar Rob de Wijk als hoogleraar verbonden is.'},
{id:'navo',name:'NAVO',type:'Org',role:'Militaire Alliantie',x:20,y:70,description:'Noord-Atlantische Verdragsorganisatie -- HCSS en De Wijk hebben aantoonbare banden via onderzoek en advies.'},
{id:'media',name:'Nederlandse Media',type:'Concept',role:'Publieke optredens',x:80,y:70,description:'NOS, RTL, NPO Radio 1 -- regelmatige optredens als defensie-analist.'},
{id:'def',name:'Min. van Defensie',type:'Government',role:'Opdrachtgever',x:50,y:85,description:'Het Ministerie van Defensie Nederland ontvangt beleidsadviezen van HCSS.'},
],
edges:[
{id:'e1',from:'rdw',to:'hcss',label:'Oprichter & Directeur',status:'verified',confidence:95,description:'Rob de Wijk richtte HCSS op in 2007.',sources:[{id:'s1',title:'HCSS Over Ons',publisher:'HCSS.nl',date:'2007-01-01',tier:'A'}]},
{id:'e2',from:'rdw',to:'leiden',label:'Hoogleraar',status:'verified',confidence:90,description:'Verbonden als hoogleraar Internationale Betrekkingen.',sources:[{id:'s2',title:'Staffpagina Leiden',publisher:'Universiteit Leiden',date:'2010-09-01',tier:'A'}]},
{id:'e3',from:'rdw',to:'media',label:'Analyst & Commentator',status:'verified',confidence:85,description:'Frequente media-optredens bij NOS, RTL en andere nationale media.',sources:[{id:'s3',title:'NOS Nieuwsarchief',publisher:'NOS',date:'2022-03-01',tier:'B'}]},
{id:'e4',from:'hcss',to:'navo',label:'Onderzoeksrelatie',status:'contested',confidence:55,description:'HCSS ontvangt (deels) NAVO-gerelateerde onderzoeksfinanciering.',sources:[{id:'s4',title:'HCSS Projectoverzicht',publisher:'HCSS',date:'2021-01-01',tier:'B'}]},
{id:'e5',from:'hcss',to:'def',label:'Beleidsadvies',status:'verified',confidence:70,description:'HCSS levert structurele beleidsadviezen aan het Ministerie van Defensie.',sources:[{id:'s5',title:'Kamerstuk 2021D12345',publisher:'Rijksoverheid',date:'2021-06-01',tier:'A'}]},
{id:'e6',from:'rdw',to:'navo',label:'Adviseur (historisch)',status:'unverified',confidence:35,description:'Mogelijke historische adviesrol -- nog niet onafhankelijk geverifieerd.',sources:[]},
],
},
{
id:'michael-jackson', title:'Michael Jackson', subtitle:'Dossier: Omgeving & Overlijden',
nodes:[
{id:'mj',name:'Michael Jackson',type:'Person',role:'Artiest',x:50,y:50,description:'King of Pop (1958?2009). Wereldberoemde artiest wiens overlijden op 25 juni 2009 wereldwijd schok teweegbracht.'},
{id:'sony',name:'Sony Music',type:'Org',role:'Platenmaatschappij',x:25,y:25,description:'Langdurige zakelijke relatie gevolgd door juridische conflicten over rechten en controle.'},
{id:'neverland',name:'Neverland Ranch',type:'Concept',role:'Privebezit',x:75,y:25,description:'Iconische ranch in Californie -- symbool van Jacksons wereld.'},
{id:'beatles',name:'Beatles Catalogus',type:'Concept',role:'Muziekrechten',x:20,y:70,description:'ATV Music Publishing -- Jackson kocht de Beatles-rechten in 1985 voor $47,5 miljoen.'},
{id:'murray',name:'Conrad Murray',type:'Person',role:'Persoonlijk arts',x:80,y:70,description:'Arts die Propofol toediende de nacht van Jacksons overlijden. Veroordeeld in 2011.'},
{id:'aeg',name:'AEG Live',type:'Org',role:'Concertpromotor',x:50,y:85,description:'Organisator van de "This Is It" concerttour.'},
],
edges:[
{id:'e1',from:'mj',to:'sony',label:'Artiest -- Conflict',status:'verified',confidence:90,description:'Decennialange zakelijke relatie die uitmondde in publieke conflicten.',sources:[{id:'s1',title:'Sony/MJ History',publisher:'Rolling Stone',date:'2003-07-01',tier:'B'}]},
{id:'e2',from:'mj',to:'neverland',label:'Eigenaar',status:'verified',confidence:95,description:'Jackson kocht Neverland in 1988. Raakte het kwijt in 2008.',sources:[{id:'s2',title:'County Records',publisher:'Santa Barbara County',date:'1988-01-01',tier:'A'}]},
{id:'e3',from:'mj',to:'beatles',label:'Eigenaar rechten',status:'verified',confidence:88,description:'Aankoop van ATV Music Publishing in 1985 voor $47,5 miljoen.',sources:[{id:'s3',title:'ATV Acquisition Deal',publisher:'New York Times',date:'1985-08-10',tier:'A'}]},
{id:'e4',from:'mj',to:'murray',label:'Arts-patient',status:'verified',confidence:92,description:'Murray was Jacksons persoonlijke arts en diende Propofol toe als slaapmiddel.',sources:[{id:'s4',title:'Trial Court Documents',publisher:'LA Superior Court',date:'2011-10-03',tier:'A'}]},
{id:'e5',from:'mj',to:'aeg',label:'Tour Contract',status:'verified',confidence:85,description:'Contract voor 50 shows in de O2 Arena -- de "This Is It" tour.',sources:[{id:'s5',title:'AEG v Jackson Estate',publisher:'LA Court',date:'2013-04-01',tier:'A'}]},
{id:'e6',from:'murray',to:'aeg',label:'Betaald door AEG?',status:'contested',confidence:60,description:'Centrale vraag in de civiele zaak: wie had controle over Murray?',sources:[{id:'s6',title:'Getuigenverklaring Dr. Murray',publisher:'Court Records',date:'2013-05-01',tier:'B'}]},
],
},
];
// -- UTILS --
function clamp(n,a,b){return Math.max(a,Math.min(b,n))}
function lerp(a,b,t){return a+(b-a)*t}
function initials(name){const p=name.split(' ').filter(Boolean);return((p[0]?.[0]??'')+(p[1]?.[0]??'')).toUpperCase()||'??'}
function slugify(s){return s.toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/(^-|-$)/g,'')}
function getEdgeColor(status,confidence,alpha=1){
const base={verified:[34,197,94],contested:[245,158,11],unverified:[239,68,68]}[status];
const t=clamp(confidence/100,0,1),fog=80;
return `rgba(${Math.round(lerp(fog,base[0],t))},${Math.round(lerp(fog,base[1],t))},${Math.round(lerp(fog,base[2],t))},${clamp(alpha*(0.35+t*0.65),0,1)})`;
}
function getEdgeWidth(c){return 1.8+(c/100)*2.8}
function getStatusStyle(s){return{verified:'rgba(34,197,94,0.12)',contested:'rgba(245,158,11,0.12)',unverified:'rgba(239,68,68,0.12)'}[s]}
function getStatusBorder(s){return{verified:'rgba(34,197,94,0.4)',contested:'rgba(245,158,11,0.4)',unverified:'rgba(239,68,68,0.4)'}[s]}
function getStatusLabel(s){return{verified:'Geverifieerd',contested:'Betwist',unverified:'Niet geverifieerd'}[s]}
function getStatusText(s){return{verified:'rgba(34,197,94,0.9)',contested:'rgba(245,158,11,0.9)',unverified:'rgba(239,68,68,0.9)'}[s]}
function getTierBg(t){return{A:'rgba(34,197,94,0.12)',B:'rgba(59,130,246,0.12)',C:'rgba(245,158,11,0.12)',D:'rgba(239,68,68,0.12)'}[t]||'rgba(255,255,255,0.05)'}
function getTierBorder(t){return{A:'rgba(34,197,94,0.4)',B:'rgba(59,130,246,0.4)',C:'rgba(245,158,11,0.4)',D:'rgba(239,68,68,0.4)'}[t]||'rgba(255,255,255,0.1)'}
function getTierText(t){return{A:'rgba(34,197,94,0.9)',B:'rgba(59,130,246,0.9)',C:'rgba(245,158,11,0.9)',D:'rgba(239,68,68,0.9)'}[t]||'rgba(255,255,255,0.5)'}
function findFreeSpot(cx,cy,maxW,maxH,existing){
const phi=2.399963229728653;
for(let i=0;i<80;i++){
const r=90+i*20,angle=i*phi;
const x=clamp(cx+Math.cos(angle)*r,24,maxW-CARD_W-24);
const y=clamp(cy+Math.sin(angle)*r,110,maxH-CARD_H-24);
if(!existing.some(e=>Math.abs(e.x-x)<CARD_W+CARD_PAD&&Math.abs(e.y-y)<CARD_H+CARD_PAD)) return {x,y};
}
return {x:cx+existing.length*22,y:cy+existing.length*16};
}
// -- CRYPTO --
async function generateKeypair(){
const key=await window.crypto.subtle.generateKey({name:'ECDSA',namedCurve:'P-256'},true,['sign','verify']);
const privRaw=await window.crypto.subtle.exportKey('pkcs8',key.privateKey);
const pubRaw=await window.crypto.subtle.exportKey('raw',key.publicKey);
const toHex=b=>Array.from(new Uint8Array(b)).map(x=>x.toString(16).padStart(2,'0')).join('');
return{privHex:toHex(privRaw),pubHex:toHex(pubRaw)};
}
async function signContent(privHex,content){
try{
const privBytes=new Uint8Array(privHex.match(/.{2}/g).map(h=>parseInt(h,16)));
const key=await window.crypto.subtle.importKey('pkcs8',privBytes,{name:'ECDSA',namedCurve:'P-256'},false,['sign']);
const sig=await window.crypto.subtle.sign({name:'ECDSA',hash:'SHA-256'},key,new TextEncoder().encode(content));
return Array.from(new Uint8Array(sig)).map(b=>b.toString(16).padStart(2,'0')).join('');
}catch{return ''}
}
function shortPub(pub){return pub.slice(0,6)+'...'+pub.slice(-4)}
// Membership
const DEMO_CODES={'SUP-DEMO-2026':{tier:'supporter',daysValid:365},'INV-DEMO-2026':{tier:'investigator',daysValid:365},'RED-DEMO-2026':{tier:'redactie',daysValid:365}};
async function hashCode(code){const buf=await window.crypto.subtle.digest('SHA-256',new TextEncoder().encode(code.toUpperCase().trim()));return Array.from(new Uint8Array(buf)).map(b=>b.toString(16).padStart(2,'0')).join('')}
async function validateActivationCode(code){const n=code.toUpperCase().trim();const e=DEMO_CODES[n];if(!e)return null;const codeHash=await hashCode(n);return{tier:e.tier,validUntil:Date.now()+e.daysValid*86400000,activatedAt:Date.now(),codeHash}}
function isMembershipValid(proof){return!!proof&&proof.validUntil>Date.now()}
const TIER_COLORS={supporter:{bg:'rgba(59,130,246,0.12)',border:'rgba(59,130,246,0.35)',text:'#93c5fd'},investigator:{bg:'rgba(224,123,57,0.12)',border:'rgba(224,123,57,0.40)',text:'#fdba74'},redactie:{bg:'rgba(167,139,250,0.12)',border:'rgba(167,139,250,0.40)',text:'#c4b5fd'}};
const TIER_LABELS={supporter:'Supporter',investigator:'Investigator',redactie:'Redactie'};
// -- SVG ICONS (subset via lucide globals) --
function Icon({name, size=16, color='currentColor', ...rest}){
const icons={
search:'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm5-5 4 4',
x:'M18 6 6 18M6 6l12 12',
'rotate-ccw':'M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8',
briefcase:'M20 7H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2',
film:'M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z',
users:'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8',
shield:'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z',
zap:'M13 2 3 14h9l-1 8 10-12h-9l1-8z',
send:'M22 2 11 13M22 2 15 22 11 13 2 9l20-7z',
'file-text':'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M16 13H8M16 17H8M10 9H8',
award:'M12 15a7 7 0 1 0 0-14 7 7 0 0 0 0 14zM8.21 13.89 7 23l5-3 5 3-1.21-9.12',
activity:'M22 12h-4l-3 9L9 3l-3 9H2',
'bar-chart-2':'M18 20V10M12 20V4M6 20v-6',
eye:'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8zM12 12a3 3 0 1 0 0-6 3 3 0 0 0 0 6',
lock:'M19 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2zM7 11V7a5 5 0 0 1 10 0v4',
plus:'M12 5v14M5 12h14',
'chevron-right':'M9 18l6-6-6-6',
'chevron-down':'M6 9l6 6 6-6',
'more-horizontal':'M3 12h.01M12 12h.01M21 12h.01',
paperclip:'M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48',
clock:'M12 2a10 10 0 1 0 0 20A10 10 0 0 0 12 2zM12 6v6l4 2',
'check-circle':'M22 11.08V12a10 10 0 1 1-5.93-9.14M22 4 12 14.01l-3-3',
'arrow-left':'M19 12H5M12 19l-7-7 7-7',
list:'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01',
'play-circle':'M12 2a10 10 0 1 0 0 20A10 10 0 0 0 12 2zM10 8l6 4-6 4V8z',
'alert-triangle':'M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0zM12 9v4M12 17h.01',
};
const d=icons[name];
if(!d) return null;
return h('svg',{xmlns:'http://www.w3.org/2000/svg',width:size,height:size,viewBox:'0 0 24 24',fill:'none',stroke:color,strokeWidth:1.8,strokeLinecap:'round',strokeLinejoin:'round',...rest},
d.split('M').filter(Boolean).map((seg,i)=>h('path',{key:i,d:'M'+seg}))
);
}
// -- BACKGROUND --
function MovingAtomsBG({w,h}){
const [pts,setPts]=useState([]);
const ref=useRef([]);
const raf=useRef(null);
useEffect(()=>{
if(!w||!h)return;
const seed=Array.from({length:14},(_,i)=>({x:(((i*151)%997)/997)*w,y:(((i*241)%997)/997)*h,vx:(0.07+((i*7%10)/130))*(i%2?1:-1),vy:(0.055+((i*11%10)/145))*(i%3?1:-1),r:0.8+((i*5%10)/15)}));
ref.current=seed;setPts(seed);
let last=performance.now();
const tick=t=>{
const dt=Math.min(34,t-last);last=t;
const next=ref.current.map(p=>{let{x,y,vx,vy}=p;x+=vx*dt*0.055;y+=vy*dt*0.055;if(x<0||x>w)vx=-vx;if(y<0||y>h)vy=-vy;return{...p,x:clamp(x,0,w),y:clamp(y,0,h),vx,vy}});
ref.current=next;
if(Math.floor(t/50)%2===0)setPts(next);
raf.current=requestAnimationFrame(tick);
};
raf.current=requestAnimationFrame(tick);
return()=>{if(raf.current)cancelAnimationFrame(raf.current)};
},[w,h]);
const lines=useMemo(()=>{
const out=[];
for(let i=0;i<pts.length;i++)for(let j=i+1;j<pts.length;j++){const d=Math.hypot(pts[i].x-pts[j].x,pts[i].y-pts[j].y);if(d<310)out.push({x1:pts[i].x,y1:pts[i].y,x2:pts[j].x,y2:pts[j].y,o:clamp(0.11-d/2900,0.02,0.09)})}
return out;
},[pts]);
return h('svg',{width:w,height:h,style:{position:'absolute',inset:0,pointerEvents:'none'},'aria-hidden':true},
h('defs',null,
h('radialGradient',{id:'nb1',cx:'32%',cy:'38%',r:'60%'},h('stop',{offset:'0%',stopColor:'rgba(59,130,246,0.20)'}),h('stop',{offset:'100%',stopColor:'transparent'})),
h('radialGradient',{id:'nb2',cx:'72%',cy:'62%',r:'55%'},h('stop',{offset:'0%',stopColor:'rgba(245,158,11,0.14)'}),h('stop',{offset:'100%',stopColor:'transparent'})),
),
h('rect',{width:w,height:h,fill:'url(#nb1)'}),h('rect',{width:w,height:h,fill:'url(#nb2)'}),
lines.map((l,i)=>h('line',{key:i,x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,stroke:'rgba(255,255,255,0.6)',strokeOpacity:l.o,strokeWidth:1})),
pts.map((p,i)=>h('circle',{key:i,cx:p.x,cy:p.y,r:p.r,fill:'white',opacity:0.12}))
);
}
// -- PORTRAIT --
function SmartPortrait({name,image}){
const [err,setErr]=useState(false);
const src=image||`/portraits/${slugify(name)}.jpg`;
if(err) return h('div',{style:{display:'flex',height:'100%',width:'100%',alignItems:'center',justifyContent:'center',background:'linear-gradient(135deg,#1e2a3a,#0f1a2e)'}},
h('span',{style:{fontSize:18,fontWeight:700,color:'rgba(255,255,255,0.5)',fontFamily:'Syne,sans-serif'}},...[initials(name)])
);
return h('img',{src,alt:name,style:{height:'100%',width:'100%',objectFit:'cover',filter:'grayscale(1)',transition:'filter 0.5s'},onError:()=>setErr(true),loading:'lazy',draggable:false,onMouseEnter:e=>e.target.style.filter='grayscale(0)',onMouseLeave:e=>e.target.style.filter='grayscale(1)'});
}
// -- ENTITY CARD --
function EntityCard({node,isSelected,isCentral,onSelect,onExpand,onAddConnection,onRemove}){
const [hov,setHov]=useState(false);
const cardBg=isSelected?'rgba(224,123,57,0.10)':hov?UI.cardBgHover:UI.cardBg;
const cardBorder=isSelected?'rgba(224,123,57,0.40)':hov?UI.cardBorderHover:UI.cardBorder;
return h('div',{style:{position:'absolute',left:node.x,top:node.y,width:CARD_W,userSelect:'none',zIndex:isSelected?30:10}},'data-node','true',
h('div',{'data-node':'true',style:{width:CARD_W,height:CARD_H,borderRadius:10,overflow:'hidden',border:`1px solid ${cardBorder}`,background:cardBg,cursor:'pointer',transition:'border-color 0.2s,background 0.2s',position:'relative'},
*/'] |