1"use strict";(self.webpackChunkaim_ene_github_io=self.webpackChunkaim_ene_github_io||[]).push([[4341],{8111(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"week-2/les-4/Quiz-Regels-Aggregate","title":"Quiz - Regels Aggregate","description":"Deze quiz gaat over de regels van aggregates, toegepast op twee casussen. Gebruik de regels uit les 2-3 om de vragen te beantwoorden.","source":"@site/courses/doex/studenten/docs/week-2/les-4/02-Quiz-Regels-Aggregate.mdx","sourceDirName":"week-2/les-4","slug":"/week-2/les-4/Quiz-Regels-Aggregate","permalink":"/doex/week-2/les-4/Quiz-Regels-Aggregate","draft":false,"unlisted":true,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"title":"Quiz - Regels Aggregate","sidebar_position":2,"unlisted":true},"sidebar":"materialSidebar"}');var r=t(74848),i=t(28453),s=t(31712);const o={title:"Quiz - Regels Aggregate",sidebar_position:2,unlisted:!0},l="Quiz Regels Aggregate",d={},c=[{value:"Casus 1: Productassortiment",id:"casus-1-productassortiment",level:2},{value:"Ophalen uit en opslaan in de Store",id:"ophalen-uit-en-opslaan-in-de-store",level:3},{value:"Associaties en encapsulatie",id:"associaties-en-encapsulatie",level:3},{value:"Casus 2: Filmfestivalplanner",id:"casus-2-filmfestivalplanner",level:2},{value:"Functionaliteiten",id:"functionaliteiten",level:3},{value:"Invariant",id:"invariant",level:3},{value:"Aggregates bepalen",id:"aggregates-bepalen",level:3}];function g(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"quiz-regels-aggregate",children:"Quiz Regels Aggregate"})}),"\n",(0,r.jsxs)(n.p,{children:["Deze quiz gaat over de regels van aggregates, toegepast op twee casussen. Gebruik de regels uit ",(0,r.jsx)(n.a,{href:"../les-3/Lesprogramma/Regels",children:"les 2-3"})," om de vragen te beantwoorden."]}),"\n",(0,r.jsx)(n.h2,{id:"casus-1-productassortiment",children:"Casus 1: Productassortiment"}),"\n",(0,r.jsxs)(n.p,{children:["Je maakt een systeem voor het beheren van een productassortiment en bestellingen. Dit ontwikkel je voor een opdrachtgever uit een winkel. Deze winkel verkoopt producten en houdt per product bij het totaal aantal dat klanten ervan besteld hebben. Als van een product de totale omzet (",(0,r.jsx)(n.code,{children:"aantal * prijs"}),") onder de ",(0,r.jsx)(n.code,{children:"\u20ac1000"})," ligt, halen ze het product uit het assortiment van de winkel."]}),"\n",(0,r.jsxs)(n.p,{children:["De winkel is gevestigd in Zaandam, maar heeft ook vestigingen elders in Nederland en Belgie (",(0,r.jsx)(n.code,{children:"895"})," winkels in Nederland en ",(0,r.jsx)(n.code,{children:"50"})," in Belgie). Als de try-out met het nieuwe systeem werkt, rollen ze het landelijk uit."]}),"\n",(0,r.jsx)(n.p,{children:"Hieronder is het klassendiagram weergegeven met een mogelijke aggregate-indeling:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-kroki",metastring:'imgType="plantuml" imgTitle="Klassendiagram Productassortiment"',children:'@startuml\nhide circle\nskinparam linetype ortho\n\nrectangle "Aggregate A" {\n\n class Product <<AR>> {\n productId\n naam\n prijs\n controleerMinimumOmzet()\n }\n\n class BestelRegel <<Entity>> {\n aantal\n stukPrijs\n getRegelPrijs()\n }\n}\n\nrectangle "Aggregate B" {\n class Bestelling <<AR>> {\n bestellingId\n datum\n }\n}\n\nProduct "1" -r- "*" BestelRegel\nBestelRegel "*" -r- "1" Bestelling\n\n@enduml\n'})}),"\n",(0,r.jsx)(n.h3,{id:"ophalen-uit-en-opslaan-in-de-store",children:"Ophalen uit en opslaan in de Store"}),"\n",(0,r.jsx)(s.A,{QuizList:[{question:"1. Welke invariant moet je in deze casus in je systeem bewaken?",answers:[{text:"De totale omzet van een product moet minstens \u20ac1000 zijn, anders gaat het product uit het assortiment",isCorrect:!0},{text:"De winkel ligt in Zaandam",isCorrect:!1},{text:"De keten heeft in Nederland 895 winkels",isCorrect:!1},{text:"Een bestelling moet altijd uit minimaal 2 bestelregels bestaan",isCorrect:!1}]},{question:"2. Wat gebeurt er als je een Product uit de Store ophaalt?",answers:[{text:"Alleen het Product zelf wordt opgehaald",isCorrect:!1},{text:"Het Product en alle bijbehorende BestelRegels worden opgehaald, want ze zitten in dezelfde aggregate",isCorrect:!0},{text:"Het Product, BestelRegels \xe9n de bijbehorende Bestellingen worden opgehaald",isCorrect:!1},{text:"Het Product en alleen de BestelRegels met een omzet boven \u20ac1000",isCorrect:!1}]},{question:"3. Kan een BestelRegel los uit de Store worden opgehaald?",answers:[{text:"Ja, want BestelRegel is een Entity met een eigen identiteit",isCorrect:!1},{text:"Ja, maar alleen als je het id van het Product meegeeft",isCorrect:!1},{text:"Nee, BestelRegel zit in de Product aggregate en kan alleen via de aggregate root worden opgehaald",isCorrect:!0},{text:"Nee, want BestelRegel is een Value Object",isCorrect:!1}]},{question:"4. Als een Bestelling uit de Store wordt opgehaald, worden de BestelRegels die ernaar verwijzen dan ook opgehaald?",answers:[{text:"Ja, want BestelRegel verwijst naar Bestelling",isCorrect:!1},{text:"Ja, want je hebt de BestelRegels nodig om de bestelling compleet te maken",isCorrect:!1},{text:"Nee, Bestelling en BestelRegel zitten in verschillende aggregates",isCorrect:!0},{text:"Nee, want BestelRegel is een Value Object en kan niet opgehaald worden",isCorrect:!1}]}]}),"\n",(0,r.jsx)(n.h3,{id:"associaties-en-encapsulatie",children:"Associaties en encapsulatie"}),"\n",(0,r.jsx)(s.A,{QuizList:[{question:"5. De associatie van BestelRegel naar Bestelling is...",answers:[{text:"Toegestaan, want objecten binnen een aggregate mogen verwijzen naar aggregate roots van andere aggregates",isCorrect:!0},{text:"Toegestaan, want alle objecten mogen naar alle andere objecten verwijzen",isCorrect:!1},{text:"Niet toegestaan, want BestelRegel mag alleen naar Product verwijzen",isCorrect:!1},{text:"Niet toegestaan, want alleen aggregate roots mogen naar andere aggregates verwijzen",isCorrect:!1}]},{question:"6. Stel dat er een directe associatie van Bestelling naar BestelRegel zou bestaan. Dit is...",answers:[{text:"Toegestaan, want Bestelling is een aggregate root",isCorrect:!1},{text:"Toegestaan, want BestelRegel is een Entity",isCorrect:!1},{text:"Niet toegestaan, want BestelRegel is geen aggregate root en objecten buiten de aggregate mogen alleen naar de root verwijzen",isCorrect:!0},{text:"Niet toegestaan, want Bestelling en BestelRegel zitten in dezelfde aggregate",isCorrect:!1}]},{question:"7. Waarom is Product de aggregate root in deze casus en niet BestelRegel?",answers:[{text:"Omdat Product meer attributen heeft dan BestelRegel",isCorrect:!1},{text:"Omdat BestelRegel een Value Object is",isCorrect:!1},{text:"Omdat Product de invariant over minimumomzet moet bewaken en daarvoor toegang nodig heeft tot alle BestelRegels",isCorrect:!0},{text:"Omdat er altijd maar \xe9\xe9n aggregate root per applicatie mag zijn",isCorrect:!1}]}]}),"\n",(0,r.jsx)(n.h2,{id:"casus-2-filmfestivalplanner",children:"Casus 2: Filmfestivalplanner"}),"\n",(0,r.jsx)(n.p,{children:"Een systeem voor een filmfestival waar bezoekers een persoonlijke dagplanning kunnen samenstellen uit het aanbod van filmvertoningen."}),"\n",(0,r.jsx)(n.p,{children:"Hieronder is het klassendiagram van het domein weergegeven (zonder aggregate-indeling):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-kroki",metastring:'imgType="plantuml" imgTitle="Klassendiagram Filmfestivalplanner (zonder aggregates)"',children:'@startuml\n\nhide circle\n\nclass Agenda <<Entity>>\n\nclass Favoriet <<Entity>> {\n isIngepland\n}\n\nclass Film <<Entity>>\n\nclass Dagplanning <<Entity>> {\n voegToe(Vertoning vertoning)\n maakPlanningsconflict()\n}\n\nclass Planningsconflict <<Value Object>> {\n conflictSoort\n}\n\nclass Onderdeel <<Value Object>>\n\nclass Vertoning <<Value Object>>\n\nDagplanning "1" --\x3e "onderdeel *" Onderdeel\nDagplanning "1" --\x3e "plannings\\nconflicten *" Planningsconflict\nPlanningsconflict "1" --\x3e "onderdelen\\n 2..*" Onderdeel\nAgenda "agenda 1" --- "dagplanning\\n*" Dagplanning\nAgenda "1" --\x3e "wensenlijst 1" Favoriet\nOnderdeel "1" --\x3e "vertoning 1" Vertoning\nFavoriet "1" --\x3e "film 1" Film\nVertoning "*" --\x3e "film 1" Film\n\n@enduml\n'})}),"\n",(0,r.jsx)(n.h3,{id:"functionaliteiten",children:"Functionaliteiten"}),"\n",(0,r.jsx)(n.p,{children:"Het systeem ondersteunt de volgende functionaliteiten:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Vertoning toevoegen aan dagplanning:"})," Een festivalbezoeker selecteert een vertoning en voegt deze toe aan de dagplanning voor een bepaalde dag. Er wordt een onderdeel aangemaakt in de dagplanning."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Planningsconflict detecteren:"})," Als een nieuw onderdeel overlapt met een bestaand onderdeel, wordt er automatisch een planningsconflict aangemaakt."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Favoriet markeren:"})," Een bezoeker kan een film op de wensenlijst zetten. Als de film ingepland wordt (zonder conflict), wordt ",(0,r.jsx)(n.code,{children:"isIngepland"})," op ",(0,r.jsx)(n.code,{children:"true"})," gezet."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"invariant",children:"Invariant"}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:"Er is altijd een planningsconflict voor onderdelen die overlappen in de dagplanning."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"aggregates-bepalen",children:"Aggregates bepalen"}),"\n",(0,r.jsx)(n.p,{children:"Gebruik de regels over aggregates om de onderstaande vragen te beantwoorden."}),"\n",(0,r.jsx)(s.A,{QuizList:[{question:"1. Welke klassen bewaken samen de invariant over planningsconflicten?",answers:[{text:"Dagplanning, Onderdeel en Planningsconflict",isCorrect:!0},{text:"Agenda, Dagplanning en Onderdeel",isCorrect:!1},{text:"Alle klassen in het diagram",isCorrect:!1},{text:"Onderdeel en Vertoning",isCorrect:!1}]},{question:"2. Op basis van de invariant: welke klasse is de beste kandidaat voor aggregate root?",answers:[{text:"Agenda, want die is de 'top-level' klasse in het diagram",isCorrect:!1},{text:"Onderdeel, want het conflict ontstaat door overlappende onderdelen",isCorrect:!1},{text:"Dagplanning, want die beheert de onderdelen en planningsconflicten die samen de invariant bewaken",isCorrect:!0},{text:"Planningsconflict, want die representeert de invariant zelf",isCorrect:!1}]},{question:"3. Als een Dagplanning verwijderd wordt, wat moet er dan ook verwijderd worden?",answers:[{text:"Alleen de Onderdelen",isCorrect:!1},{text:"De Onderdelen en Planningsconflicten",isCorrect:!0},{text:"De Onderdelen, Planningsconflicten \xe9n de Vertoningen",isCorrect:!1},{text:"Niets, de andere objecten bestaan onafhankelijk",isCorrect:!1}]},{question:"4. Als een Vertoning verwijderd wordt, moeten de Onderdelen die ernaar verwijzen dan ook verwijderd worden?",answers:[{text:"Ja, want Onderdeel kan niet bestaan zonder Vertoning",isCorrect:!1},{text:"Ja, want ze zitten in dezelfde aggregate",isCorrect:!1},{text:"Nee, Onderdeel en Vertoning horen waarschijnlijk niet in dezelfde aggregate omdat ze geen gemeenschappelijke invariant bewaken",isCorrect:!0},{text:"Nee, want Vertoning is een Value Object en kan niet verwijderd worden",isCorrect:!1}]},{question:"5. Moet Film in dezelfde aggregate als Vertoning?",answers:[{text:"Ja, want Vertoning verwijst naar Film",isCorrect:!1},{text:"Ja, want ze hebben een gedeelde lifecycle",isCorrect:!1},{text:"Nee, want een Film kan bestaan zonder Vertoningen en ze bewaken geen gemeenschappelijke invariant",isCorrect:!0},{text:"Nee, want Film is een Value Object",isCorrect:!1}]},{question:"6. Waarom is het beter om Agenda en Dagplanning NIET in dezelfde aggregate te plaatsen?",answers:[{text:"Omdat Agenda geen methoden heeft",isCorrect:!1},{text:"Omdat ze geen gemeenschappelijke invariant bewaken, en een grote aggregate trager is door meer objecten uit de Store te laden",isCorrect:!0},{text:"Omdat Agenda een Entity is en Dagplanning een Value Object",isCorrect:!1},{text:"Omdat er maar \xe9\xe9n aggregate root per applicatie mag zijn",isCorrect:!1}]}]})]})}function u(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(g,{...e})}):g(e)}},31712(e,n,t){t.d(n,{A:()=>u});var a=t(22007),r=t(10467),i=t(96540),s=t(34164);const o={form:"form_PqFI",infoNote:"infoNote_keBb",infoNoteIcon:"infoNoteIcon_DOx9",infoNoteText:"infoNoteText_LIVp",radio_btn__wrapper:"radio_btn__wrapper_UuEu",radio_btn:"radio_btn_Shob",checkButtonDisabledVisual:"checkButtonDisabledVisual_Qpnd",disabledCheckInl
1ineMessage:"disabledCheckInlineMessage_omBi",unlockForm:"unlockForm_XGKl",unlockLabel:"unlockLabel_c3Dv",unlockInput:"unlockInput_Hhrk",unlockInputError:"unlockInputError_AYgJ",unlockError:"unlockError_YlxA"};var l=t(74848);function d(e){var n=e.question,t=e.answers,a=e.chosenAnswer,r=i.useState(),s=(r[0],r[1]);return(0,l.jsx)("div",{children:(0,l.jsxs)("div",{children:[(0,l.jsx)("h3",{children:n}),(0,l.jsx)("div",{className:"radio",children:t.map(function(e,t){var r=a===t,i="default";return r&&e.isCorrect?i="correct":r&&!e.isCorrect?i="wrong":e.isCorrect&&void 0!==a&&(i="reveal"),(0,l.jsxs)("label",{className:o.radio_btn__wrapper,"data-state":i,children:[(0,l.jsx)("input",{className:o.radio_btn,type:"radio",name:n,value:e.text,onChange:function(e){s(t);var a=e.currentTarget.form;a&&a.querySelectorAll('input[name="'+n+'"]').forEach(function(e){return e.setCustomValidity("")})},required:!0,onInvalid:function(e){e.currentTarget.setCustomValidity("Selecteer een antwoord")}}),e.text,r&&e.isCorrect&&(0,l.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"var(--ifm-color-success)",width:24,height:24,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm13.36-1.814a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z",clipRule:"evenodd"})}),r&&!e.isCorrect&&(0,l.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"var(--ifm-color-danger)",width:24,height:24,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-1.72 6.97a.75.75 0 10-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 101.06 1.06L12 13.06l1.72 1.72a.75.75 0 101.06-1.06L13.06 12l1.72-1.72a.75.75 0 10-1.06-1.06L12 10.94l-1.72-1.72z",clipRule:"evenodd"})})]},t)})})]})})}function c(e){return g.apply(this,arguments)}function g(){return(g=(0,r.A)((0,a.A)().m(function e(n){var t,r,i,s;return(0,a.A)().w(function(e){for(;;)switch(e.n){case 0:if("undefined"!=typeof window&&null!=(t=window.crypto)&&t.subtle){e.n=1;break}throw new Error("SHA-256 is not available in this environment");case 1:return r=new TextEncoder,i=r.encode(n),e.n=2,window.crypto.subtle.digest("SHA-256",i);case 2:return s=e.v,e.a(2,Array.from(new Uint8Array(s)).map(function(e){return e.toString(16).padStart(2,"0")}).join(""))}},e)}))).apply(this,arguments)}function u(e){var n=e.QuizList,t=e.disableAnswerCheck,g=void 0!==t&&t,u=e.disabledCheckAlertMessage,p=void 0===u?"Denk zelf na wat goede antwoord is, neem materiaal verder door en/of bespreek met mede student":u,m=e.showInfoNote,h=void 0===m||m,w=e.infoNoteText,v=void 0===w?"Deze quiz helpt je toetsen of je de bron echt hebt bekeken/gelezen en begrepen. Zo niet: bekijk/lees de bron opnieuw. Gebruik deze quiz niet als 'gaming' voor de toets; de toetsvragen zijn inhoudelijk anders.":w,x=e.unlockCode,k=e.unlockHash,f=i.useState([]),b=f[0],j=f[1],C=i.useState(!1),z=C[0],A=C[1],N=function(e){var n=e.unlockCode,t=e.unlockHash,s=t?"h:"+t:n?"c:"+n:"",o="quiz_unlocked_"+s,l=!!s,d=i.useState(function(){return!("undefined"==typeof window||!l)&&"true"===localStorage.getItem(o)}),g=d[0],u=d[1],p=i.useState(""),m=p[0],h=p[1],w=i.useState(!1),v=w[0],x=w[1],k=i.useState(!1),f=k[0],b=k[1],j=i.useState(!1),C=j[0],z=j[1],A=function(){var e=(0,r.A)((0,a.A)().m(function e(){var r,i;return(0,a.A)().w(function(e){for(;;)switch(e.p=e.n){case 0:if(l&&!C){e.n=1;break}return e.a(2);case 1:if(z(!0),e.p=2,r=!1,!t){e.n=4;break}return e.n=3,c(m);case 3:i=e.v,r=i===t,e.n=5;break;case 4:n&&(r=m===n);case 5:r?(localStorage.setItem(o,"true"),u(!0),x(!1),b(!1)):b(!0),e.n=7;break;case 6:e.p=6,e.v,b(!0);case 7:return e.p=7,z(!1),e.f(7);case 8:return e.a(2)}},e,null,[[2,6,7,8]])}));return function(){return e.apply(this,arguments)}}();return{unlocked:g,inputValue:m,setInputValue:h,showInput:v,setShowInput:x,error:f,setError:b,isChecking:C,tryUnlock:A}}({unlockCode:x,unlockHash:k}),B=(!!x||!!k)&&!N.unlocked,R=B||g;return(0,l.jsx)("section",{className:o.quizs,children:(0,l.jsxs)("div",{children:[h&&(0,l.jsxs)("div",{className:o.infoNote,role:"note","aria-label":"Quiz toelichting",children:[(0,l.jsx)("span",{className:o.infoNoteIcon,"aria-hidden":"true",children:"i"}),(0,l.jsx)("p",{className:o.infoNoteText,children:v})]}),(0,l.jsxs)("form",{className:o.form,onSubmit:function(e){if(e.preventDefault(),R)A(!0);else{var t=new FormData(e.currentTarget),a=n.map(function(e){return e.answers.findIndex(function(n){return n.text===t.get(e.question)})});j(a)}},children:[n.map(function(e,n){return(0,l.jsx)(d,{question:e.question,answers:e.answers,chosenAnswer:b[n]},e.question)}),(0,l.jsx)("button",{style:{alignSelf:"center"},className:(0,s.A)("button button--primary button--lg",R&&o.checkButtonDisabledVisual),type:R?"button":"submit",onClick:function(){B?(N.setShowInput(!0),A(!1)):g&&A(!0)},children:"Check je antwoorden"}),B&&N.showInput&&(0,l.jsxs)("div",{className:o.unlockForm,role:"status","aria-live":"polite",children:[(0,l.jsxs)("label",{className:o.unlockLabel,children:["Voer de code in om antwoorden te controleren:",(0,l.jsx)("input",{className:(0,s.A)(o.unlockInput,N.error&&o.unlockInputError),type:"password",value:N.inputValue,onChange:function(e){N.setInputValue(e.target.value),N.error&&N.setError(!1)},onKeyDown:function(e){"Enter"===e.key&&(e.preventDefault(),N.tryUnlock())},placeholder:"Code",autoFocus:!0})]}),(0,l.jsx)("button",{type:"button",className:"button button--secondary button--sm",onClick:function(){N.tryUnlock()},disabled:N.isChecking,children:N.isChecking?"Controleren...":"Ontgrendelen"}),N.error&&(0,l.jsx)("p",{className:o.unlockError,children:"Onjuiste code. Probeer opnieuw."})]}
1),!B&&g&&z&&(0,l.jsx)("p",{className:o.disabledCheckInlineMessage,role:"status","aria-live":"polite",children:p})]})]})})}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>o});var a=t(96540);const r={},i=a.createContext(r);function s(e){const n=a.useContext(i);return a.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),a.createElement(i.Provider,{value:n},e.children)}}}]);
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.