Skip to main content

Account, profiel, toegankelijkheid en voorkeuren

5.1 Doel

Dit hoofdstuk beschrijft de functionele grenzen rond accounttoegang, interne accountcontext, profielgegevens, toegankelijkheidsinstellingen, voorkeuren, accountverwijdering en logout.

OefenHub maakt hierbij expliciet onderscheid tussen:

  • authenticatie bij de externe identity provider;
  • het interne OefenHub-account;
  • het OefenHub-applicatieprofiel;
  • gebruikersinstellingen en voorkeuren;
  • rol- en frontendcontext;
  • account lifecycle en anonimisering.

Authenticatie, credentials en primaire identity-provider-sessies blijven buiten het OefenHub-profielbeheer. OefenHub verwerkt na succesvolle externe authenticatie uitsluitend de interne applicatiecontext.

5.2 Authenticatiegrens

OefenHub beheert geen wachtwoorden, credentialstatus, wachtwoord-reset, e-mailverificatie of primaire identity-provider-sessies.

De externe identity provider is bronhouder voor:

  • login;
  • registratie;
  • wachtwoorden;
  • wachtwoord vergeten / reset;
  • credential lifecycle;
  • e-mailverificatie;
  • primaire authenticatiesessie.

OefenHub beheert zelf:

  • het interne Users-record;
  • de stabiele koppeling met de identity provider via Users.ExternalId;
  • OefenHub-profielgegevens;
  • roltoekenningen en rolcontext;
  • gebruikersinstellingen;
  • toegankelijkheid en voorkeuren;
  • domeintoegang en applicatiecontext.

Een succesvolle identity-providerlogin is dus nog geen volledige OefenHub-login. OefenHub-toegang ontstaat pas wanneer het interne account eenduidig bestaat, actief is en server-side naar een geldige applicatiecontext vertaald kan worden.

5.3 Eerste login en accountprovisioning

Na succesvolle terugkeer uit de identity-providerflow zoekt OefenHub het interne account op via Users.ExternalId.

SituatieFunctioneel gedrag
ExternalId bestaat alOefenHub gebruikt het bestaande interne account en vervolgt de reguliere sessieverwerking.
ExternalId bestaat nog nietOefenHub start interne accountprovisioning.
Vereiste identity-data ontbreektOefenHub blokkeert provisioning en logt de fout technisch.
Identity-data conflicteert met bestaande interne dataOefenHub blokkeert provisioning en voorkomt een half of dubbel account.
Intern account is gedeactiveerd of geanonimiseerdOefenHub bouwt geen reguliere applicatiesessie op.

Provisioning is idempotent. Een herhaalde callback of opnieuw inloggen met dezelfde externe identiteit mag nooit een tweede intern OefenHub-account aanmaken.

Tijdens provisioning worden minimaal verwerkt:

  • intern Users-record;
  • stabiele ExternalId;
  • basisprofielgegevens voor zover betrouwbaar beschikbaar;
  • UserSettings met toegestane defaults;
  • eventuele publieke initiële rolcontext wanneer die betrouwbaar en toegestaan is;
  • geldige pending relatie-uitnodigingen op genormaliseerd e-mailadres;
  • systeemberichten voor gekoppelde inkomende relatie-uitnodigingen;
  • technische of accountlogregistratie van provisioning- en conflictsituaties.

Niet-publieke rollen zoals Beheerder en TestDocent mogen nooit via publieke provisioning, profielwijziging of relatie-uitnodiging worden toegekend.

5.4 Falen van OefenHub-initialisatie na identity-providerlogin

Wanneer de identity-providerlogin of registratie slaagt, maar OefenHub de interne applicatiecontext niet veilig kan initialiseren, krijgt de gebruiker geen reguliere OefenHub-sessie.

In dat geval geldt:

  • de gebruiker ziet geen normale ingelogde applicatiecontext;
  • er wordt geen reguliere rolfrontpage opgebouwd;
  • er wordt geen automatische gebruikersgerichte herstelactie aangeboden wanneer de interne toestand niet veilig te herstellen is;
  • de fout wordt technisch of accountlogmatig vastgelegd;
  • logging bevat geen wachtwoorden, tokens, secrets of credentialgegevens;
  • de gebruiker krijgt een veilige foutmelding of contactroute.

