PageSourceSearch

https://www.wiim.immo/_nuxt/Dfv6y6wT.js

js wiim.immo collected 2026-10-09 22:59:47 UTC 18,910 bytes, 1 lines download raw bytes

1import{_ as he}from"./6JOvctkh.js";import{_ as ke}from"./DxOG0pT0.js";import{_ as we}from"./Dx_Ou25x.js";import{_ as Ce}from"./ByWatnw4.js";import Ve from"./BlUlAP2D.js";import{_ as Ee}from"./BA4VewZY.js";import{e as qe,C as Te,h as M,f as B,u as De,c as u,a as l,d,t as o,k as _,F as w,b as s,w as m,B as Ue,s as Fe,p as h,q as S,o as c,r as q,n as O,i as G,A as J,l as f}from"./D8644rYh.js";import{D as Se}from"./B3pBtLLm.js";import{u as Pe}from"./MRLRowXz.js";import"./Cwm7gl9R.js";import"./DlAUqK2U.js";const $e={class:"text-sm text-grey-text mb-6"},ze={key:0},Ae={key:0,class:"text-grey-text"},Ne={class:"flex flex-wrap items-center justify-between gap-2 mb-2"},je={class:"flex items-center gap-2"},Le={class:"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border border-gray-200 dark:border-gray-700 text-[11px] font-medium text-grey-text whitespace-nowrap"},Me={class:"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border border-gray-200 dark:border-gray-700 text-[11px] font-medium text-grey-text whitespace-nowrap"},Be={class:"max-w-md mx-auto mb-5"},Re={key:0,role:"alert",class:"text-danger text-sm mb-3"},He={class:"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2"},Ie=["disabled","onClick"],Oe={class:"text-sm text-dark dark:text-gray-200"},Ge={class:"grid sm:grid-cols-2 gap-4"},Je={class:"flex items-center justify-between mb-4"},Ye={class:"text-lg font-semibold text-dark dark:text-white mb-0"},Ze={class:"space-y-3"},We={class:"grid sm:grid-cols-12 gap-3 items-start"},Ke=["value"],Qe=["value"],Xe={class:"flex flex-wrap items-center justify-between gap-3 mt-3"},et={class:"inline-flex items-center gap-2 text-sm cursor-pointer"},tt=["onUpdate:modelValue"],lt={key:0,class:"inline-flex items-center gap-2 text-sm"},at=["onClick"],st={class:"mt-2.5 text-xs text-grey-text bg-gray-50 dark:bg-gray-900 rounded-lg px-3 py-2 flex items-start gap-1.5"},it={key:0,class:"text-center py-8 text-grey-text"},nt={class:"flex flex-wrap items-center justify-between gap-2 mb-2"},ot={class:"text-lg font-semibold text-dark dark:text-white mb-0"},rt={class:"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border border-gray-200 dark:border-gray-700 text-[11px] font-medium text-grey-text whitespace-nowrap"},dt={class:"text-xs text-grey-text mb-4"},ut={class:"space-y-3"},ct={class:"grid sm:grid-cols-12 gap-3 items-start"},mt={value:""},pt=["value"],gt=["value"],ft={class:"inline-flex items-center gap-2 text-sm h-10 cursor-pointer"},yt=["onUpdate:modelValue"],vt={class:"mt-1.5 text-[11px] text-grey-text"},bt={class:"mt-3 flex justify-end"},xt=["onClick"],_t={key:0,class:"text-center py-8 text-grey-text"},ht={class:"mt-2 text-sm"},kt={class:"flex flex-wrap items-center gap-3 mt-4"},wt={key:0,class:"text-success text-sm"},Ct={key:1,class:"text-danger text-sm"},Vt={class:"flex items-center gap-3"},Et={key:0,class:"text-success text-sm"},qt={key:1,class:"text-danger text-sm"},Mt=qe({__name:"index",setup(Tt){const C=Pe(),{t:p}=Te(),v=h([]),Y=S(()=>v.value.filter(e=>e.active).length),Z=S(()=>v.value.filter(e=>!e.active&&e.coming_soon).length),W=S(()=>v.value.filter(e=>e.active).map(e=>e.code)),K=S(()=>v.value.filter(e=>!e.active&&e.coming_soon).map(e=>e.code)),T=h(""),V=h([]);async function N(e){if(V.value.includes(e.code))return!1;const t=e.active?{active:!1,coming_soon:!0}:e.coming_soon?{active:!1,coming_soon:!1}:{active:!0,coming_soon:!1},i={active:e.active,coming_soon:e.coming_soon};e.active=t.active,e.coming_soon=t.coming_soon,T.value="",V.value=[...V.value,e.code];try{const r=await C(`/admin/departments/${e.code}`,{method:"PATCH",body:t});return r&&typeof r.active=="boolean"&&(e.active=r.active,e.coming_soon=r.coming_soon),!0}catch(r){return e.active=i.active,e.coming_soon=i.coming_soon,T.value=`${e.code} ${e.name} n'a pas pu être enregistré. Réessayez.`,console.error("cycleDept",r),!1}finally{V.value=V.value.filter(r=>r!==e.code)}}async function Q(e){const t=v.value.find(y=>y.code===e);if(t){await N(t);return}const i=Se[e];if(!i){T.value=`Le département ${e} n'est pas reconnu.`;return}v.value=[...v.value,{code:e,name:i,active:!1,coming_soon:!1}].sort((y,x)=>y.code.localeCompare(x.code,"fr"));const r=v.value.find(y=>y.code===e);if(!r)return;await N(r)||(v.value=v.value.filter(y=>y.code!==e))}function X(e){return e.active?"Couvert":e.coming_soon?"Bientôt":"Hors zone"}function ee(e){return e.active?"bg-primary-50 dark:bg-gray-900 border-primary-300 dark:border-primary-700":e.coming_soon?"border-primary-200 dark:border-primary-800 bg-primary-50/40 dark:bg-gray-900/40":"border-gray-200 dark:border-gray-700 opacity-70"}function te(e){return e.active?"text-primary-600":e.coming_soon?"text-primary-500":"text-grey-text"}const le=[{v:"eq",label:"= égal"},{v:"neq",label:"≠ différent"},{v:"gt",label:"> sup."},{v:"gte",label:"≥ sup. ou égal"},{v:"lt",label:"< inf."},{v:"lte",label:"≤ inf. ou égal"},{v:"in",label:"∈ dans la liste"},{v:"nin",label:"∉ hors liste"}],j=[{key:"operation_type",label:"Type d'opération",hint:'["immeuble","maison_terrain","ensemble"]'},{key:"usage",label:"Usage du bien",hint:'["habitation","mixte"]'},{key:"division_only",label:"Division uniquement",hint:"true"},{key:"works_needed",label:"Travaux nécessaires",hint:'["none","ingenierie"]'},{key:"asking_price",label:"Prix de vente affiché (€)",hint:"un nombre, ex. 500000"},{key:"lots_estimes",label:"Lots estimés",hint:"un nombre, ex. 2"},{key:"role",label:"Profil du déposant",hint:'["proprietaire","agent","apporteur","ambassadeur","cooperation"]'}];function R(e){return j.find(t=>t.key===e)?.label??e}function ae(e){return j.find(t=>t.key===e)?.hint??'true, un nombre, ou une liste ["A","B"]'}function se(e,t){e.field=t,e.label=R(t)}function ie(e){const t={eq:"égal à",neq:"différent de",gt:"supérieur à",gte:"supérieur ou égal à",lt:"inférieur à",lte:"inférieur ou égal à",in:"dans la liste",nin:"hors de la liste"},i=e.field?R(e.field):"ce champ",r=e.value===""||e.value===void 0||e.value===null?"…":e.value,b=e.hard_fail?"→ sinon REFUS":`→ +${e.points||0} pts si respecté`;return`« ${i} » doit être ${t[e.operator]??e.operator} ${r}  ${b}`}const g=Fe({name:"",pass_threshold:50,definition:[]}),P=h(!1),D=h(""),$=h(""),L=[{type:"titre_propriete",label:"Titre de propriété",fields:"propriétaires, références cadastrales, adresse du bien, date d'acquisition, notaire"},{type:"plans",label:"Plans de l'immeuble",fields:"nombre de lots, surfaces, niveaux / étages"},{type:"dpe",label:"DPE",fields:"étiquette énergie, étiquette GES, consommation kWh/m²/an, date de réalisation, validité"},{type:"taxe_fonciere",label:"Taxe foncière",fields:"montant total, année, commune, références"},{type:"etat_locatif",label:"État locatif / baux",fields:"lots loués, loyers mensuels, locataires, surfaces"},{type:"diagnostics",label:"Diagnostics techniques",fields:"types de diagnostics, dates, conclusions"},{type:"photos",label:"Photos / vidéos",fields:"état général, travaux visibles"},{type:"plan_cadastral",label:"Plan cadastral",fields:"commune, sections et numéros de parcelles, échelle, contenance"},{type:"dossier_complet",label:"Dossier complet",fields:"pièces présentes, points saillants"}],k=h([]),z=h(!1),U=h(""),A=h("");function ne(e){return e.split(/[,;\n]/).map(t=>
1t.trim()).filter(Boolean)}function H(e){return(e??[]).join(", ")}function oe(e,t){e.type=t;const i=L.find(r=>r.type===t);i&&(e.label.trim()||(e.label=i.label),e.analysisFieldsText.trim()||(e.analysisFieldsText=i.fields))}function re(){k.value.push({type:"",label:"",required:!0,analysisFieldsText:""})}function de(e){return e.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"").slice(0,40)}async function ue(){z.value=!0,U.value="",A.value="";try{const e=k.value.map(i=>{const r=ne(i.analysisFieldsText);return{type:i.type||de(i.label),label:i.label.trim(),required:!!i.required,...r.length?{analysis_fields:r}:{}}}).filter(i=>i.label&&i.type),t=await C("/admin/checklist-template",{method:"PUT",body:{items:e}});k.value=t.map(i=>({type:i.type,label:i.label,required:!!i.required,analysisFieldsText:H(i.analysis_fields)})),U.value=p("adminEligibility.docsSaved"),setTimeout(()=>{U.value=""},3e3)}catch{A.value=p("adminEligibility.docsSaveError")}finally{z.value=!1}}function ce(e){return typeof e=="string"?e:JSON.stringify(e)}function me(e){if(typeof e!="string")return e;const t=e.trim();if(t==="")return"";try{return JSON.parse(t)}catch{return e}}const{data:pe,status:ge}=M("admin-departments",()=>C("/admin/departments"),{server:!1,default:()=>[]});B(pe,e=>{v.value=e??[]},{immediate:!0});const{data:fe,status:ye}=M("admin-rules",()=>C("/admin/eligibility/rules"),{server:!1});B(fe,e=>{e&&(g.version=e.version,g.name=e.name??"",g.pass_threshold=e.pass_threshold??50,g.definition=(e.definition??[]).map(t=>({...t,value:ce(t.value)})))},{immediate:!0});const{data:ve,status:be}=M("admin-eligibility-docs",()=>C("/admin/checklist-template"),{server:!1,default:()=>[]});B(ve,e=>{k.value=(e??[]).map(t=>({type:t.type,label:t.label,required:!!t.required,analysisFieldsText:H(t.analysis_fields)}))},{immediate:!0});const xe=S(()=>[ge.value,ye.value,be.value].some(e=>e==="idle"||e==="pending"));function I(){g.definition.push({field:"",label:"",operator:"eq",value:"",points:0,hard_fail:!1})}async function _e(){P.value=!0,D.value="",$.value="";try{const e={name:g.name,pass_threshold:g.pass_threshold,definition:g.definition.map(i=>({field:i.field,label:i.label||void 0,operator:i.operator,value:me(i.value),points:i.points||void 0,hard_fail:i.hard_fail||void 0}))},t=await C("/admin/eligibility/rules",{method:"PUT",body:e});g.version=t.version,D.value=`Grille v${t.version} enregistrée ✓`,setTimeout(()=>D.value="",3e3)}catch{$.value="Échec de l'enregistrement."}finally{P.value=!1}}return De({title:"Admin · Règles d'éligibilité"}),(e,t)=>{const i=he,r=ke,b=we,y=Ce,x=Ve,F=Ee;return c(),u("div",null,[t[18]||(t[18]=l("h1",{class:"font-display text-2xl font-bold text-dark dark:text-white mb-1"},"Règles d'éligibilité",-1)),l("p",$e,[t[2]||(t[2]=d(" Grille active ",-1)),g.version?(c(),u("span",ze,"v"+o(g.version),1)):_("",!0),t[3]||(t[3]=d(". Enregistrer crée une ",-1)),t[4]||(t[4]=l("strong",null,"nouvelle version",-1)),t[5]||(t[5]=d(" (l'historique des soumissions est préservé). ",-1))]),xe.value?(c(),u("p",Ae,"Chargement…")):(c(),u(w,{key:1},[s(r,{class:"mb-6"},{default:m(()=>[l("div",Ne,[t[8]||(t[8]=l("h2",{class:"text-lg font-semibold text-dark dark:text-white mb-0"},"Zone couverte · départements",-1)),l("div",je,[l("span",Le,[t[6]||(t[6]=l("span",{class:"h-1.5 w-1.5 rounded-full bg-primary-600"},null,-1)),d(" "+o(Y.value)+" couverts",1)]),l("span",Me,[t[7]||(t[7]=l("span",{class:"h-1.5 w-1.5 rounded-full bg-primary-400"},null,-1)),d(" "+o(Z.value)+" bientôt",1)])])]),t[9]||(t[9]=l("p",{class:"text-xs text-grey-text mb-3"},[d("Cliquez un département (carte ou liste) pour faire défiler son état : "),l("strong",{class:"text-primary-600"},"couvert"),d(" → "),l("strong",{class:"text-primary-500"},"bientôt"),d(" → hors zone. Pris en compte "),l("strong",null,"immédiatement"),d(" dans le formulaire public.")],-1)),l("div",Be,[s(i,{active:W.value,coming:K.value,interactive:!0,onToggle:Q},null,8,["active","coming"])]),T.value?(c(),u("p",Re,o(T.value),1)):_("",!0),l("div",He,[(c(!0),u(w,null,q(v.value,a=>(c(),u("button",{key:a.code,type:"button",disabled:V.value.includes(a.code),class:O(["flex items-center justify-between gap-2 rounded-lg border px-3 py-2 text-left transition disabled:opacity-50",ee(a)]),onClick:E=>N(a)},[l("span",Oe,[l("strong",null,o(a.code),1),d(" "+o(a.name),1)]),l("span",{class:O(["text-[10px] font-medium whitespace-nowrap",te(a)])},o(X(a)),3)],10,Ie))),128))])]),_:1}),s(r,{class:"mb-6"},{default:m(()=>[l("div",Ge,[s(y,{label:"Nom de la grille"},{default:m(()=>[s(b,{modelValue:g.name,"onUpdate:modelValue":t[0]||(t[0]=a=>g.name=a),class:"w-full",placeholder:"Acquisition vendeurs · v2"},null,8,["modelValue"])]),_:1}),s(y,{label:"Seuil d'éligibilité (score ≥)"},{default:m(()=>[s(b,{modelValue:g.pass_threshold,"onUpdate:modelValue":t[1]||(t[1]=a=>g.pass_threshold=a),modelModifiers:{number:!0},type:"number",min:"0",class:"w-full"},null,8,["modelValue"])]),_:1})]),t[10]||(t[10]=l("p",{class:"text-xs text-grey-text mt-3"},[d(" Verdict : un critère "),l("strong",null,"bloquant"),d(" non satisfait → "),l("em",null,"inéligible"),d(". Sinon score ≥ seuil → "),l("em",null,"éligible"),d(", sinon "),l("em",null,"revue manuelle"),d(". ")],-1))]),_:1}),s(r,{class:"mb-6"},{default:m(()=>[l("div",Je,[l("h2",Ye,"Critères ("+o(g.definition.length)+")",1),s(F,{variant:"ghost",size:"sm",onClick:I},{default:m(()=>
1[s(x,{name:"solar:add-circle-linear",class:"h-4 w-4 mr-1.5"}),t[11]||(t[11]=d(" Ajouter un critère",-1))]),_:1})]),l("div",Ze,[(c(!0),u(w,null,q(g.definition,(a,E)=>(c(),u("div",{key:E,class:"rounded-xl border border-gray-200 dark:border-gray-700 p-4"},[l("div",We,[s(y,{class:"sm:col-span-4",label:"Information du formulaire"},{default:m(()=>[s(b,{as:"select","model-value":a.field,class:"w-full",onChange:n=>se(a,n.target.value)},{default:m(()=>[t[12]||(t[12]=l("option",{value:""},"Choisir…",-1)),(c(),u(w,null,q(j,n=>l("option",{key:n.key,value:n.key},o(n.label),9,Ke)),64))]),_:1},8,["model-value","onChange"])]),_:2},1024),s(y,{class:"sm:col-span-3",label:"Condition"},{default:m(()=>[s(b,{modelValue:a.operator,"onUpdate:modelValue":n=>a.operator=n,as:"select",class:"w-full"},{default:m(()=>[(c(),u(w,null,q(le,n=>l("option",{key:n.v,value:n.v},o(n.label),9,Qe)),64))]),_:1},8,["modelValue","onUpdate:modelValue"])]),_:2},1024),s(y,{class:"sm:col-span-5",label:"Valeur attendue"},{default:m(()=>[s(b,{modelValue:a.value,"onUpdate:modelValue":n=>a.value=n,class:"w-full",placeholder:ae(a.field)},null,8,["modelValue","onUpdate:modelValue","placeholder"])]),_:2},1024)]),l("div",Xe,[l("label",et,[G(l("input",{"onUpdate:modelValue":n=>a.hard_fail=n,type:"checkbox",class:"h-4 w-4 accent-primary-600"},null,8,tt),[[J,a.hard_fail]]),t[13]||(t[13]=l("span",null,[d("Critère "),l("strong",null,"bloquant"),d(" : refus immédiat si non respecté")],-1))]),a.hard_fail?_("",!0):(c(),u("label",lt,[t[14]||(t[14]=l("span",{class:"text-grey-text"},"Points si respecté",-1)),s(b,{modelValue:a.points,"onUpdate:modelValue":n=>a.points=n,modelModifiers:{number:!0},type:"number",class:"w-full !py-1"},null,8,["modelValue","onUpdate:modelValue"])])),l("button",{class:"text-danger text-xs ml-auto",onClick:n=>g.definition.splice(E,1)},"Supprimer",8,at)]),l("p",st,[s(x,{name:"solar:clipboard-text-linear",class:"h-4 w-4 shrink-0 mt-0.5"}),d(" "+o(ie(a)),1)])]))),128)),g.definition.length?_("",!0):(c(),u("div",it,[s(x,{name:"solar:checklist-minimalistic-linear",class:"h-8 w-8 mx-auto opacity-40"}),t[16]||(t[16]=l("p",{class:"mt-2 text-sm"},"Aucun critère. Ajoutez-en un pour construire la grille.",-1)),s(F,{variant:"ghost",size:"sm",class:"mt-4",onClick:I},{default:m(()=>[s(x,{name:"solar:add-circle-linear",class:"h-4 w-4 mr-1.5"}),t[15]||(t[15]=d(" Ajouter un critère",-1))]),_:1})]))])]),_:1}),s(r,{class:"mb-6"},{default:m(()=>[l("div",nt,[l("h2",ot,o(f(p)("adminEligibility.docsTitle")),1),l("span",rt,o(f(p)("adminEligibility.docsCount",{n:k.value.length})),1)]),l("p",dt,o(f(p)("adminEligibility.docsHelp")),1),l("div",ut,[(c(!0),u(w,null,q(k.value,(a,E)=>(c(),u("div",{key:E,class:"rounded-xl border border-gray-200 dark:border-gray-700 p-4"},[l("div",ct,[s(y,{class:"sm:col-span-4",label:f(p)("adminEligibility.docType")},{default:m(()=>[s(b,{as:"select","model-value":a.type,class:"w-full",onChange:n=>oe(a,n.target.value)},{default:m(()=>[l("option",mt,o(f(p)("adminEligibility.docTypeChoose")),1),(c(),u(w,null,q(L,n=>l("option",{key:n.type,value:n.type},o(n.label),9,pt)),64)),a.type&&!L.some(n=>n.type===a.type)?(c(),u("option",{key:0,value:a.type},o(a.label||a.type),9,gt)):_("",!0)]),_:2},1032,["model-value","onChange"])]),_:2},1032,["label"]),s(y,{class:"sm:col-span-5",label:f(p)("adminEligibility.docLabel")},{default:m(()=>[s(b,{modelValue:a.label,"onUpdate:modelValue":n=>a.label=n,class:"w-full",placeholder:f(p)("adminEligibility.docLabelPlaceholder")},null,8,["modelValue","onUpdate:modelValue","placeholder"])]),_:2},1032,["label"]),s(y,{class:"sm:col-span-3",label:f(p)("adminEligibility.docRequired")},{default:m(()=>[l("label",ft,[G(l("input",{"onUpdate:modelValue":n=>a.required=n,type:"checkbox",class:"h-4 w-4 accent-primary-600"},null,8,yt),[[J,a.required]]),l("span",null,o(a.required?f(p)("adminEligibility.requiredYes"):f(p)("adminEligibility.requiredNo")),1)])]),_:2},1032,["label"])]),s(y,{class:"mt-3",label:f(p)("adminEligibility.analysisFields")},{default:m(()=>[s(b,{modelValue:a.analysisFieldsText,"onUpdate:modelValue":n=>a.analysisFieldsText=n,class:"w-full",placeholder:f(p)("adminEligibility.analysisFieldsPlaceholder")},null,8,["modelValue","onUpdate:modelValue","placeholder"])]),_:2},1032,["label"]),l("p",vt,o(f(p)("adminEligibility.analysisFieldsHint")),1),l("div",bt,[l("button",{type:"button",class:"text-danger text-xs",onClick:n=>k.value.splice(E,1)},o(f(p)("adminEligibility.removeDoc")),9,xt)])]))),128)),k.value.length?_("",!0):(c(),u("div",_t,[s(x,{name:"solar:document-add-linear",class:"h-8 w-8 mx-auto opacity-40"}),l("p",ht,o(f(p)("adminEligibility.docsEmpty")),1)]))]),l("div",kt,[s(F,{variant:"ghost",size:"sm",onClick:re},{default:m(()=>
1[s(x,{name:"solar:add-circle-linear",class:"h-4 w-4 mr-1.5"}),d(" "+o(f(p)("adminEligibility.addDoc")),1)]),_:1}),s(F,{disabled:z.value,size:"sm",onClick:ue},{default:m(()=>[s(x,{name:"solar:diskette-linear",class:"h-4 w-4 mr-1.5"}),d(" "+o(z.value?f(p)("adminEligibility.savingDocs"):f(p)("adminEligibility.saveDocs")),1)]),_:1},8,["disabled"]),U.value?(c(),u("span",wt,o(U.value),1)):_("",!0),A.value?(c(),u("span",Ct,o(A.value),1)):_("",!0)])]),_:1}),l("div",Vt,[s(F,{disabled:P.value,onClick:_e},{default:m(()=>[s(x,{name:"solar:diskette-linear",class:"h-5 w-5 mr-1.5"}),d(" "+o(P.value?"Enregistrement…":"Enregistrer la grille"),1)]),_:1},8,["disabled"]),D.value?(c(),u("span",Et,o(D.value),1)):_("",!0),$.value?(c(),u("span",qt,o($.value),1)):_("",!0)]),t[17]||(t[17]=Ue('<p class="text-xs text-grey-text mt-4"> La <strong>zone (départements)</strong> est gérée plus haut, séparément des règles. Valeur : <code class="px-1 py-0.5 rounded bg-gray-100 dark:bg-gray-900 text-primary-700 text-xs">true</code> / <code class="px-1 py-0.5 rounded bg-gray-100 dark:bg-gray-900 text-primary-700 text-xs">false</code>, un nombre (<code class="px-1 py-0.5 rounded bg-gray-100 dark:bg-gray-900 text-primary-700 text-xs">500000</code>), ou une liste <code class="px-1 py-0.5 rounded bg-gray-100 dark:bg-gray-900 text-primary-700 text-xs">[&quot;immeuble&quot;,&quot;ensemble&quot;]</code>. </p>',1))],64))])}}});export{Mt 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.