🔒
UniqEnergy · Alchem

Offset-Well Program Builder

Confidential drilling data. Enter the access PIN to continue.

Incorrect PIN
Authorized personnel only. Do not share this link.
Code Interpreter code ↔ plain English · narrates the engine live
what the engine runswhat it means
Open a screen — the Program builder is the richest — and the engine will narrate every step here as it carries out your request.

+Math.round(est.total_cost||0).toLocaleString()+''+ '
'+ '
Casing program
'+_dtbl(p.plan_casing,[['Casing','name'],['OD','od_mm'],['Grade','grade'],['Start','start_md'],['End','end_md']])+'
'+ '
Hole sections · planned loss rate
'+_dtbl(p.plan_sections,[['Section','hole_section'],['Bit mm','bit_size_mm'],['Start','start_md'],['End','end_md'],['Loss/100m','planned_losses_rate_m3_100m']])+'
'+ '
'+ '
'+ '
Product program (top by cost)
'+_dtbl(prods.slice(0,10),[['Product','product'],['$ total','total_cost']])+'
'+ '
Formation tops
'+_dtbl((p.plan_tops||[]).slice(0,18),[['Formation','formation'],['MD','md'],['TVD','tvd'],['Press kPa','pressure_kpa']])+'
'+ '
'+ ''; }).join(''); return '

Donor programs · '+ds.length+' real UES DFP on file for '+fm+'

'+ '

The actual UES drilling-fluid programs behind the donors — casing, hole sections with planned loss rates, product program and formation tops. This is the plan side the template reverse-engineers against (plan-vs-actual).

'+body+'
'; } /* === CrossCheck -> Program Builder handoff (URL hash, no browser storage) === */ function applyHandoff(){ try{ var m=(location.hash||'').match(/ccwell=([^&]+)/); if(!m) return; var json=decodeURIComponent(escape(atob(decodeURIComponent(m[1])))); var w=JSON.parse(json); window.__CCWELL=w; var fms=[]; (typeof RAW!=='undefined'?RAW:[]).forEach(function(x){if(x.formation&&fms.indexOf(x.formation)<0)fms.push(x.formation);}); var base=_fmBase(w.formation); var hit=fms.filter(function(f){var b=_fmBase(f);return b&&(b.indexOf(base)>=0||base.indexOf(b)>=0);})[0]; if(hit) state.pbFormation=hit; state.screen='program'; if(typeof render==='function') render(); var main=document.getElementById('main'); if(main && !document.getElementById('ccBanner')){ var b=document.createElement('div'); b.id='ccBanner'; b.className='cc-banner'; b.innerHTML='FROM CROSSCHECK '+(w.name||w.uwi||'well')+'' +' · '+(w.formation||'?')+(w.field?(' · '+w.field):'') +(w.uwi?(' · '+w.uwi):'') +' target TVD '+(w.tvd||w.target_tvd||'?')+(w.well_type?(' · '+w.well_type):'')+'' +(hit?(' — formation preset to '+hit+'; donors + program generated from analog offsets.'):' — no exact formation match in the fleet; pick the nearest analog above.') +' '; main.insertBefore(b, main.firstChild); } }catch(e){} } function templatePanel(fm,donors){ const rop=envel(donors,'rop_max'), loss=envel(donors,'losses_per_100m_drilled'), cost=envel(donors,'cost_per_m_drilled'), tq=envel(donors,'torque_max'), legs=envel(donors,'n_legs'); const holes=[...new Set(donors.flatMap(w=>(w.hole_sizes_mm||[]).filter(x=>x>10)))].sort((a,b)=>b-a); const r=(l,v,n)=>`
${l}${v}${n?` ${n}`:''}
`; return `

Template starter · ${fm}

Defaults are the donor median; the envelope is the donor min–max — your tuning range per variable.