Deze situatie valt binnen het OefenHub-domein voor detectie, blokkade, logging en veilige gebruikersafhandeling. De oorzaak kan bij de identity provider, claimset, database, provisioning, configuratie of applicatieservice liggen, maar OefenHub moet voorkomen dat een half aangemaakt of inconsistent account bruikbaar wordt.

5.5 Reguliere login en sessieverwerking

Voor bestaande accounts verwerkt OefenHub na succesvolle externe authenticatie de interne sessiecontext.

Daarbij worden minimaal gecontroleerd of geladen:

  • token/callback en vereiste claims;
  • Users.ExternalId;
  • Users.IsActive;
  • Users.LastSeenAtUtc;
  • actieve UserRoles en Roles;
  • UserSettings;
  • toegankelijkheidsinstellingen;
  • verplichte profiel- of niveaucontext;
  • veilige terugkeerroute;
  • passende frontpage- of vervolgroute.

Clientstate, routeparameters, oude browsercontext, bookmarks of formulierwaarden mogen geen rolcontext, frontendcontext of terugkeerroute afdwingen.

Een oorspronkelijke terugkeerroute mag alleen worden gebruikt wanneer de gebruiker na server-side contextbepaling toegang heeft tot die route. Anders wordt de gebruiker naar de passende veilige context geleid.

5.6 Geen rol of onvolledige accountcontext

Een geauthenticeerde gebruiker kan intern wel bekend en actief zijn, maar nog geen bruikbare OefenHub-context hebben.

SituatieFunctioneel gedrag
Geen actieve rolcontextGebruiker krijgt de beperkte geauthenticeerde context zonder rol.
Alleen inactieve of onbruikbare rollenSysteem behandelt dit als geen geldige rolcontext.
Ontbrekende verplichte profielgegevensGebruiker wordt naar de daarvoor bedoelde profielaanvulling geleid.
Ontbrekend verplicht niveauGebruiker wordt naar de verplichte niveauflow geleid.
Ontbrekende UserSettings bij geldig actief accountSysteem mag UserSettings veilig initialiseren met toegestane defaults.
UserSettings niet veilig initialiseerbaarReguliere contextopbouw wordt geblokkeerd en technisch gelogd.

Een ontbrekend verplicht niveau mag niet automatisch met een willekeurige standaardwaarde worden ingevuld.

Systeemnotificaties blokkeren deze accountcontextbepaling niet. Zij worden pas gecontroleerd nadat een frontpage of passende contextweergave succesvol geladen is.

5.7 Profiel

Een gebruiker kan het eigen OefenHub-profiel bekijken en bewerkbare profielvelden wijzigen.

Profielbeheer werkt altijd vanuit de server-side sessiecontext van de ingelogde gebruiker. Routeparameters, formulierwaarden of client-side identifiers mogen nooit bepalen welk gebruikersprofiel als “eigen profiel” wordt gelezen of gewijzigd.

Beheerbare profielonderdelen zijn onder meer:

  • voornaam;
  • tussenvoegsel;
  • achternaam;
  • weergavenaam voor OefenHub-context;
  • actieve niveaucontext waar functioneel toegestaan;
  • profielfoto uit vooraf gedefinieerde profielavatars.

Avatarweergave is centraal gedrag. Pagina's, kaarten, relatieoverzichten en profielmenu's vragen een avatarpresentatie op en bouwen niet zelf opnieuw initialen, kleuren, afbeelding- of toekomstige samengestelde avatarlogica op. De locatie bepaalt hoogstens formaat, toegankelijk label en CSS-variant; de inhoudelijke avatarvorm blijft uitbreidbaar vanuit één centrale service.

Profielmutaties mogen uitsluitend eigen profielvelden en toegestane profielinstellingen wijzigen. Zij wijzigen geen:

  • rollen;
  • relaties;
  • autorisaties;
  • berichten;
  • meldingen;
  • oefenresultaten;
  • niveauautorisaties;
  • live-meekijkrechten;
  • identity-providercredentials.

5.8 E-mailadres en wachtwoord

E-mailadres en wachtwoord hebben een bijzondere positie.

OefenHub kan een e-mailadres functioneel tonen of gebruiken voor uitnodigings- en accountcontext, maar de credential- en verificatiekant blijft eigendom van de identity provider.

