PostgreSQL read-replicas voor rapportage: houd dashboards snel
Gebruik PostgreSQL read-replicas voor rapportage om dashboards snel te houden en je primaire database te beschermen tegen trage queries, pieken en lock-pressure.

Waarom rapportage je primaire database kan vertragen
Een veelvoorkomend patroon ziet er zo uit: de app voelt de meeste dagen prima aan, maar zodra iemand een dashboard opent beginnen checkouts, logins of supporttools te vertragen. Niets is “down”, maar alles wordt trager. Dat is meestal je primaire database die tegelijkertijd twee verschillende soorten werk moet doen.
Transacties (het dagelijkse appwerk) zijn kort en selectief. Ze lezen of updaten een klein aantal rijen, gebruiken indexen en zijn snel klaar zodat andere verzoeken verder kunnen. Rapportagequeries gedragen zich anders. Ze scannen vaak veel data, joinen meerdere tabellen, sorteren en groeperen resultaten, en berekenen totalen over dagen of maanden. Zelfs wanneer ze schrijfbewerkingen niet direct blokkeren, kunnen ze dezelfde gedeelde resources opsouperen die je app nodig heeft.
Hier zijn de gebruikelijke manieren waarop dashboards een OLTP-database schaden:
- Zware reads concurreren om CPU, geheugen en schijf-I/O
- Grote scans drukken “hete” pagina’s uit de cache, waardoor normale queries langzamer worden
- Grote sorteringen en GROUP BYs schrijven naar schijf en veroorzaken pieken in load
- Langlopende queries vergroten contention en laten pieken langer duren
- Ad hoc filters (datumbereiken, segmenten) maken de load onvoorspelbaar
Een read replica is een aparte PostgreSQL-server die continu data van je primary kopieert en alleen readonly queries kan bedienen. Door PostgreSQL read-replicas voor rapportage te gebruiken, laat je dashboards hun zware werk ergens anders doen, zodat de primary zich kan focussen op snelle transacties.
De verwachting die je vroeg moet vastleggen: replicas helpen bij reads, niet bij writes. Je kunt niet veilig inserts/updates naar een standaard replica sturen, en resultaten kunnen een beetje achterlopen ten opzichte van de primary omdat replicatie tijd kost. Voor veel dashboards is dat een goede ruil: iets minder "verse" cijfers in ruil voor consistente app-prestaties.
Als je interne dashboards bouwt (bijvoorbeeld in AppMaster) past deze scheiding vaak goed: de app blijft naar de primary schrijven, terwijl de rapportage-schermen de replica bevragen.
Hoe read replicas werken in PostgreSQL (in gewone taal)
Een PostgreSQL read replica is een tweede databaseserver die een bijna realtime kopie van je hoofd(primary) database bijhoudt. De primary handelt writes (INSERT, UPDATE, DELETE). De replica dient vooral reads (SELECT), zodat rapportagequeries niet concurreren met dagelijkse transacties.
Primary vs replica in één minuut
Denk aan de primary als de kassamedewerker in een drukke winkel: die moet snel reageren omdat elke verkoop voorraad, betalingen en bestellingen bijwerkt. Een replica is als een display waarop totalen en trends worden getoond. Die kijkt wat de kassa doet en werkt zijn eigen weergave kort daarna bij.
Onder de motorkap kopieert PostgreSQL wijzigingen door een stroom van wat er op de primary veranderd is te verzenden en die op de replica af te spelen. Dat betekent dat de replica dezelfde database-structuur en data krijgt, maar iets achterloopt.
In praktische termen kopieert replicatie:
- Tabeldata (rijen)
- Indexwijzigingen (zodat queries dezelfde indexen kunnen gebruiken)
- Schemawijzigingen (zoals nieuwe kolommen, nieuwe tabellen en veel soorten migraties)
- De meeste andere databaseveranderingen die via normale SQL gebeuren
Wat een replica niet oplost: het maakt zware writes niet ineens goedkoper en het verhelpt geen trage query veroorzaakt door een slecht schema of ontbrekende indexen. Als je dashboardquery een enorme tabel scant op de replica, kan die nog steeds traag zijn. Het zorgt er alleen voor dat die traagheid de checkout niet tegelijk vertraagt.
Daarom zijn PostgreSQL read-replicas voor rapportage populair: ze scheiden OLTP-werk (snel, frequent) van OLAP-achtig werk (langere reads, groeperen en totalen). Als je interne dashboards of adminpanelen bouwt (bijvoorbeeld in AppMaster) is het vaak het eenvoudigst om rapportagepagina’s naar een replica te wijzen.
Veelvoorkomende rapportage-workloads die thuishoren op een replica
Een goede vuistregel: als een query vooral veel data leest om die samen te vatten, is het een sterke kandidaat om op een replica te draaien. Met PostgreSQL read-replicas voor rapportage bescherm je checkoutflows, aanmeldingen en andere transactionele taken tegen het zware werk dat dashboards vaak vereisen.
Het meest voorkomende dashboardpatroon is een groot datumbereik plus een paar filters. "Laatste 90 dagen per regio, product en kanaal" kan gemakkelijk miljoenen rijen raken, ook al toont de uiteindelijke grafiek maar 12 balken. Deze scans kunnen concurreren met je primary database om schijfreads en cache-ruimte.
Workloads die goed passen op een replica
De meeste teams beginnen met het verplaatsen van deze workloads naar de rapportagedatabase:
- Grote joins over meerdere tabellen (orders + items + customers + refunds)
- Aggregaties zoals SUM, COUNT DISTINCT, percentielen, cohortberekeningen
- Langlopende queries die grote resultsets sorteren en groeperen
- Geplande rapporten die elk uur/dag hetzelfde zware werk opnieuw doen
- Exploratieve BI-sessies waarin mensen klikken en variaties opnieuw uitvoeren
Zelfs wanneer een query "read-only" is, kan het CPU, geheugen en I/O opbranden. Grote GROUP BY-operaties kunnen andere queries uit het geheugen duwen. Herhaalde scans kunnen de buffer cache opschudden, waardoor je primary vaker vanaf schijf moet lezen.
Gedrag rond verbindingen is ook belangrijk. Veel BI-tools openen meerdere verbindingen per gebruiker, verversen tegels elke paar minuten en draaien achtergrond-extracts. Dat kan plotselinge pieken in connections en gelijktijdige queries veroorzaken. Een replica geeft die pieken een veiliger plek om te landen.
Een eenvoudig voorbeeld: je operations-dashboard laadt om 9:00 uur en 50 mensen openen het tegelijk. Elke paginaview triggert meerdere widgets en elk widget draait een query met een andere filter. Op de primary kan die burst ordercreatie vertragen. Op een replica kan het dashboard trager of iets achterlopen zijn, maar je transacties blijven snel.
Als je interne dashboards bouwt binnen een platform zoals AppMaster, is het vaak een eenvoudige winst om rapportageschermen naar een replica-verbinding te wijzen, mits iedereen begrijpt dat de data een paar seconden (of minuten) achter kan lopen.
De afweging: versheid versus snelheid (replicatie-lag)
Een read replica houdt dashboards snel omdat hij rapportagequeries van je primary database afhaalt. De kost is dat een replica meestal iets achterloopt. Die vertraging heet replicatie-lag en is de belangrijkste afweging bij PostgreSQL read-replicas voor rapportage.
Wat gebruikers merken is eenvoudig: het "vandaag"-cijfer is wat laag, de nieuwste bestellingen ontbreken, of een grafiek werkt een paar minuten later bij. De meeste mensen vinden het niet erg als een wekelijkse trend 2 minuten verouderd is, maar ze vinden het vervelend als een "betaling net gelukt"-weergave onjuist is.
Lag ontstaat wanneer de primary sneller wijzigingen produceert dan de replica kan ontvangen en afspelen. Veelvoorkomende oorzaken zijn write-bursts (flash sales, imports), beperkte netwerkbandbreedte, trage schijf op de replica, of langlopende queries die CPU en I/O gebruiken terwijl de replica probeert wijzigingen toe te passen.
Een praktische manier om aanvaardbare lag te kiezen is die af te stemmen op de beslissing die het dashboard ondersteunt:
- Executive KPI-dashboards: seconden tot enkele minuten is vaak prima.
- Operationele wachtrijen (shipping, support): streef naar near real time, gewoonlijk seconden.
- Financiële afsluiting of audits: draai op een gecontroleerde snapshot, niet "live".
- Klantgerichte "mijn recente bestellingen": near real time, of gebruik de primary.
Eenvoudige regel: als een rapport de meest recent gecommitte transactie moet bevatten, moet het de primary raken (of een systeem dat gegarandeerde versheid biedt). Typische voorbeelden zijn voorraadbeschikbaarheid tijdens checkout, fraudchecks en alles dat een onmiddellijke actie triggert.
Voorbeeld: een sales-team dashboard kan veilig van een replica lezen en elke minuut verversen. Maar de "orderbevestiging"-pagina moet van de primary lezen, omdat "geen order gevonden" direct na plaatsen een supportticket is dat wacht om te gebeuren.
Als je app of no-code tool je toestaat een databaseverbinding te kiezen (bijvoorbeeld rapportageschermen in AppMaster naar een replica wijzen), kun je deze scheiding toepassen zonder te veranderen hoe je team de UI bouwt.
Stap voor stap: read replicas instellen voor dashboards
Het opzetten van een replica voor dashboards draait grotendeels om een paar duidelijke keuzes vooraf en daarna rapportageverkeer weghouden van je primary database.
1) Begin met de juiste vorm
Begin met topologie. Eén replica is vaak genoeg voor één BI-tool en een paar dashboards. Meerdere replicas helpen wanneer je veel analisten hebt of meerdere tools die de hele dag de data raken. Als je gebruikers ver van je hoofdregio zitten, kan een regionale replica latentie voor dashboards verminderen, maar het voegt ook meer plekken toe om te monitoren.
Kies vervolgens synchronische of asynchrone replicatie. Synchronous geeft de beste versheid maar kan writes vertragen, wat voor veel teams het doel ondermijnt. Asynchronous is de gebruikelijke keuze voor dashboards, zolang iedereen accepteert dat data een beetje achter kan lopen.
2) Bouw de replica als een reporting-server
Een replica is geen goedkope kopie van productie. Rapportagequeries hebben vaak meer CPU nodig, meer geheugen voor sorteringen en snelle schijven voor scans.
Hier is een praktisch stappenplan voor PostgreSQL read-replicas voor rapportage:
- Bepaal hoeveel replicas je nodig hebt en waar ze moeten staan (zelfde regio of dichter bij gebruikers).
- Kies async vs sync op basis van hoeveel vertraging je dashboards kunnen tolereren.
- Voorzie resources voor read-heavy werk (CPU, RAM en disk IOPS zijn meestal belangrijker dan opslaggrootte).
- Maak aparte read-only credentials voor reporting gebruikers en tools.
- Routeer dashboardqueries naar de replica (configureer je app, BI-tool of een kleine reporting-service om de replica-verbinding te gebruiken).
Na het routen, valideer met een simpele test: draai een bekende zware dashboardquery en bevestig dat die niet langer in de activity van de primary verschijnt.
Als je apps bouwt met AppMaster betekent dit meestal het definiëren van een aparte databaseverbinding voor reporting en die alleen voor dashboardendpoints te gebruiken, zodat checkout en andere transactionele flows hun eigen snelle pad houden.
Toegangsbeheer en veiligheid voor reporting-gebruikers
Een read replica is geweldig voor dashboards, maar heeft nog steeds regels nodig. Behandel het als een gedeelde resource: geef reporting-tools net genoeg toegang om hun werk te doen en beperk hoe veel schade een slechte query kan aanrichten.
Begin met een aparte databasegebruiker voor reporting. Hergebruik niet de hoofdcredentials van je app, ook niet als je naar de replica wijst. Dat maakt het eenvoudiger om activiteit te auditen, wachtwoorden te roteren en privileges strak te houden.
Hier is een simpele aanpak die voor de meeste teams past:
-- Create a dedicated login
CREATE ROLE report_user LOGIN PASSWORD '...';
-- Allow read-only access to a schema
GRANT CONNECT ON DATABASE yourdb TO report_user;
GRANT USAGE ON SCHEMA public TO report_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO report_user;
-- Put safety limits on the role
ALTER ROLE report_user SET statement_timeout = '30s';
ALTER ROLE report_user SET idle_in_transaction_session_timeout = '15s';
Vervolgens: controleer connection-stormen. Dashboards en BI-tools openen vaak veel connections, vooral wanneer meerdere widgets tegelijk verversen. Beperk reporting-verbindingen op de database en op je pooler en houd ze gescheiden van transactioneel verkeer.
Een praktische checklist:
- Gebruik een read-only gebruiker (geen INSERT/UPDATE/DELETE, geen schema-wijzigingen).
- Zet per-role timeouts voor lange queries en idle sessies.
- Beperk max connections voor reporting-gebruikers tot een veilig aantal.
- Beperk toegang tot alleen de schema's en tabellen die een dashboard nodig heeft.
- Masker of exclusieer gevoelige kolommen (PII, secrets, tokens) uit reporting-views.
Als je gedeeltelijke klantdata moet tonen, vertrouw dan niet op "mensen zullen voorzichtig zijn". Maak reporting-views die gevoelige velden verbergen of hashen, of onderhoud een gecureerd reporting-schema. Wanneer teams dashboards bouwen met AppMaster, gebruik dan de replica connection string en de dedicated reporting user zodat de gegenereerde app veilig kan lezen zonder productie write-toegang.
Deze controles houden PostgreSQL read-replicas voor rapportage snel, voorspelbaar en veel lastiger om te misbruiken.
Monitoring die verrassingen uit je dashboards houdt
Een replica helpt alleen als hij zich voorspelbaar gedraagt. De twee dingen die teams meestal verrassen zijn stille replicatie-lag (dashboards zien er "fout" uit) en resource-pieken op de replica (dashboards worden traag). Monitoring moet beide vangen voordat je gebruikers het merken.
Begin met het meten van lag en maak afspraken over wat "vers genoeg" betekent voor je business. Voor veel rapportagedashboards is 30 tot 120 seconden prima. Voor anderen (zoals voorraad of fraude) kan zelfs 5 seconden al te veel zijn. Wat je ook kiest, maak het een zichtbare maat en stel alerts in.
Hier zijn praktische signalen om op te letten voor PostgreSQL read-replicas voor rapportage:
- Replicatie-lag (tijd en bytes). Alert wanneer het je drempel overschrijdt voor een paar minuten, niet alleen een enkele spike.
- Replica-gezondheid: CPU, geheugenbelasting en disk read I/O tijdens piekrapportage-uren.
- Connection-saturatie op de replica (te veel dashboard-sessies kunnen lijken op "de database is traag").
- Trage queries op de replica, gebruikmakend van de replica’s eigen statistieken en logs (ga er niet van uit dat de primary het hele verhaal vertelt).
- Autovacuum en bloat op de replica. Reads kunnen degraderen als tabellen of indexen bloat hebben.
Tracking van trage queries verdient speciale aandacht. Een veelvoorkomende fout is een dashboard dat in testen goed werkte maar in productie verandert in een "full table scan festival". Zorg dat de replica dezelfde monitoring heeft als de primary, inclusief top queries op totale tijd en gemiddelde tijd.
Bepaal tenslotte van tevoren wat je app doet wanneer de replica onbeschikbaar is of te ver achterloopt. Kies één gedrag en implementeer het consistent:
- Toon een "data vertraagd" banner wanneer lag boven de drempel is.
- Schakel tijdelijk de zwaarste grafieken uit en toon alleen lichte samenvattingen.
- Val terug op gecachte resultaten voor een vaste periode (bijv. laatste 15 minuten).
- Routeer kritische reads terug naar de primary alleen voor specifieke schermen.
- Zet dashboards in read-only onderhoudsmodus totdat de replica hersteld is.
Als je interne dashboards in AppMaster bouwt, behandel de replica als een aparte datasource: monitor hem apart en ontwerp dashboards die gracieus degraderen wanneer versheid of prestatie daalt.
Veelgemaakte fouten en valkuilen om te vermijden
Een read replica helpt, maar het is geen magische knop om rapportage gratis te maken. De meeste replica-problemen ontstaan door hem te behandelen als een onbeperkt analytics-warehouse en dan verbaasd te zijn wanneer dashboards traag of onjuist worden.
Een gemakkelijke miss: replicas kunnen ook overbelast raken. Een paar brede table scans, zware joins of "SELECT *" exports kunnen CPU en schijf zwaar belasten en timeouts veroorzaken. Als de replica op kleinere hardware draait dan de primary (veel teams doen dit om kosten te besparen), merk je de vertraging nog eerder.
Hier zijn de valkuilen die het meest pijn doen:
- Kritische realtime schermen naar de replica routen. Als een dashboard wordt gebruikt om een net voltooide checkout te bevestigen of live voorraad te tonen, kan replicatie-lag doen lijken alsof data ontbreekt.
- BI-tools teveel connections laten openen. Sommige tools verversen veel tegels tegelijk en elke tegel kan een eigen sessie openen. Connection-pieken kunnen een replica neerhalen zelfs als elke query op zichzelf klein lijkt.
- Denken dat indexen alles oplossen. Een index maakt geen verschil voor een query die miljoenen rijen trekt, groeperen op de verkeerde keys of joinen zonder limieten. Query-vorm en datavolume wegen zwaarder dan een extra index.
- Vergeten dat "snel één keer" niet gelijkstaat aan "snel altijd". Een query die 's ochtends snel draait kan traag worden als data groeit of als meerdere mensen hetzelfde rapport verversen.
- Niet plannen voor failover-gedrag. Tijdens failover kan een replica gepromoveerd worden of vervangen, en clients kunnen read-only fouten of verouderde endpoints raken als je de switch niet plant.
Een realistisch voorbeeld: jouw BI-tool ververses een "vandaag bestellingen"-pagina elke minuut. Als die vijf zware queries per verversing draait en 20 mensen hebben die open, zijn dat 100 zware query-bursts per minuut. De primary kan veilig blijven, maar de replica kan alsnog bezwijken.
Als je interne dashboards bouwt met een platform als AppMaster, behandel de rapportagedatabase als een apart doel met eigen connection-limieten en "vereiste versheid" regels, zodat gebruikers niet per ongeluk afhankelijk worden van verouderde data.
Ontwerppatronen die rapportage op een replica sneller maken
Een read replica geeft je ademruimte, maar maakt niet automatisch elk dashboard snel. Het beste resultaat komt van queries zo te vormen dat ze minder werk doen en voorspelbaarder zijn. Deze patronen werken goed voor PostgreSQL read-replicas voor rapportage omdat ze zware scans en herhaalde aggregatie verminderen.
Scheid de "reporting layer"
Overweeg een dedicated reporting-schema (bijv. reporting) met stabiele views en hulptabellen. Dit voorkomt dat BI-tools en dashboards direct raw transactionele tabellen raken en geeft je één plek om te optimaliseren. Een goede reporting-view verbergt ook rommelige joins zodat de dashboardquery eenvoudig blijft.
Pre-aggregateer het zware werk
Als een dashboard de hele dag dezelfde totalen herberekent (dagelijkse omzet, orders per status, top producten), stop met alles elke keer opnieuw berekenen. Bouw samenvattende tabellen of materialized views die die cijfers al gegroepeerd opslaan.
Veelvoorkomende keuzes:
- Dagelijkse of uurlijkse rollups (per datum, regio, kanaal)
- "Laatst bekende" snapshot-tabellen (voorraad, accountsaldo)
- Top-N tabellen (top producten, top klanten)
- Fact-tabellen met gedenoormaliseerde kolommen voor snellere filtering
Ververs zware metrics volgens schema
Ververs pre-aggregaties met geplande jobs, bij voorkeur buiten piekuren. Als de business het kan doen met "iedere 5 minuten geüpdatet", kun je een kleine vertraging ruilen voor veel snellere dashboards. Voor zeer grote datasets zijn incrementele updates (alleen nieuwe rijen sinds de laatste run) meestal goedkoper dan volledige refreshes.
Cache wat gebruikers vaak klikken
Als dezelfde dashboardwidgets steeds opnieuw worden opgevraagd, cache de resultaten in de app-laag voor een korte tijd (30 tot 120 seconden is vaak genoeg). Bijvoorbeeld, een "Vandaag's omzet" tegel kan per bedrijf of winkel gecachet worden. In tools zoals AppMaster is dit vaak het makkelijkst rond het API-endpoint dat het dashboard voedt toe te voegen.
Eenvoudige regel: als een query traag en populair is, pre-aggregateer hem, cache hem, of beide.
Een realistisch voorbeeld: salesrapportage zonder checkout te vertragen
Stel je een kleine e-commerce app voor. De hoofd-database handelt logins, carts, betalingen en orderupdates de hele dag af. Tegelijk wil het team een dashboard met uuromzet, top producten en refunds.
Voor de verandering draait het dashboard zware queries op de primary database. Rond het einde van de maand opent iemand een "laatste 30 dagen per product"-grafiek en die scant een groot deel van de orders-tabel. Checkout begint traag te voelen omdat die rapportagequeries concurreren om CPU, geheugen en schijfreads.
De oplossing is simpel: verplaats de dashboardreads naar een replica. Met PostgreSQL read-replicas voor rapportage blijft de primary snelle writes doen terwijl de replica lange reads beantwoordt. Het dashboard wijst naar de replica connection string, niet naar de primary.
Het team stelt ook duidelijke versheidsregels zodat niemand perfecte realtime cijfers verwacht:
- Toon "Data bijgewerkt X minuten geleden" op het dashboard
- Sta maximaal 5 minuten vertraging toe tijdens normale uren
- Als lag boven 10 minuten komt, schakelt het dashboard in "vertraagde modus" en pauzeert de zwaarste grafieken
- Houd checkout en orderupdates altijd op de primary
Na de verandering is het resultaat merkbaar. Checkout blijft stabiel, zelfs tijdens rapportagepieken, en grafieken laden sneller omdat ze niet langer vechten met transacties.
Wat gebruikers moeten horen is eenvoudig: het dashboard is "bijna realtime", niet de bron van waarheid voor de laatste 10 seconden. Als iemand exacte totalen voor reconciliatie nodig heeft, moeten ze een geplande export of een eind-van-de-dag rapport draaien.
Als je de app bouwt met een platform zoals AppMaster, behandel reporting vanaf dag één als een aparte read-only verbinding zodat je transactionele flows voorspelbaar blijven.
Snelle checks en volgende stappen
Voordat je dashboards naar een replica wijst, doe een korte sanity-check. Een paar kleine instellingen en gewoonten voorkomen de meest voorkomende verrassingen: verouderde cijfers, timeouts en per ongeluk schrijven.
Hier is een korte checklist om te configureren voordat je verkeer naar een replica stuurt:
- Maak reporting-verbindingen read-only (gebruik een dedicated gebruiker en handhaaf read-only transacties).
- Scheid reporting van app-verkeer (eigen connection pool en redelijke connection-limieten).
- Bevestig dat de replica de indexen heeft waarop je dashboards vertrouwen (replicas kopiëren indexen, maar controleer recente wijzigingen).
- Stel statement- en lock-timeouts in voor reporting-queries zodat één slechte grafiek niet alles ophangt.
- Valideer dat grafieken kleine vertragingen verdragen (toon "as of" timestamps of rond af op minuten waar nodig).
Zodra het verkeer stroomt, behandel monitoring als een lichte wekelijkse routine, niet als een blusoefening. Dit geldt vooral voor PostgreSQL read-replicas voor rapportage, waar "het werkte gisteren" snel kan veranderen als datavolume groeit.
Wekelijkse monitoring-checklist (10 minuten):
- Replicatie-lag: bekijk de typische lag en de ergste pieken tijdens piekuren.
- Trage queries: volg top-offenders op totale tijd, niet alleen individuele trage runs.
- Verbindingen: controleer max connections, pool-saturatie en opgestapelde idle connections.
- Schijf en CPU: replicas kunnen bottlenecken op opslag krijgen tijdens zware scans.
- Mislukte queries: kijk naar timeouts, gecancelde statements of permissiefouten.
Volgende stappen gaan vooral over routeringsregels en een fallback-plan. Bepaal welke endpoints altijd veilig zijn om van de replica te lezen (dashboards, exports, admin-rapporten) en welke op de primary moeten blijven (alles dat up-to-the-second moet zijn). Definieer wat er gebeurt wanneer lag je limiet overschrijdt: toon een waarschuwing, schakel voor een subset van pagina’s terug naar de primary, of schakel tijdelijk de zwaarste grafieken uit.
Als je interne dashboards of admin-tools bouwt, kan AppMaster een praktische manier zijn om ze snel uit te rollen terwijl je rapportageschermen naar een replica wijst zodat je kern transactionele app soepel blijft draaien.