${r('hole program', holes.join(' → '),'mm')} ${r('expected ROP', `${fmt(rop.md)}`,`m/hr · ${fmt(rop.lo)}–${fmt(rop.hi)} band`)} ${r('expected losses', `${fmt(loss.md,1)}`,`m³/100m · ${fmt(loss.lo,1)}–${fmt(loss.hi,1)}`)} ${r('expected $/m', `$${fmt(cost.md,2)}`,`· $${fmt(cost.lo,2)}–${fmt(cost.hi,2)}`)} ${r('torque ceiling', fmt(tq.hi),'N·m — design BHA/mud below this')} ${r('typical legs', fmt(legs.md),`· ${fmt(legs.lo)}–${fmt(legs.hi)} laterals`)}
provenance · derived from ${donors.length} donor well(s):
${donors.map(w=>'— '+(w.name||'(unnamed)')).join('
')}
`; } function templateCode(fm,donors){ const rop=envel(donors,'rop_max'), loss=envel(donors,'losses_per_100m_drilled'), cost=envel(donors,'cost_per_m_drilled'), tq=envel(donors,'torque_max'); const holes=[...new Set(donors.flatMap(w=>(w.hole_sizes_mm||[]).filter(x=>x>10)))].sort((a,b)=>b-a); const j=`// program_template — generated stub, ${fm}. Wire DFP/EST for product_program[] + variables[] drivers (spec §8). { "template_id": "tmpl_${fm.toLowerCase().replace(/\\s+/g,'_')}_v0", "formation": "${fm}", "derived_from_well_ids": [${donors.map(w=>`"${w.uwi||w.name}"`).join(', ')}], "hole_program_mm": [${holes.join(', ')}], "expected_kpis": { "rop_m_hr": { "target": ${fmt(rop.md)}, "band": [${fmt(rop.lo)}, ${fmt(rop.hi)}] }, "losses_per_100m": { "target": ${fmt(loss.md,1)}, "band": [${fmt(loss.lo,1)}, ${fmt(loss.hi,1)}] }, "cost_per_m": { "target": ${fmt(cost.md,2)}, "band": [${fmt(cost.lo,2)}, ${fmt(cost.hi,2)}] }, "torque_ceiling": ${fmt(tq.hi)} }, "variables": [ { "name":"sweep_volume_m3", "driver":"f(hole_size, losses_seen)", "status":"needs_DFP" }, { "name":"inhibitor_conc", "driver":"f(formation_reactivity)", "status":"needs_DFP" }, { "name":"anti_accretion_pkg","driver":"f(torque_trend)", "status":"needs_DFP" } ], "confidence": "${donors.length>=3?'medium — '+donors.length+' donors':'low — thin sample'}" }`; return `
${j}
`; } /* ================= WELL DETAIL DRAWER + 3D ================= */ let three={}; function openDrawer(i){ const w=RAW[i]; document.getElementById('dw-eyebrow').textContent=(w._c.type)+' · '+(w.field||'—')+' · rig '+(w.rig||'?'); document.getElementById('dw-name').textContent=w.name||'(unnamed — folder label only)'; document.getElementById('dw-uwi').textContent=(w.uwi||'no UWI in header')+' · '+(w.operator||'?')+' · '+(w.contractor||'?'); document.getElementById('dw-body').innerHTML=drawerBody(w); document.getElementById('scrim').classList.add('on'); document.getElementById('drawer').classList.add('on'); setTimeout(()=>initWell3D(w),60); } function closeDrawer(){ document.getElementById('scrim').classList.remove('on'); document.getElementById('drawer').classList.remove('on'); if(three.raf)cancelAnimationFrame(three.raf); three={}; } document.addEventListener('keydown',e=>{if(e.key==='Escape')closeDrawer();}); function drawerBody(w){ const c=w._c; const kv=(l,v,n)=>`
${l}
${v}
${n?`
${n}
`:''}
`; const td = w.td_actual_maxMD!=null ? `
TD = ICP ${fmt(w.icp_deepest_csg)} + drilled ${fmt(w.drilled_metres)}
max-MD = ${fmt(w.td_actual_maxMD)} m · ${w.n_legs} leg${w.n_legs>1?'s':''}${w.n_legs>1?` · multi-leg: drilled (${fmt(w.drilled_metres)} m) > max-MD (${fmt(w.td_actual_maxMD)} m) — normalize by drilled`:''}
` : '
no MD series
'; const acts=(w.activity_summary||[]); const actHTML = acts.length ? acts.slice(0,14).map(a=>{const m=a.match(/^R(\d+):\s*(.*)$/); return `
R${m?m[1]:'?'} ${m?m[2]:a}
`;}).join('') : '
Activity Summary empty in export — numeric flags below are the reliable issue signal (rule 4).
'; return `
drag · pinch/scroll · tap a part
Tap a leg or casing string in the model — its detail shows here.
${kv('ROP max', fmt(w.rop_max)+' m/hr', w._c.speedCostEligible?'speed-eligible':'held out of speed rank')} ${kv('Torque max', fmt(w.torque_max), 'N·m')} ${kv('Losses', fmt(w.losses_per_100m_drilled,1)+' /100m', fmt(w.total_losses_m3,1)+' m³ total · drilled-norm')} ${kv('Cost', w.cost_per_m_drilled?'$'+fmt(w.cost_per_m_drilled,2)+' /m':'–', w.product_cost?'$'+fmt(w.product_cost)+' product':'')} ${kv('Density', w.density_range?w.density_range.join('–'):'–', 'kg/m³ range')} ${kv('Days', fmt(w.days_on_well,1), w.spud?new Date(w.spud).toISOString().slice(0,10)+' spud':'')}

TD math (rule 2)

${td}

QC flags · ${c.flags.length}

${c.flags.length?c.flags.map(f=>`
${f}
`).join(''):'
No flags raised — identity, TD math and ranges look clean.
'}

Activity summary · ${acts.length}/${w.n_reports} reports

${actHTML}
`; } /* ---- three.js schematic multi-leg wellbore ---- */ let cur3DWell=null, cur3DMetric='losses'; function set3DMetric(m,btn){ cur3DMetric=m; btn.parentNode.querySelectorAll('button').forEach(b=>b.classList.remove('on')); btn.classList.add('on'); if(cur3DWell)initWell3D(cur3DWell); } function metricColor(w){ let c; if(cur3DMetric==='losses') c=sev(w.losses_per_100m_drilled,'loss',false); else if(cur3DMetric==='torque') c=sev(w.torque_max,'torque',false); else c=sev(w.rop_max,'rop',true); return c==='s-good'?0x3fcab0 : c==='s-warn'?0xe0a64b : c==='s-bad'?0xe5614d : 0x5d6b82; } function initWell3D(w){ cur3DWell=w; const host=document.getElementById('well3d'); if(!host||!window.THREE)return; if(three.raf)cancelAnimationFrame(three.raf); host.querySelectorAll('canvas').forEach(c=>c.remove()); const readEl=document.getElementById('w3read'); if(readEl){ readEl.classList.remove('sel'); readEl.innerHTML='Tap a leg or casing string in the model — its detail shows here.'; } const W=host.clientWidth, H=host.clientHeight; const scene=new THREE.Scene(); const cam=new THREE.PerspectiveCamera(45,W/H,0.1,5000); const renderer=new THREE.WebGLRenderer({antialias:true,alpha:true}); renderer.setSize(W,H); renderer.setPixelRatio(Math.min(2,devicePixelRatio)); host.appendChild(renderer.domElement); scene.add(new THREE.AmbientLight(0xffffff,0.9)); const dl=new THREE.DirectionalLight(0xffffff,0.5); dl.position.set(1,2,1); scene.add(dl); const td=w.td_actual_maxMD||2000; const SC=120/td; // map TD to ~120 units tall const icpM=(w.icp_deepest_csg||td*0.4); const icp=icpM*SC; const col=metricColor(w); const grp=new THREE.Group(); const picks=[]; // meshes that show floating info on click // depth rings (faint) for(let d=0; d<=td; d+=Math.max(250,Math.round(td/6/100)*100)){ const r=new THREE.Mesh(new THREE.RingGeometry(60,61,48), new THREE.MeshBasicMaterial({color:0x1c2734,side:THREE.DoubleSide,transparent:true,opacity:.28})); r.rotation.x=-Math.PI/2; r.position.y=-d*SC; grp.add(r); } // surface marker const surf=new THREE.Mesh(new THREE.RingGeometry(2,4,32),new THREE.MeshBasicMaterial({color:0x5a8dd6,side:THREE.DoubleSide})); surf.rotation.x=-Math.PI/2; grp.add(surf); // ---- HOLE SCHEMATIC: nested casing strings by hole size, surface (widest) -> production ---- const holes=(w.hole_sizes_mm||[]).filter(x=>x>10).sort((a,b)=>b-a); // big->small const nh=holes.length||1; const shades=[0x3a4658,0x46556a,0x52647c]; // split the cased interval 0..icp into one band per hole size (schematic) for(let i=0;i`${label}`; let html=mk(0,'0 m')+mk(1, fmt(td)+' m'); if(icpM>0 && icpMhole ${holes.length?holes.join(' → ')+' mm':'n/f'}` +`ICP ${fmt(icpM)} m`+`TD ${fmt(td)} m`+`legs ${n}`; // ---- camera + orbit ---- let rotY=0.6, rotX=0.2, dist=230; function applyCam(){ cam.position.set(Math.sin(rotY)*Math.cos(rotX)*dist, Math.sin(rotX)*dist+10, Math.cos(rotY)*Math.cos(rotX)*dist); cam.lookAt(0,-10,0); } applyCam(); const cv=renderer.domElement; cv.style.cursor='grab'; let dragging=false, moved=false, px=0, py=0, auto=true, pinchStart=null; cv.onpointerdown=e=>{dragging=true;moved=false;px=e.clientX;py=e.clientY;auto=false;cv.style.cursor='grabbing';cv.setPointerCapture(e.pointerId);}; cv.onpointermove=e=>{ if(pinchStart||!dragging)return; if(Math.abs(e.clientX-px)+Math.abs(e.clientY-py)>3) moved=true; rotY-=(e.clientX-px)*0.008; rotX=Math.max(-1.2,Math.min(1.3,rotX+(e.clientY-py)*0.006)); px=e.clientX;py=e.clientY; applyCam(); }; cv.onpointerup=e=>{ dragging=false; cv.style.cursor='grab'; if(!moved) pick(e); }; cv.onwheel=e=>{e.preventDefault();dist=Math.max(90,Math.min(420,dist+e.deltaY*0.25));applyCam();}; // touch pinch-to-zoom (tablets have no scroll wheel) cv.addEventListener('touchstart',e=>{ if(e.touches.length===2){ auto=false; dragging=false; pinchStart=Math.hypot(e.touches[0].clientX-e.touches[1].clientX, e.touches[0].clientY-e.touches[1].clientY); } },{passive:false}); cv.addEventListener('touchmove',e=>{ if(e.touches.length===2 && pinchStart){ e.preventDefault(); const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX, e.touches[0].clientY-e.touches[1].clientY); dist=Math.max(90,Math.min(420,dist*(pinchStart/d))); pinchStart=d; applyCam(); } },{passive:false}); cv.addEventListener('touchend',e=>{ if(e.touches.length<2) pinchStart=null; }); // ---- click-to-show: route detail to the staged readout (never over the model) ---- const ray=new THREE.Raycaster(); const m2=new THREE.Vector2(); function pick(e){ const r=cv.getBoundingClientRect(); m2.x=((e.clientX-r.left)/r.width)*2-1; m2.y=-((e.clientY-r.top)/r.height)*2+1; ray.setFromCamera(m2,cam); const hit=ray.intersectObjects(picks,false)[0]; const el=document.getElementById('w3read'); if(!el) return; if(hit){ const u=hit.object.userData; el.classList.add('sel'); el.innerHTML=''+u.title+''+u.lines.map(l=>''+l+'').join('')+''; } else { el.classList.remove('sel'); el.innerHTML='Tap a leg or casing string in the model — its detail shows here.'; } } function loop(){ three.raf=requestAnimationFrame(loop); if(auto){rotY+=0.0035;applyCam();} renderer.render(scene,cam); } loop(); three.renderer=renderer; three.scene=scene; } /* ================= INTERPRETER (code <-> English, live) ================= */ let INTERP={steps:[],speeds:[560,300,140],si:1,timer:null}; function iesc(s){ return String(s).replace(/&/g,'&').replace(//g,'>'); } function interpOpen(){ return document.getElementById('interp').classList.contains('on'); } function toggleInterp(){ const d=document.getElementById('interp'), t=document.getElementById('interp-toggle'); const on=d.classList.toggle('on'); t.textContent = on?'⌗ Code Interpreter ▾':'⌗ Code Interpreter'; if(on) playInterp(); else clearInterval(INTERP.timer); } function cycleSpeed(btn){ INTERP.si=(INTERP.si+1)%3; btn.textContent='speed: '+['slow','med','fast'][INTERP.si]; if(interpOpen()) playInterp(); } function runInterp(steps){ INTERP.steps=steps||[]; if(interpOpen()) playInterp(); } function replayInterp(){ playInterp(); } function playInterp(){ const body=document.getElementById('interp-body'); if(!body) return; const hdr=document.getElementById('icolhead'); if(hdr) hdr.style.display=''; clearInterval(INTERP.timer); body.innerHTML=''; const steps=INTERP.steps||[]; if(!steps.length){ body.innerHTML='
Nothing to narrate on this screen yet — try the Program builder.
'; return; } let i=0; const tick=()=>{ if(i>=steps.length){ clearInterval(INTERP.timer); return; } const s=steps[i++]; const el=document.createElement('div'); el.className='istep k-'+(s.kind||'calc'); el.innerHTML='
'+iesc(s.code)+'
'+s.en+'
'; body.appendChild(el); requestAnimationFrame(()=>el.classList.add('show')); body.scrollTop=body.scrollHeight; }; tick(); INTERP.timer=setInterval(tick, INTERP.speeds[INTERP.si]); } /* trace builders — these narrate the REAL computation with REAL numbers (no guessing) */ function fleetTrace(rows){ const S=[]; S.push({kind:'filter', code:`rows = wells(58).filter(op=${state.op||'·'}, fm=${state.fm||'·'}, rig=${state.rig||'·'}${state.hideNd?', hideNonDrills':''})`, en:`Start from all 58 wells and apply your filters${state.hideNd?'; non-drills hidden':''}.`}); if(state.q) S.push({kind:'filter', code:`.filter(text ~ "${state.q}")`, en:`Keep wells whose name, field or operator contains “${state.q}”.`}); S.push({kind:'calc', code:`.sort(${state.sortKey}, ${state.sortDir<0?'desc':'asc'})`, en:`Sort by ${String(state.sortKey).replace(/_/g,' ')}, ${state.sortDir<0?'highest first':'lowest first'}.`}); S.push({kind:'out', code:`→ ${rows.length} rows · bars = fleet percentile`, en:`Showing ${rows.length} wells. Each KPI bar is coloured against the whole fleet — teal good, amber mid, vermilion problem.`}); return S; } function scenarioTrace(){ return [ {kind:'filter', code:`for each scenario: pool = eligibleWells(scenario)`, en:`Each scenario builds its own pool — speed & cost use drilling wells only; losses & torque keep every well that recorded a value.`}, {kind:'calc', code:`pool.sort(metric); best = slice(0,2); worst = slice(-2)`, en:`Sort the pool by that scenario's KPI, then surface the 2 best and 2 worst, each with its evidence (operator, formation, report count).`}, {kind:'out', code:`cement.metric = losses_per_100m // PROXY, flagged`, en:`Cement readiness has no returns field yet, so it ranks by loss-control as a proxy — labelled as such until the cement data is wired.`}, ]; } function programTrace(fm,pool,ranked,donors){ const rop=envel(donors,'rop_max'), loss=envel(donors,'losses_per_100m_drilled'), cost=envel(donors,'cost_per_m_drilled'), tq=envel(donors,'torque_max'); const holes=[...new Set(donors.flatMap(w=>(w.hole_sizes_mm||[]).filter(x=>x>10)))].sort((a,b)=>b-a); const S=[]; S.push({kind:'filter', code:`pool = wells.filter(w => w.formation==="${fm}" && isDrill(w)) // ${pool.length}`, en:`Collect every drilled offset in ${fm}: ${pool.length} wells. Injection, SWD and re-entries are left out — they can't be speed or cost donors.`}); S.push({kind:'calc', code:`score(w) = mean( pr(rop,↑), pr(loss,↓), pr(torque,↓), pr($/m,↓) )`, en:`Score each well by its percentile rank inside ${fm} across four KPIs, equal weight: faster ROP is good; lower losses, torque and cost are good.`}); donors.slice(0,3).forEach((d,k)=>{ S.push({kind:'pick', code:`donor[${k}] = "${d.name||'(unnamed)'}" // score ${Math.round((d._score||0)*100)}`, en:`${k===0?'Best all-round':'Next'}: ${d.name||'(unnamed)'} — ${fmt(d.rop_max)} m/hr, ${fmt(d.losses_per_100m_drilled,1)} m³/100m losses, $${fmt(d.cost_per_m_drilled,2)}/m.`}); }); S.push({kind:'out', code:`hole_program = [${holes.join(', ')}]`, en:`Inherit the hole sizes the donors actually drilled: ${holes.join(' → ')||'n/a'} mm.`}); S.push({kind:'out', code:`expected.rop = median(donors) = ${fmt(rop.md)} // band ${fmt(rop.lo)}–${fmt(rop.hi)}`, en:`Target ROP = donor median ${fmt(rop.md)} m/hr; the ${fmt(rop.lo)}–${fmt(rop.hi)} spread is your realistic range.`}); S.push({kind:'out', code:`expected.losses = ${fmt(loss.md,1)} // m³ /100m drilled`, en:`Target losses ${fmt(loss.md,1)} m³ per 100 drilled metres — normalized so multi-leg wells aren't unfairly penalized.`}); S.push({kind:'out', code:`expected.cost = $${fmt(cost.md,2)}/m`, en:`Target cost $${fmt(cost.md,2)} per drilled metre (donor median).`}); S.push({kind:'calc', code:`torque_ceiling = max(donor torque) = ${fmt(tq.hi)}`, en:`Design the BHA and mud to stay under ${fmt(tq.hi)} N·m — the worst torque any donor saw.`}); S.push({kind:'calc', code:`variables: sweep_volume_m3 = f(hole_size, losses); inhibitor_conc = f(reactivity)`, en:`Flag the knobs a program engineer tunes, each with an explicit driver. These resolve to numbers once the DFP/EST plan files are wired in.`}); S.push({kind:'out', code:`confidence = "${donors.length>=3?'medium':'low'} — ${donors.length} donors"`, en:`Confidence is ${donors.length>=3?'medium':'low'}, set by how many donor wells backed the template (${donors.length}).`}); return S; } /* ================= CODE INTERPRETER — data command console ================= */ const FIELDS_NUM=['days_on_well','td_actual_maxMD','drilled_metres','n_legs','icp_deepest_csg','n_reports','rop_max','torque_max','total_losses_m3','losses_per_100m_maxMD','losses_per_100m_drilled','product_cost','cost_per_m_drilled','cost_per_m_maxMD']; const FIELDS_STR=['name','operator','contractor','rig','formation','field','license','uwi','well']; const FIELD_ALIAS={rop:'rop_max',cost:'cost_per_m_drilled',losses:'losses_per_100m_drilled',loss:'losses_per_100m_drilled',torque:'torque_max',td:'td_actual_maxMD',depth:'td_actual_maxMD',drilled:'drilled_metres',legs:'n_legs',days:'days_on_well'}; const DATAFILE='./extracted_rows_all58.json'; // swap to extracted_rich_all.json from run_rich.sh on the G drive function rf(f){ if(!f) return null; f=String(f).toLowerCase(); if(FIELD_ALIAS[f]) return FIELD_ALIAS[f]; return FIELDS_NUM.concat(FIELDS_STR).find(x=>x.toLowerCase()===f)||null; } function isNum(f){ return FIELDS_NUM.includes(f); } const OPJS={'=':'===','!=':'!==','>':'>','<':'<','>=':'>=','<=':'<='}; function parseConds(s){ if(!s||!s.trim()) return {conds:[]}; const conds=[]; for(const p of s.split(/\s+and\s+/i)){ const m=p.trim().match(/^([\w$/]+)\s*(>=|<=|!=|=|>|<|contains)\s*(.+)$/i); if(!m) return {err:'could not read condition: "'+p.trim()+'"'}; const f=rf(m[1]); if(!f) return {err:'unknown field: "'+m[1]+'" (try: fields)'}; conds.push({field:f, op:m[2].toLowerCase(), val:m[3].trim().replace(/^["']|["']$/g,'')}); } return {conds}; } function passCond(w,c){ const v=w[c.field]; if(c.op==='contains') return String(v==null?'':v).toLowerCase().includes(String(c.val).toLowerCase()); if(isNum(c.field)){ const a=Number(v),b=Number(c.val); if(isNaN(a))return false; return c.op==='='?a===b:c.op==='!='?a!==b:c.op==='>'?a>b:c.op==='<'?a='?a>=b:a<=b; } const a=String(v==null?'':v).toLowerCase(),b=String(c.val).toLowerCase(); return c.op==='='?a===b:c.op==='!='?a!==b:c.op==='>'?a>b:c.op==='<'?a='?a>=b:a<=b; } function condEN(c){ return c.field+' '+c.op+' '+c.val; } function condJS(c){ if(c.op==='contains') return `String(w.${c.field}||'').toLowerCase().includes(${JSON.stringify(String(c.val).toLowerCase())})`; if(isNum(c.field)) return `Number(w.${c.field}) ${OPJS[c.op]} ${Number(c.val)}`; return `String(w.${c.field}||'').toLowerCase() ${OPJS[c.op]} ${JSON.stringify(String(c.val).toLowerCase())}`; } function filterJS(conds){ return conds.length?`\n .filter(w => ${conds.map(condJS).join(' && ')})`:''; } function median(a){ a=a.filter(x=>x!=null).sort((x,y)=>x-y); return a.length?a[Math.floor(a.length/2)]:null; } function runCmd(force){ const inp=document.getElementById('icmd'); const raw = force || (inp?inp.value:''); if(force && inp) inp.value=''; const hdr=document.getElementById('icolhead'); if(hdr) hdr.style.display='none'; const body=document.getElementById('interp-body'); if(!body) return; clearInterval(INTERP.timer); let html; try { html = execCommand(raw); } catch(e){ html = `
⚠ ${iesc(String(e.message||e))}
`; } body.innerHTML = html; body.scrollTop=0; } function execCommand(raw){ const cmd=(raw||'').trim(); const low=cmd.toLowerCase(); if(!cmd) return helpHTML(); if(low==='help') return helpHTML(); if(low==='fields') return fieldsHTML(); let main=cmd, wherePart=''; const wi=low.search(/\bwhere\b/); if(wi>=0){ main=cmd.slice(0,wi); wherePart=cmd.slice(wi+5); } const pc=parseConds(wherePart); if(pc.err) return qErr(pc.err); const conds=pc.conds; const rows=RAW.filter(w=>conds.every(c=>passCond(w,c))); const t=main.trim().split(/\s+/).filter(Boolean); const verb=(t[0]||'list').toLowerCase(); const whereEN = conds.length?(' where '+conds.map(condEN).join(' and ')):''; // ---- donors ---- if(verb==='donors'){ const fm=main.trim().replace(/^donors\s+/i,'').trim(); if(!fm) return qErr('usage: donors e.g. donors Clearwater'); const pool=RAW.filter(w=>String(w.formation||'').toLowerCase()===fm.toLowerCase() && w._c.speedCostEligible); if(!pool.length) return qErr('no drilled offsets found in formation "'+fm+'"'); pool.forEach(w=>w._score=compositeScore(w,pool)); const r=pool.slice().sort((a,b)=>b._score-a._score).slice(0,5) .map(w=>({name:w.name, score:Math.round(w._score*100), rop_max:w.rop_max, 'loss/100m':w.losses_per_100m_drilled, '$/m':w.cost_per_m_drilled})); return qRender(cmd, `Composite-ranked drilled donors in ${fm} (${pool.length} wells): ROP↑, losses↓, torque↓, $/m↓, equal weight.`, tableHTML(r), donorsCode(fm)); } // ---- count [by ] ---- if(verb==='count'){ const byF = t[1]&&/^by$/i.test(t[1]) ? rf(t[2]) : null; if(t[1]&&/^by$/i.test(t[1]) && !byF) return qErr('unknown field after "by"'); if(byF){ const g={}; rows.forEach(w=>{const k=(w[byF]==null||w[byF]==='')?'(blank)':w[byF]; g[k]=(g[k]||0)+1;}); const r=Object.entries(g).sort((a,b)=>b[1]-a[1]).map(([k,n])=>({[byF]:k, count:n})); return qRender(cmd, `Counted ${rows.length} wells${whereEN}, grouped by ${byF}.`, tableHTML(r), countByCode(byF,conds)); } return qRender(cmd, `Matched ${rows.length} wells${whereEN}.`, `
${rows.length}
`, countCode(conds)); } // ---- avg|median|min|max [by ] ---- if(['avg','mean','median','min','max'].includes(verb)){ const fn = verb==='mean'?'avg':verb; const f=rf(t[1]); if(!f||!isNum(f)) return qErr('usage: '+verb+' [by ] e.g. '+verb+' rop_max by formation'); const byF = t[2]&&/^by$/i.test(t[2]) ? rf(t[3]) : null; const agg=arr=>{ const v=arr.map(w=>w[f]).filter(x=>x!=null); if(!v.length)return null; return fn==='avg'?v.reduce((s,x)=>s+x,0)/v.length : fn==='median'?median(v) : fn==='min'?Math.min(...v):Math.max(...v); }; if(byF){ const g={}; rows.forEach(w=>{const k=(w[byF]==null||w[byF]==='')?'(blank)':w[byF]; (g[k]=g[k]||[]).push(w);}); const r=Object.entries(g).map(([k,a])=>({[byF]:k, [fn+'_'+f]: round(agg(a))})).sort((a,b)=>(b[fn+'_'+f]||0)-(a[fn+'_'+f]||0)); return qRender(cmd, `${fn} of ${f}${whereEN}, grouped by ${byF} (${rows.length} wells).`, tableHTML(r), aggByCode(fn,f,byF,conds)); } const val=agg(rows); return qRender(cmd, `${fn} of ${f} across ${rows.length} wells${whereEN}.`, `
${fmt(val, f.includes('cost')||f.includes('per_100')?2:0)}
`, aggCode(fn,f,conds)); } // ---- top / bottom ---- if(verb==='top'||verb==='bottom'){ const f=rf(t[1]); const n=parseInt(t[2],10)||5; if(!f||!isNum(f)) return qErr('usage: '+verb+' e.g. '+verb+' rop_max 5'); const desc=verb==='top'; const r=rows.slice().filter(w=>w[f]!=null).sort((a,b)=>desc?b[f]-a[f]:a[f]-b[f]).slice(0,n); return qRender(cmd, `${desc?'Highest':'Lowest'} ${n} by ${f}${whereEN} — ${r.length} shown.`, tableHTML(projectRows(r,[f])), sortCode(f,desc,n,conds)); } // ---- sort [asc|desc] ---- if(verb==='sort'){ const f=rf(t[1]); const dir=(t[2]||'desc').toLowerCase()==='asc'?'asc':'desc'; if(!f||!isNum(f)) return qErr('usage: sort [asc|desc]'); const r=rows.slice().filter(w=>w[f]!=null).sort((a,b)=>dir==='desc'?b[f]-a[f]:a[f]-b[f]).slice(0,40); return qRender(cmd, `Sorted ${rows.length} wells${whereEN} by ${f} ${dir} — first ${r.length} shown.`, tableHTML(projectRows(r,[f])), sortCode(f,dir==='desc',40,conds)); } // ---- list (default) ---- const r=rows.slice(0,40); return qRender(cmd, `Listed ${rows.length} wells${whereEN}${rows.length>40?' (first 40 shown)':''}.`, tableHTML(projectRows(r,[])), listCode(conds)); } /* ---- helpers: rendering ---- */ function round(v){ return v==null?null:+v.toFixed(2); } function projectRows(rows, extra){ const cols=[...new Set(['name','operator','formation', ...extra, 'rop_max','cost_per_m_drilled'])].slice(0,6); return rows.map(w=>{ const o={}; cols.forEach(c=>o[c]= Array.isArray(w[c])?w[c].join('/'):w[c]); return o; }); } function tableHTML(rows){ if(!rows||!rows.length) return '
no rows
'; const cols=Object.keys(rows[0]); const head=''+cols.map(c=>`${c}`).join('')+''; const fmtcell=(c,v)=>{ if(v==null) return '–'; if(isNum(c)||/^score$|per_100|^\$\/m$|loss/.test(c)) return fmt(v, (String(c).includes('cost')||String(c).includes('per_100')||c==='$/m'||c==='loss/100m')?2:0); return iesc(String(v)); }; const b=rows.slice(0,60).map(r=>''+cols.map(c=>`${fmtcell(c,r[c])}`).join('')+'').join(''); return `
${head}${b}
`; } function qRender(cmd, narr, resHTML, code){ return `
▸ ${iesc(cmd)}
${narr}
${resHTML}
portable code source run on any computer against the G-drive dataset
${iesc(code)}
`; } function qErr(m){ return `
⚠ ${iesc(m)}
Type help for commands or fields for the data columns.
`; } function copyCode(btn){ const pre=btn.closest('.qblock').querySelector('.qcode'); const txt=pre.textContent; try{ navigator.clipboard.writeText(txt); btn.textContent='copied'; setTimeout(()=>btn.textContent='copy',1200); } catch(e){ const r=document.createRange(); r.selectNode(pre); getSelection().removeAllRanges(); getSelection().addRange(r); btn.textContent='selected'; setTimeout(()=>btn.textContent='copy',1200); } } /* ---- code generators (portable Node, runs against the pipeline dataset) ---- */ const HEAD=`// Offset-well data query — generated by the Code Interpreter\n// Run with Node on any computer that has the G-drive dataset from run_rich.sh\nconst wells = require(${JSON.stringify(DATAFILE)});`; function sortCode(f,desc,n,conds){ return `${HEAD}\nconst rows = wells${filterJS(conds)}\n .filter(w => w.${f} != null)\n .sort((a,b) => ${desc?`b.${f} - a.${f}`:`a.${f} - b.${f}`})\n .slice(0, ${n})\n .map(w => ({ name:w.name, operator:w.operator, formation:w.formation, ${f}:w.${f} }));\nconsole.table(rows);`; } function listCode(conds){ return `${HEAD}\nconst rows = wells${filterJS(conds)}\n .map(w => ({ name:w.name, operator:w.operator, formation:w.formation, rop_max:w.rop_max, cost_per_m_drilled:w.cost_per_m_drilled }));\nconsole.table(rows.slice(0,40));`; } function countCode(conds){ return `${HEAD}\nconst n = wells${filterJS(conds)}.length;\nconsole.log('matched', n, 'wells');`; } function countByCode(byF,conds){ return `${HEAD}\nconst g = {};\nwells${filterJS(conds)}\n .forEach(w => { const k = w.${byF} || '(blank)'; g[k] = (g[k]||0) + 1; });\nconsole.table(Object.entries(g).sort((a,b)=>b[1]-a[1]).map(([k,n]) => ({ ${byF}:k, count:n })));`; } function aggCode(fn,f,conds){ const red= fn==='avg'?`const v=a.map(w=>w.${f}).filter(x=>x!=null); const out=v.reduce((s,x)=>s+x,0)/v.length;` : fn==='median'?`const v=a.map(w=>w.${f}).filter(x=>x!=null).sort((x,y)=>x-y); const out=v[Math.floor(v.length/2)];` : `const v=a.map(w=>w.${f}).filter(x=>x!=null); const out=Math.${fn}(...v);`; return `${HEAD}\nconst a = wells${filterJS(conds)};\n${red}\nconsole.log('${fn} ${f} =', out);`; } function aggByCode(fn,f,byF,conds){ const calc= fn==='avg'?`v.reduce((s,x)=>s+x,0)/v.length` : fn==='median'?`v.sort((x,y)=>x-y)[Math.floor(v.length/2)]` : `Math.${fn}(...v)`; return `${HEAD}\nconst g = {};\nwells${filterJS(conds)}\n .forEach(w => { const k = w.${byF} || '(blank)'; (g[k] = g[k]||[]).push(w.${f}); });\nconst out = Object.entries(g).map(([k,arr]) => { const v=arr.filter(x=>x!=null); return { ${byF}:k, ${fn}_${f}: +(${calc}).toFixed(2) }; });\nconsole.table(out.sort((a,b)=>b.${fn}_${f}-a.${fn}_${f}));`; } function donorsCode(fm){ return `${HEAD}\nconst isDrill = w => { const s=(w.well+' '+(w.name||'')).toLowerCase();\n return !/swd|\\binj\\b|injection|wsw|well kill|well_kill|re-?entry/.test(s) && w.drilled_metres && w.rop_max; };\nconst pool = wells.filter(w => String(w.formation||'').toLowerCase() === ${JSON.stringify(fm.toLowerCase())} && isDrill(w));\nconst pr = (w,f,hi) => { const v=pool.map(x=>x[f]).filter(n=>n!=null).sort((a,b)=>a-b);\n if (w[f]==null || !v.length) return 0.5; const below=v.filter(n=>n ({ name:w.name,\n score: +(((pr(w,'rop_max',1)+pr(w,'losses_per_100m_drilled',0)+pr(w,'torque_max',0)+pr(w,'cost_per_m_drilled',0))/4)*100).toFixed(0),\n rop_max:w.rop_max, loss:w.losses_per_100m_drilled, cost:w.cost_per_m_drilled }))\n .sort((a,b)=>b.score-a.score);\nconsole.table(ranked.slice(0,5));`; } function helpHTML(){ return `
Commands — operate on the ${RAW.length} wells, then hand you runnable code:
 • top <field> <n> · bottom <field> <n> · sort <field> [asc|desc]
 • count [by <field>]
 • avg|median|min|max <field> [by <field>]
 • donors <formation> — composite-ranked template wells
 • list — rows (default)
 • add where <field> <op> <value> [and …] · ops: = != > < >= <= contains

Examples
 top rop_max 5 where formation = Clearwater
 avg cost_per_m_drilled by operator
 count by formation where rop > 200
 donors Waseca

Type fields to list every column. Aliases: rop, cost, losses, torque, td, drilled, legs, days.
`; } function fieldsHTML(){ return `
Numeric (sort/avg/min/max/compare):
 ${FIELDS_NUM.join(', ')}

Text (= != contains):
 ${FIELDS_STR.join(', ')}

Aliases: rop→rop_max, cost→cost_per_m_drilled, losses→losses_per_100m_drilled, torque→torque_max, td→td_actual_maxMD, drilled→drilled_metres, legs→n_legs, days→days_on_well
`; } /* ================= PIN GATE + DATA DECRYPTION ================= */ /* The dataset is obfuscated in-page with a PIN-derived keystream so a plain view-source does not expose confidential drilling data. NOTE: a 4-digit PIN is a light access gate, not strong encryption — pair it with host-level password protection for the live link. */ function _mulberry32(a){ return function(){ a|=0; a=a+0x6D2B79F5|0; let t=Math.imul(a^a>>>15,1|a); t=t+Math.imul(t^t>>>7,61|t)^t; return ((t^t>>>14)>>>0)/4294967296; }; } function _keystream(pin,n){ let h=2166136261; const s='owpb::'+pin+'::salt::v1'; for(let i=0;i>>0; for(let k=0;k<8000;k++){ seed=(Math.imul(seed^0x9E3779B9,2654435761))>>>0; } const rnd=_mulberry32(seed); const out=new Uint8Array(n); for(let i=0;i garbage -> header fails text=text.slice(6); } else { text=node.textContent; } // unencrypted dev build const arr=JSON.parse(text); document.getElementById('pin').classList.add('hide'); bootWithData(arr); return true; }catch(e){ return false; } } let _pinBuf=''; function pinRender(){ const d=document.getElementById('pindots').children; for(let i=0;i=4) return; _pinBuf+=n; pinRender(); document.getElementById('pinmsg').classList.remove('on'); if(_pinBuf.length===4){ setTimeout(()=>{ if(!tryUnlock(_pinBuf)){ const b=document.getElementById('pinbox'); b.classList.add('shake'); document.getElementById('pinmsg').classList.add('on'); setTimeout(()=>b.classList.remove('shake'),360); _pinBuf=''; pinRender(); } },120); } } function pinDel(){ _pinBuf=_pinBuf.slice(0,-1); pinRender(); } function pinClear(){ _pinBuf=''; pinRender(); document.getElementById('pinmsg').classList.remove('on'); } function initPinGate(){ document.addEventListener('keydown',e=>{ if(document.getElementById('pin').classList.contains('hide')) return; if(/^[0-9]$/.test(e.key)) pinKey(e.key); else if(e.key==='Backspace') pinDel(); else if(e.key==='Escape') pinClear(); }); // dev convenience: if the data was never encrypted, a wrong/any pin still needs entry, but allow direct boot const node=document.getElementById('welldata'); if(node.getAttribute('data-enc')!=='1'){ /* unencrypted build still shows the gate; PIN 1755 expected */ } } /* ================= BOOT ================= */ initPinGate();