Daarom geldt:

  • wachtwoorden worden nooit in OefenHub verwerkt of opgeslagen;
  • wachtwoord wijzigen loopt via de identity-providerflow;
  • wachtwoord vergeten / reset loopt via de identity-providerflow;
  • e-mailadres wijzigen is geen gewone OefenHub-profielmutatie;
  • OefenHub mag hoogstens doorverwijzen naar de gekoppelde identity-provideromgeving;
  • wijzigingen in identity-providergegevens mogen pas effect hebben in OefenHub wanneer de applicatiecontext server-side veilig opnieuw bepaald is.

5.9 Verplicht niveau

Voor gebruikers waarvoor een actief niveau functioneel verplicht is, leidt het ontbreken van een geldig niveau tot een gerichte attenderings- of blokkadesituatie.

De gekozen niveaucontext moet server-side worden gevalideerd tegen de actuele toegestane niveaucontext van de gebruiker.

Het instellen of wijzigen van de actieve niveaucontext:

  • wijzigt geen docent-leerlingrelatie;
  • kent geen nieuwe niveauautorisatie toe;
  • maakt geen oefening toegankelijk zonder onderliggende autorisatie;
  • mag geen oude clientselectie als bron van waarheid gebruiken.

Wanneer de gebruiker het profiel wil verlaten zonder verplicht niveau in te stellen, volgt de daarvoor bedoelde profiel- of popupafhandeling.

5.10 Profielfoto

De profielfoto is geen vrije upload.

Gebruikers kiezen uit vooraf gedefinieerde actieve profielafbeeldingen. Hierdoor blijft de applicatie beschermd tegen ongewenste, onveilige of ongepaste uploads.

Voor profielfoto’s geldt:

  • keuze alleen uit actieve ProfileAvatars;
  • geen vrije upload;
  • geen externe avatar-URL;
  • server-side validatie van de gekozen avatar;
  • historisch gekozen avatars blijven herleidbaar wanneer zij later inactief worden;
  • nieuwe keuzes mogen alleen uit actieve avatars komen.

5.11 Toegankelijkheid

Toegankelijkheidsinstellingen verbeteren leesbaarheid en bediening binnen OefenHub.

Ondersteunde instellingen zijn minimaal:

  • verhoogd contrast / leesbaarheid;
  • dyslexielettertype;
  • vergroten of verkleinen van standaard lettergrootte.

Na login zijn de waarden in het profiel- of UserSettings-domein de primaire bron van waarheid.

Een technische cookie of vergelijkbare browserwaarde mag toegankelijkheidskeuzes al vóór login toepassen, maar vormt geen tweede bron van waarheid. Deze browserwaarde mag geen persoonsgegevens, identity-providerinformatie, rolcontext, autorisatiedata of profielgegevens bevatten.

Bij login worden de profielwaarden leidend. Waar nodig worden de relevante waarden opnieuw naar de browserwaarde gespiegeld.

Ontbrekende, corrupte of onbekende browserwaarden worden veilig genegeerd en veroorzaken geen fouttoestand.

Wanneer de toegankelijkheidsfeature sitebreed is uitgeschakeld:

  • wordt de toegankelijkheidspagina niet als reguliere optie aangeboden;
  • worden opgeslagen toegankelijkheidswaarden functioneel genegeerd;
  • blijven bestaande gebruikerswaarden bewaard;
  • worden de waarden opnieuw relevant zodra de feature weer actief is.

5.12 Voorkeuren

Voorkeuren zijn algemene of rolgebonden instellingen die presentatiegedrag of gebruikersgedrag beïnvloeden.

Voorbeelden zijn:

  • naamweergave in docent- of ouder-/voogdoverzichten;
  • sorteervoorkeuren;
  • verborgen waarschuwingen zoals “Waarschuw me niet weer” bij Geen idee;
  • andere niet-profielgebonden presentatiekeuzes.

Voorkeuren wijzigen nooit:

  • autorisaties;
  • rollen;
  • relaties;
  • niveauautorisaties;
  • zichtbare gegevenssets;
  • domeintoegang;
  • oefenresultaten;
  • berichten of meldingen.

Rolgebonden voorkeuren mogen alleen worden getoond en opgeslagen wanneer de gebruiker de betreffende rolcontext daadwerkelijk bezit. Een rolgebonden voorkeur verandert uitsluitend presentatie binnen die rolcontext.

