PageSourceSearch

https://whisperai.com/assets/AdminAnalyticsSearchTraffic-BeqSLwLX.js

js whisperai.com collected 2026-09-24 09:32:35 UTC 19,887 bytes, 1 lines download raw bytes

1import{r as u,j as e}from"./react-vendor-BxUrAMDo.js";import{q as z,j as I,C as R,B as v,I as b,o as J}from"./index-CQAF4vvG.js";import"./scroll-area-NqSjhhDJ.js";import{u as W}from"./AdminAnalyticsDashboard-BcFA6zDA.js";import"./select-CbBqKqra.js";import"./popover-DjgHS5px.js";import{A as Y}from"./AnalyticsPage-B6j55I7K.js";/* empty css                          */import{u as Z,b as V}from"./query-vendor-C8OxFoLA.js";import{T as X,a as ee,b as A,e as k,c as se,d as q}from"./table-CIm0ogev.js";import{T as te,a as ae,b as re}from"./tabs-TEpZzWEk.js";import{C as F}from"./ChartCard-CQDY5E4l.js";import{u as ne}from"./chartTheme-7d0KzAdU.js";import{c as ie}from"./compareOverlay-DrN1hA3q.js";import{T as ce}from"./TimeSeriesChart-CerRyMKA.js";import{E as L}from"./EmptyState-CCePUi3r.js";import{a3 as oe,aZ as M,aJ as B,bb as le}from"./icons-B2ApzMU8.js";import"./ui-vendor-BRGvjLlB.js";import"./types-DKfOy4iX.js";import"./textarea-DeKoTNkm.js";import"./en-US-UPLte4iB.js";import"./format-BoAV63Jo.js";import"./skeleton-CFN5HhQK.js";import"./generateCategoricalChart-DYjO9m1h.js";import"./index-CuAZr8ML.js";import"./Line-CJTYINav.js";import"./CartesianGrid-FE7MTn9S.js";(function(){try{var s=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{};s.SENTRY_RELEASE={id:"76af7de9158b89afec09e7e9dfdae5ea3e5aff85"};var t=new s.Error().stack;t&&(s._sentryDebugIds=s._sentryDebugIds||{},s._sentryDebugIds[t]="6003ad42-51f7-4b22-9a40-9a1bd2d80577",s._sentryDebugIdIdentifier="sentry-dbid-6003ad42-51f7-4b22-9a40-9a1bd2d80577")}catch{}})();const O="admin_analytics_search_traffic_filters",j=["query","pagePath","country","device","channel","sourceMedium","campaign"],de=["query","page","country","device","channel","source_medium","campaign","landing_page","ga4_country","ga4_device"],w={chips:{},querySearch:"",pathSearch:"",touch:"first",activeTab:"search",activeDimension:"query"};function Q(s){if(!s||typeof s!="object")return w;const t=s,a={};for(const r of j){const o=t.chips?.[r];Array.isArray(o)&&(a[r]=[...new Set(o.filter(n=>typeof n=="string"&&n.trim()).map(n=>n.trim()))].slice(0,20))}return{chips:a,querySearch:typeof t.querySearch=="string"?t.querySearch.trim().slice(0,100):"",pathSearch:typeof t.pathSearch=="string"?t.pathSearch.trim().slice(0,100):"",touch:t.touch==="last"?"last":"first",activeTab:["search","traffic","quality"].includes(t.activeTab??"")?t.activeTab:"search",activeDimension:de.includes(t.activeDimension)?t.activeDimension:"query"}}function ue(s){const t=new URLSearchParams(s),a={};for(const r of j)a[r]=t.getAll(r);return Q({chips:a,querySearch:t.get("querySearch")??"",pathSearch:t.get("pathSearch")??"",touch:t.get("touch"),activeTab:t.get("stTab"),activeDimension:t.get("stDimension")})}function he(s,t){const a=new URLSearchParams(t);for(const o of[...j,"querySearch","pathSearch","touch","stTab","stDimension"])a.delete(o);for(const o of j)for(const n of s.chips[o]??[])a.append(o,n);s.querySearch&&a.set("querySearch",s.querySearch),s.pathSearch&&a.set("pathSearch",s.pathSearch),a.set("touch",s.touch),a.set("stTab",s.activeTab),a.set("stDimension",s.activeDimension);const r=a.toString();return r?`?${r}`:""}function me(){try{const s=new URLSearchParams(window.location.search);if(j.some(a=>s.has(a))||["querySearch","pathSearch","touch","stTab","stDimension"].some(a=>s.has(a)))return ue(window.location.search);const t=localStorage.getItem(O);return t?Q(JSON.parse(t)):w}catch{return w}}const U=u.createContext(null);function pe({children:s}){const[t,a]=u.useState(me);u.useEffect(()=>{localStorage.setItem(O,JSON.stringify(t)),window.history.replaceState(null,"",`${window.location.pathname}${he(t,window.location.search)}${window.location.hash}`)},[t]);const r=u.useCallback((i,d)=>{const g=d.trim();g&&a(c=>{const p=c.chips[i]??[];return p.includes(g)||p.length>=20?c:{...c,chips:{...c.chips,[i]:[...p,g]}}})},[]),o=u.useCallback((i,d)=>{a(g=>({...g,chips:{...g.chips,[i]:(g.chips[i]??[]).filter(c=>c!==d)}}))},[]),n=u.useCallback(()=>a(i=>({...i,chips:{}})),[]),h=u.useCallback(i=>a(d=>({...d,querySearch:i.slice(0,100)})),[]),l=u.useCallback(i=>a(d=>({...d,pathSearch:i.slice(0,100)})),[]),m=u.useCallback(i=>a(d=>({...d,touch:i})),[]),f=u.useCallback(i=>a(d=>({...d,activeTab:i})),[]),x=u.useCallback(i=>a(d=>({...d,activeDimension:i})),[]),y=u.useMemo(()=>({...t,addChip:r,removeChip:o,clearChips:n,setQuerySearch:h,setPathSearch:l,setTouch:m,setActiveTab:f,setActiveDimension:x}),[t,r,o,n,h,l,m,f,x]);return e.jsx(U.Provider,{value:y,children:s})}function T(){const s=u.useContext(U);if(!s)throw new Error("useSearchTrafficFilters requires SearchTrafficFiltersProvider");return s}function fe(s){return{query:"Query",pagePath:"Page",country:"Country",device:"Device",channel:"Channel",sourceMedium:"Source / medium",campaign:"Campaign"}[s]}const C="/api/v2/admin/analytics/search-traffic";function K(s){const t=new URLSearchParams;for(const[a,r]of Object.entries(s))if(!(r==null||r===""))for(const o of Array.isArray(r)?r:[r])t.append(a,String(o));return t}function H(){const{buildQueryParams:s}=W(),t=T();return u.useMemo(()=>{const{tier:a,productLine:r,...o}=s(),n={...o,querySearch:t.querySearch||void 0,pathSearch:t.pathSearch||void 0,touch:t.touch};for(const[h,l]of Object.entries(t.chips))l?.length&&(n[h]=l);return n},[s,t.chips,t.querySearch,t.pathSearch,t.touch])}function S(s,t={},a={}){const r=H(),o=u.useMemo(()=>({...r,...t}),[r,t]),n=`${C}/${s}`;return Z({...a,queryKey:[n,o],queryFn:async()=>{const h=K(o).toString(),l=await fetch(`${n}${h?`?${h}`:""}`,{credentials:"include",headers:I()});if(!l.ok)throw new Error(`${l.status}: ${await l.text()||l.statusText}`);return l.json()},retry:(h,l)=>l.message.startsWith("429:")&&h<3})}function D(s,t={}){return V({...t,mutationFn:async a=>{const r=await fetch(`${C}/${s}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...I()},body:JSON.stringify(a)});if(!r.ok)throw new Error(`${r.status}: ${await r.text()||r.statusText}`);return r.json()},onSuccess:(...a)=>{z.invalidateQueries({predicate:r=>typeof r.queryKey[0]=="string"&&r.queryKey[0].startsWith(C)}),t.onSuccess?.(...a)}})}function xe(s,t,a,r){return`${C}/export?${K({...s,dimension:t,sort:a,direction:r,limit:100,format:"csv"})}`}function ge(){const s=S("data-quality"),[t,a]=u.useState("all"),[r,o]=u.useState(""),[n,h]=u.useState(""),l=D("sync-now"),m=D("backfill"),f=r&&n?Math.floor((new Date(`${n}T00:00:00Z`).getTime()-new Date(`${r}T00:00:00Z`).getTime())/864e5)+1:0,x=f<1||f>(s.data?.backfill.maxRangeDays??480),y=l.error??m.error;return e.jsxs(R,{className:"aa-glass-card rounded-2xl p-4","data-testid":"st-data-quality",children:[e.jsx("h2",{className:"text-lg font-semibold",children:"Data quality"}),s.isLoading?e.jsx("div",{className:"mt-3 h-40 animate-pulse rounded bg-muted"}):s.error?e.jsx("p",{className:"mt-3 text-sm text-destructive",children:"Could not load sync status."}):e.jsxs(e.Fragment,{children:[s.data?.serviceAccountEmail?e.jsxs("div",{className:"mt-3 text-sm",children:["Grant source access to"," ",e.jsx("code",{className:"select-all rounded bg-muted px-1",children:s.data.serviceAccountEmail})," ",e.jsx(v,{size:"sm",variant:"ghost",onClick:()=>navigator.clipboard.writeText(s.data?.serviceAccountEmail??""),children:"Copy"})]}):s.data?.serviceAccountReason?e.jsxs("p",{className:"mt-3 text-sm text-muted-foreground",children:["Service-account email unavailable: ",s.data.serviceAccountReason]}):null,e.jsx("div",{className:"mt-3 space-y-3",children:s.data?.sources.map(i=>e.jsxs("section",{children:[e.jsx("h3",{className:"font-medium",children:i.source==="ga4"?"GA4":"Search Console"}),!i.configured&&e.jsxs("p",{className:"text-sm text-amber-700",children:["Not configured: ",i.reason]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:i.lagNotice}),e.jsx("div",{className:"mt-1 overflow-x-auto",children:e.jsxs("table",{className:"w-full text-left text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Report"}),e.jsx("th",{children:"Status"}),e.jsx("th",{children:"Last success"}),e.jsx("th",{children:"Latest data"}),e.jsx("th",{children:"Flags"})]})}),e.jsx("tbody",{children:i.reports.map(d=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{children:d.report}),e.jsx("td",{children:d.lastStatus??"Never run"}),e.jsx("td",{children:d.lastSuccessAt??"—"}),e.jsx("td",{children:d.latestDataDate??"—"}),e.jsxs("td",{children:[d.missingDays.length," missing · ",d.truncatedDays," truncated ·"," ",d.sampledDays," sampled · ",d.thresholdedDays," thresholded",d.lastError&&e.jsx("div",{className:"text-destructive",children:d.lastError})]})]},d.report))})]})})]},i.source))}),e.jsxs("div",{className:"mt-4 space-y-2 border-t pt-3",children:[e.jsxs("label",{className:"block text-sm",children:["Source",e.jsxs("select",{className:"ml-2 roun
1ded border bg-background p-1",value:t,onChange:i=>a(i.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"search_console",children:"Search Console"}),e.jsx("option",{value:"ga4",children:"GA4"})]})]}),e.jsx(v,{size:"sm",disabled:l.isPending,onClick:()=>l.mutate({source:t}),children:"Sync now"}),e.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[e.jsxs("label",{className:"text-xs",htmlFor:"st-backfill-start",children:["Start",e.jsx(b,{id:"st-backfill-start",type:"date",value:r,onChange:i=>o(i.target.value)})]}),e.jsxs("label",{className:"text-xs",htmlFor:"st-backfill-end",children:["End",e.jsx(b,{id:"st-backfill-end",type:"date",value:n,onChange:i=>h(i.target.value)})]}),e.jsx(v,{size:"sm",variant:"outline",disabled:m.isPending||!r||!n||x,onClick:()=>m.mutate({source:t,startDate:r,endDate:n}),children:"Backfill range"})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Maximum backfill range: ",s.data?.backfill.maxRangeDays??480," days.",r&&n&&x?" Choose a valid range within that cap.":""]}),y&&e.jsxs("p",{className:"text-sm text-destructive",children:["Action failed: ",y.message,y.message.startsWith("429:")&&" Please wait for the current request and try again."]})]})]})]})}const E={clicks:"Clicks",impressions:"Impressions",ctr:"CTR",position:"Avg position",sessions:"Sessions",users:"Avg daily users",newUsers:"New users",engagedSessions:"Engaged sessions",keyEvents:"Key events"},G="Average daily active users across the selected window. GA4 users are distinct per day and cannot be summed across days.",ye={clicks:"Clicks",impressions:"Impressions",ctr:"CTR",position:"Avg position",sessions:"Sessions",users:"Avg daily users",newUsers:"New users",engagedSessions:"Engaged sessions",engagementRate:"Engagement rate",keyEvents:"Key events",signups:"Signups"},ve={users:G,signups:"First-party signups whose landing page matches this path in the window"};function N(s,t){return t==null?"—":s==="ctr"||s==="engagementRate"?`${(t*100).toLocaleString(void 0,{maximumFractionDigits:2})}%`:s==="position"||s==="users"?t.toLocaleString(void 0,{maximumFractionDigits:1}):t.toLocaleString(void 0,{maximumFractionDigits:0})}function je({values:s}){const t=s.filter(n=>n!=null);if(t.length<2)return e.jsx("div",{className:"h-5"});const a=Math.min(...t),r=Math.max(...t)-a||1,o=t.map((n,h)=>`${h?"L":"M"}${h*(72/(t.length-1))},${18-(n-a)/r*16}`).join(" ");return e.jsx("svg",{viewBox:"0 0 72 20",className:"h-5 w-[72px] text-primary","aria-hidden":"true",children:e.jsx("path",{d:o,fill:"none",stroke:"currentColor",strokeWidth:"1.5"})})}function Se(){const s=S("kpis"),t=s.data?.kpis??Object.keys(E).map(a=>({key:a,source:["clicks","impressions","ctr","position"].includes(a)?"search_console":"ga4",value:null,previous:null,changePct:null,lowerIsBetter:a==="position",sparkline:[],scoped:!1}));return e.jsx(R,{className:"aa-glass-card rounded-2xl p-4","data-testid":"st-kpis",children:s.error?e.jsx("p",{className:"text-sm text-destructive",children:"Could not load Search & Traffic KPIs."}):e.jsx("div",{className:"grid gap-2 md:grid-cols-3 xl:grid-cols-5",children:t.map(a=>{const r=a.changePct,o=r!=null&&r!==0&&(a.lowerIsBetter?r<0:r>0);return e.jsxs("div",{className:"rounded-lg border bg-muted/20 p-3",children:[e.jsx("div",{className:"text-xs text-muted-foreground",title:a.key==="users"?G:void 0,children:E[a.key]}),e.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:s.isLoading?"…":N(a.key,a.value)}),e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("span",{className:r==null||r===0?"text-muted-foreground":o?"text-emerald-600":"text-rose-600",children:r==null?"—":e.jsxs(e.Fragment,{children:[r>0?e.jsx(M,{className:"inline h-3 w-3"}):r<0?e.jsx(B,{className:"inline h-3 w-3"}):e.jsx(le,{className:"inline h-3 w-3"}),Math.abs(r).toFixed(1),"%"]})}),e.jsx(je,{values:a.sparkline})]})]},a.key)})})})}const _=s=>s.split("�").filter(Boolean).join(" ")||s;function be(){const s=T(),[t,a]=u.useState(s.querySearch),[r,o]=u.useState(s.pathSearch);return u.useEffect(()=>{const n=setTimeout(()=>s.setQuerySearch(t),300);return()=>clearTimeout(n)},[t,s.setQuerySearch]),u.useEffect(()=>{const n=setTimeout(()=>s.setPathSearch(r),300);return()=>clearTimeout(n)},[r,s.setPathSearch]),e.jsxs("div",{className:"aa-glass-card space-y-2 rounded-2xl border-l-[3px] border-l-[#087c73] p-3",children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[Object.entries(s.chips).flatMap(([n,h])=>
1(h??[]).map(l=>{const m=n;return e.jsxs(J,{variant:"secondary","data-testid":`st-chip-${m}-${l}`,children:[fe(m)," = ",_(l),e.jsx("button",{type:"button",className:"ml-1","aria-label":`Remove ${_(l)}`,onClick:()=>s.removeChip(m,l),children:e.jsx(oe,{className:"h-3 w-3"})})]},`${m}:${l}`)})),Object.values(s.chips).some(n=>n?.length)&&e.jsx(v,{size:"sm",variant:"ghost",onClick:s.clearChips,children:"Clear all"})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row",children:[e.jsx(b,{value:t,onChange:n=>a(n.target.value.slice(0,100)),placeholder:"Query contains","aria-label":"Query contains"}),e.jsx(b,{value:r,onChange:n=>o(n.target.value.slice(0,100)),placeholder:"Page path contains","aria-label":"Page path contains"})]})]})}const $=[["clicks","Clicks"],["impressions","Impressions"],["sessions","Sessions"],["users","Daily users"],["keyEvents","Key events"]];function Ce(){const s=S("series"),[t,a]=u.useState(["clicks","sessions"]),r=ne(),o=$.filter(([n])=>t.includes(n)).map(([n,h],l)=>({dataKey:n,name:h,color:r.seriesColor(l)}));return e.jsx(F,{title:"Daily search & traffic",loading:s.isLoading,testId:"st-chart",actions:e.jsx("div",{className:"flex flex-wrap gap-1",children:$.map(([n,h])=>e.jsx(v,{size:"sm",variant:t.includes(n)?"secondary":"ghost",onClick:()=>a(l=>l.includes(n)?l.length>1?l.filter(m=>m!==n):l:[...l,n]),children:h},n))}),children:s.error?e.jsx("p",{className:"py-8 text-center text-sm text-destructive",children:"Could not load chart."}):s.data?.current.length?e.jsx(ce,{variant:"line",data:s.data.current,xKey:"date",series:o,valueFormatter:n=>N("",n),comparison:ie(!0,s.data.previous??void 0,o)}):e.jsx(L,{message:"No search or traffic data in this range"})})}const Te=[["query","Query"],["page","Page"],["country","Country"],["device","Device"]],we=[["channel","Channel group"],["source_medium","Source / medium"],["campaign","Campaign"],["landing_page","Landing page"],["ga4_country","Country"],["ga4_device","Device"]],Ne={query:"query",page:"pagePath",country:"country",device:"device",channel:"channel",source_medium:"sourceMedium",campaign:"campaign",landing_page:"pagePath",ga4_country:"country",ga4_device:"device"};function P({kind:s}){const t=T(),a=s==="search"?Te:we,r=a[0][0],o=a.some(([c])=>c===t.activeDimension)?t.activeDimension:r,[n,h]=u.useState(s==="search"?"clicks":"sessions"),[l,m]=u.useState("desc"),f=s==="search"?["clicks","impressions","ctr","position"]:["sessions","users","newUsers","engagedSessions","engagementRate","keyEvents",...o==="landing_page"?["signups"]:[]],x=f.some(c=>c===n)?n:f[0],i=S("rows",{dimension:o,sort:x,direction:l,limit:100}),d=H(),g=c=>{h(c),m(p=>x===c&&p==="desc"?"asc":"desc")};return e.jsxs(F,{title:s==="search"?"Search Console":"GA4 traffic",description:"Click any row to filter the entire page.",testId:`st-${s}-panel`,children:[e.jsxs("div",{className:"mb-3 flex flex-wrap items-center justify-between gap-2",children:[e.jsx(te,{value:o,onValueChange:c=>t.setActiveDimension(c),children:e.jsx(ae,{children:a.map(([c,p])=>e.jsx(re,{value:c,children:p},c))})}),e.jsx("a",{className:"text-sm font-medium text-primary underline",href:xe(d,o,x,l),children:"Export CSV"})]}),o==="landing_page"&&e.jsx("div",{className:"mb-2 flex gap-1",children:["first","last"].map(c=>e.jsx(v,{size:"sm",variant:t.touch===c?"secondary":"ghost",onClick:()=>t.setTouch(c),children:c==="first"?"First touch":"Last touch"},c))}),i.isLoading?e.jsx("div",{className:"h-48 animate-pulse rounded bg-muted"}):i.error?e.jsx("p",{className:"py-8 text-center text-sm text-destructive",children:"Could not load rows."}):i.data?.rows.length?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(X,{children:[e.jsx(ee,{children:e.jsxs(A,{children:[e.jsx(k,{children:"Name"}),f.map(c=>e.jsx(k,{className:"text-right",children:e.jsxs("button",{type:"button",onClick:()=>g(c),title:ve[c],children:[ye[c]??c.replace(/([A-Z])/g," $1"),x===c&&(l==="desc"?e.jsx(B,{className:"inline h-3 w-3"}):e.jsx(M,{className:"inline h-3 w-3"}))]})},c))]})}),e.jsx(se,{children:i.data.rows.map(c=>e.jsxs(A,{"data-testid":`st-row-${c.key}`,children:[e.jsxs(q,{className:"relative min-w-48",children:[e.jsx("div",{className:"absolute inset-y-1 left-1 rounded bg-primary/10",style:{width:`${Math.max(0,Math.min(1,c.share))*100}%`}}),e.jsx("button",{type:"button",className:"relative w-full text-left font-medium",onClick:()=>t.addChip(Ne[o],c.key),"data-testid":`st-row-action-${c.key}`,children:c.label})]}),f.map(p=>e.jsx(q,{className:"text-right tabular-nums",children:N(p,c[p])},p))]},c.key))})]})}),i.data.nonAdditive.length>0&&e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:["Non-additive across rows: ",i.data.nonAdditive.join(", "),". Do not sum these values.",i.data.nonAdditive.includes("users")?" Users are shown as average daily active users of the window.":""]})]}):e.jsx(L,{})]})}function Ae(){const s=S("data-quality");if(!s.data)return null;if(!s.data.sources.some(a=>a.configured))return e.jsx("div",{className:"rounded-xl border border-amber-300 bg-amber-50 p-4 text-sm dark:bg-amber-950/30",children:"Search Console and GA4 are not configured. Add the required property and site identifiers, then grant the service account access."});const t=s.data.recentFailures.find(a=>a.error?.includes("403")||/grant/i.test(a.error??""));return t?e.jsxs("div",{className:"rounded-xl border border-amber-300 bg-amber-50 p-4 text-sm dark:bg-amber-950/30",children:["Google access has not been granted for ",t.source,". Grant access to the service account shown under Data quality."]}):null}function ke(){const s=T();return e.jsx(Y,{title:"Search & Traffic",description:"Organic search performance, acquisition traffic, and Google sync health.",testId:"page-search-traffic",spacing:"loose",children:e.jsxs("div",{className:"pm-cockpit space-y-5",children:[e.jsx(Ae,{}),e.jsx(be,{}),e.jsx(Se,{}),e.jsx(Ce,{}),e.jsx("div",{className:"flex gap-1 rounded-lg border p-1",children:["search","traffic","quality"].map(t=>e.jsx("button",{type:"button",className:`rounded-md px-3 py-1.5 text-sm font-medium ${s.activeTab===t?"bg-secondary":""}`,onClick:()=>s.setActiveTab(t),children:t==="quality"?"Data quality":t==="search"?"Search":"Traffic"},t))}),s.activeTab==="search"&&e.jsx(P,{kind:"search"}),s.activeTab==="traffic"&&e.jsx(P,{kind:"traffic"}),s.activeTab==="quality"&&e.jsx(ge,{})]})})}function ts(){return e.jsx(pe,{children:e.jsx(ke,{})})}
1export{ts as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.