Verborgen of systeemgestuurde voorkeuren worden niet automatisch als vrij bewerkbare velden op de voorkeurenpagina getoond.

Alle voorkeuren worden server-side gevalideerd op sleutel, type, waardebereik, beheerbaarheid en eventuele rolcontext.

5.13 Accountverwijdering door gebruiker

Selfservice-accountverwijdering is een gebruikersflow voor het eigen interne OefenHub-account.

De gebruiker kan hiermee:

  • geen account van een andere gebruiker verwijderen;
  • geen identity-provideraccount verwijderen;
  • geen wachtwoord- of credentialstatus wijzigen;
  • geen losse domeinobjecten handmatig selecteren voor verwijdering.

Na definitieve bevestiging start OefenHub de interne anonimiseer- en opruimflow. Er bestaat voor eindgebruikers geen aparte tussenstatus waarin het account wel verwijderd maar nog niet geanonimiseerd is.

Na succesvolle verwerking:

  • wordt reguliere OefenHub-toegang beëindigd;
  • wordt de lokale applicatiesessie beëindigd;
  • worden persoonsgegevens geanonimiseerd volgens de vastgestelde regels;
  • worden afhankelijke actieve relaties en toegang administratief opgeruimd;
  • blijft historie behouden waar dat functioneel, auditmatig of administratief nodig is.

5.14 Functionele retentie bij accountverwijdering

Accountverwijdering binnen OefenHub betekent functioneel niet dat alle domeinrecords hard worden verwijderd. De verwijderflow beëindigt reguliere toegang en start anonimisering, terwijl historische records waar nodig beschikbaar blijven binnen hun eigen autorisatie-, retentie- en auditregels.

DomeinFunctionele regel na accountverwijdering of anonimisering
Account en profielActuele persoonsgegevens worden verwijderd, vervangen of gemaskeerd volgens de accountregels. Het interne account blijft waar nodig als geanonimiseerde historische referentie bestaan.
Rollen en sessiesActieve rollen, sessies en frontendcontexten zijn niet langer bruikbaar. Oude clientstate of bookmarks mogen geen toegang herstellen.
Relaties en uitnodigingenActieve relaties worden administratief beëindigd of niet langer autoriserend gemaakt. Open uitnodigingen van of naar het account worden niet langer accepteerbaar.
Oefenruns en resultatenHistorische oefenruns, resultaten, gedeelde-oefeningcontext en PDF-brondata worden niet blind verwijderd. Zij blijven reconstructeerbaar waar dat functioneel nodig is, zonder actuele persoonsgegevens van het geanonimiseerde account te tonen.
BerichtenPrivéberichtdeelname en mailboxzichtbaarheid van het verwijderde account worden beëindigd volgens de berichtregels. Threadinhoud van andere deelnemers wordt niet generiek verwijderd.
Meldingen en ticketsMeldingen, externe discussie, sluitingen, heropenverzoeken en history blijven waar nodig raadpleegbaar voor bevoegde beheerders, maar tonen geen actuele persoonsgegevens van het geanonimiseerde account.
Audit en lifecyclelogAudit-, history- en lifecyclelagen blijven herleidbaar voor toegestane beheer- en reconstructiedoeleinden, maar mogen geen onnodige actuele persoonsgegevens blijven tonen.

Exacte juridische bewaartermijnen, backupretentie, fysieke opslagverwijdering en technische cleanupjobs horen niet in dit FO-hoofdstuk. Het FO legt hier de functionele zichtbaarheid, autorisatie en historische reconstructie vast.

5.15 Accountanonimisering en afhankelijke toegang

Accountanonimisering is een interne vervolgverwerking na een definitieve en geautoriseerde verwijdertrigger.

Bij anonimisering worden zichtbare persoonsgegevens vervangen door systeemwaarden. De geanonimiseerde identiteit blijft functioneel bruikbaar voor historische reconstructie zonder actuele persoonsgegevens te tonen.

De verwerking raakt onder meer:

  • Users;
  • UserRoles;
  • UserSettings;
  • actieve relaties;
  • openstaande relatie-uitnodigingen;
  • docent-leerlingtoegang;
  • ouder-/voogdcontext;
  • collaboratorrechten;
  • docentniveau-eigenaarschap;
  • privéberichtdeelname;
  • meldingen en ticketcontext;
  • oefenruns en gedeelde oefeningen;
  • live-meekijksessies;
  • audit- en historylagen.

Anonimisering mag bestaande domeinhistorie niet zodanig herschrijven dat resultaten, meldingen, beheeracties of gedeelde oefeningen functioneel onverklaarbaar worden. Waar een gebruikersnaam, e-mailadres of profielgegeven niet meer getoond mag worden, gebruikt OefenHub een geanonimiseerde weergave of systeemlabel.

Voor zichtbare accountidentiteit gelden bij anonimisering vaste systeemwaarden. Deze waarden zijn functioneel relevant omdat zij in geschiedenis, meldingen, auditweergaven en beheercontexten kunnen terugkomen zonder actuele persoonsgegevens te tonen.

ProfielveldFunctionele anonimisering
VoornaamAnoniem
Tussenvoegsel#, gereserveerd voor systeemgebruik
AchternaamKorte niet-voorspelbare systeemcode
E-mailadresSysteemadres volgens anoniem.<code>@verwijderd.acc

De waarde # mag niet via normale profielinvoer als regulier tussenvoegsel worden opgeslagen. De anonieme systeemcode mag niet voorspelbaar of persoonsherleidbaar zijn en mag niet botsen met bestaande accountidentiteit.

Wanneer een docent eigenaar is van een niveau, moet vóór afronding van de anonimisering een geldig opvolgscenario bestaan:

SituatieAfhandeling
Geen actieve collaboratorNiveau wordt historisch of inactief gemaakt volgens domeinregels.
Eén actieve collaboratorEigenaarschap mag automatisch aan die collaborator worden overgedragen.
Meerdere actieve collaboratorsEr moet eerst een geldige opvolgende eigenaar worden gekozen.

Accountanonimisering moet transactioneel of via een gecontroleerde workflow worden bewaakt zodat geen bruikbare half-geanonimiseerde accounttoestand ontstaat. Verplichte account lifecycle-logging moet slagen voordat anonimisering als afgerond wordt beschouwd.

5.16 Beheerdercorrecties op accounts en instellingen

Beheerderaccountbeheer valt buiten de normale eigen-profielusecases, maar raakt hetzelfde account- en gebruikersinstellingendomein.

Een beheerder mag alleen expliciet ondersteunde gebruikersinstellingen corrigeren. Deze correcties mogen geen:

  • wachtwoorden;
  • credentials;
  • identity-providerdata;
  • externe sessies;
  • niet-publieke rollen buiten beheerregels;
  • domeintoegang buiten de daarvoor bedoelde flows

wijzigen.

Accountstatuswijzigingen, rolmutaties, instellingencorrecties en anonimisering moeten herleidbaar zijn via accountgeschiedenis of lifecyclelogging.

5.17 Logout

Bij logout worden de lokale OefenHub-applicatiesessie, beveiligde frontendcontext en realtime context beëindigd.

Logout:

  • wijzigt geen rollen;
  • wijzigt geen relaties;
  • wijzigt geen profielgegevens;
  • wijzigt geen voorkeuren;
  • maakt geen systeemberichten;
  • maakt geen meldingen;
  • rondt geen oefenrun af;
  • verwijdert geen account.

Wanneer federated logout is geconfigureerd, mag OefenHub ook de identity-providerlogoutflow starten. Wanneer identity-providerlogout faalt, blijft de lokale OefenHub-sessie beëindigd.

Toegankelijkheidsbrowserwaarden mogen na logout blijven bestaan wanneer zij uitsluitend presentatie-instellingen bevatten en geen persoonsgegevens, identity-providerinformatie, rolcontext of autorisatiedata.

Wanneer een leerling uitlogt tijdens een niet-afgeronde oefenrun, wordt die run niet als afgerond gemarkeerd en ontstaat geen resultaat. Eventuele live-meekijkcontexten worden beëindigd volgens de live-meekijkregels.

Na logout mogen browsergeschiedenis, oude tabs, oude clientstate of directe API-/SignalR-aanroepen geen toegang meer geven tot beveiligde OefenHub-data.

5.18 Gerelateerde bronverwijzingen

BronLink
Technisch Ontwerp — identiteitIdentiteit, authenticatie en rolcontext
Technisch Ontwerp — autorisatieAutorisatie, policies en server-side contextcontrole
Technisch Ontwerp — privacy en anonimiseringPrivacy, retentie, anonimisering en gegevensbescherming
Usecases — accounttoegang en lifecycleAccounttoegang en account lifecycle
UC-GEN-ACC-001 — Eerste login en account provisioningEerste login en account provisioning
UC-GEN-ACC-002 — Inloggen en sessie verwerkenInloggen en sessie verwerken
UC-GEN-ACC-003 — Geen rol of onvolledig account afhandelenGeen rol of onvolledig account afhandelen
UC-GEN-ACC-004 — Account verwijderen aanvragenAccount verwijderen aanvragen
UC-GEN-ACC-005 — Account anonimiseren en afhankelijke toegang opruimenAccount anonimiseren en afhankelijke toegang opruimen
UC-GEN-ACC-006 — Uitloggen en sessie beëindigenUitloggen en sessie beëindigen
Usecases — profiel, voorkeuren en toegankelijkheidProfiel, voorkeuren en toegankelijkheid
UC-GEN-PROF-001 — Profiel bekijkenProfiel bekijken
UC-GEN-PROF-002 — Profielgegevens wijzigenProfielgegevens wijzigen
UC-GEN-PROF-003 — Verplicht niveau instellenVerplicht niveau instellen
UC-GEN-PROF-004 — Profielfoto kiezenProfielfoto kiezen
UC-GEN-PROF-005 — Toegankelijkheidsinstellingen beherenToegankelijkheidsinstellingen beheren
UC-GEN-PROF-006 — Toegankelijkheid vóór en na login synchroniserenToegankelijkheid vóór en na login synchroniseren
UC-GEN-PROF-007 — Voorkeuren beherenVoorkeuren beheren
Schermdocumentatie — profielProfiel
Schermdocumentatie — toegankelijkheidToegankelijkheid
Schermdocumentatie — voorkeurenVoorkeuren
Database-informatie — identiteit en autorisatieIdentiteit en autorisatie
FO — rollen, context en autorisatieRollen, context en autorisatie
FO — applicatieschil, header, footer en navigatieApplicatieschil, header, footer en navigatie

5.x Eerste onboarding en remote-login failures

Eerste onboarding als accountstatus

OefenHub maakt onderscheid tussen een succesvolle externe authenticatie en een afgeronde OefenHub-onboarding. Een gebruiker mag pas normale appnavigatie bereiken wanneer de centrale onboarding-gate alle verplichte stappen heeft afgerond. De afronding wordt vastgelegd op accountniveau met identity.Users.OnboardingCompletedAtUtc.

Deze waarde hoort niet in UserSettings: het is geen voorkeur die een gebruiker zelf mag wijzigen, maar een lifecycle-status van het interne account.

De onboarding-gate verwerkt de stappen server-side in vaste volgorde:

  1. Als de gebruiker nog geen toegestane rol heeft, wordt de rolkeuzepagina getoond.
  2. Als de gebruiker na rolkeuze nog verplichte geclaimde relatie-uitnodigingen heeft, wordt de relatie-uitnodigingen-onboarding getoond.
  3. Als alle verplichte stappen zijn afgerond, vult OefenHub OnboardingCompletedAtUtc en wordt normale navigatie toegestaan.

Latere uitnodigingen na afgeronde onboarding zijn geen verplichte onboardingstap. Zij worden via normale mailbox-, relatiepagina- of notificatieflows afgehandeld.

Remote-login failure handling

OIDC/Keycloak-callbacks zonder geldige OefenHub correlation-context, zoals Correlation failed, mogen nooit als Developer Exception aan gebruikers worden getoond. OefenHub moet deze remote failures veilig afhandelen:

  • technische logging met correlation-id;
  • geen tokens, raw payloads of identity-providerdetails in de gebruikersmelding;
  • veilige Nederlandstalige pagina met uitleg om opnieuw aan te melden of verder te gaan in het venster waar login wel is afgerond;
  • geen succesvolle login accepteren wanneer de OIDC state/correlation niet geldig is.

De configuratiecontrole moet onderscheid maken tussen een oplosbare OefenHub-configuratiefout en een verwachte cross-device/cross-tab OIDC-beperking waarbij de callback in een andere browsercontext geen correlation-cookie heeft.