mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
1 line
94 KiB
XML
1 line
94 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" data-diagram-type="CLASS" height="1484px" preserveAspectRatio="none" style="width:6292px;height:1484px;background:#FAFCF9;" version="1.1" viewBox="0 0 6292 1484" width="6292px" zoomAndPan="magnify"><?plantuml 1.2026.3?><defs/><g><rect fill="#FAFCF9" height="1484" style="stroke:none;stroke-width:1;" width="6292" x="0" y="0"/><g class="title" data-source-line="25"><text fill="#28342A" font-family="'Volkhov'" font-size="20" font-weight="700" lengthAdjust="spacing" textLength="443.18" x="2921.1187" y="29.42">The Biergarten Data Pipeline - Class Diagram</text></g><!--class BiergartenPipelineOrchestrator--><g class="entity" data-qualified-name="BiergartenPipelineOrchestrator" data-source-line="27" id="ent0002"><rect fill="#FAFCF9" height="299.42" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="441.7737" x="3524.45" y="53.8"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="441.7737" x="3524.45" y="53.8"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="441.7737" x="3524.45" y="79.528"/><rect fill="none" height="299.42" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="441.7737" x="3524.45" y="53.8"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="201.9644" x="3644.3547" y="72.688">BiergartenPipelineOrchestrator</text><line style="stroke:#547461;stroke-width:0.5;" x1="3525.45" x2="3965.2237" y1="82.028" y2="82.028"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="93.642"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="223.0099" x="3543.45" y="99.916">logger_ : std::shared_ptr<ILogger></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="111.87"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="366.6779" x="3543.45" y="118.144">context_service_ : std::unique_ptr<IEnrichmentService></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="130.098"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="294.8859" x="3543.45" y="136.372">generator_ : std::unique_ptr<DataGenerator></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="148.326"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="284.2809" x="3543.45" y="154.6">exporter_ : std::unique_ptr<IExportService></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="166.554"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="415.2299" x="3543.45" y="172.828">curated_data_service_ : std::unique_ptr<ICuratedDataService></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="184.782"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="399.3924" x="3543.45" y="191.056">postal_code_service_ : std::unique_ptr<IPostalCodeService></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="203.01"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="276.4022" x="3543.45" y="209.284">application_options_ : ApplicationOptions</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="221.238"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="343.9246" x="3543.45" y="227.512">generated_breweries_ : std::vector<BreweryRecord></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="239.466"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="291.2669" x="3543.45" y="245.74">generated_users_ : std::vector<UserRecord></text><line style="stroke:#547461;stroke-width:0.5;" x1="3525.45" x2="3965.2237" y1="254.08" y2="254.08"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3535.45" cy="268.694" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="73.5806" x="3543.45" y="271.968">Run() : bool</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="283.922"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="302.8519" x="3543.45" y="290.196">QueryCitiesWithCountries() : std::vector<City></text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="302.15"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="416.7737" x="3543.45" y="308.424">GenerateBreweries(cities : std::span<const EnrichedCity>) : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="320.378"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="389.4247" x="3543.45" y="326.652">GenerateUsers(cities : std::span<const EnrichedCity>) : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3532.45" y="338.606"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="118.9687" x="3543.45" y="344.88">LogResults() : void</text></g><!--class LogLevel--><g class="entity" data-qualified-name="LogLevel" data-source-line="44" id="ent0003"><rect fill="#FAFCF9" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="97.144" x="2432.77" y="1307.17"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="97.144" x="2432.77" y="1307.17"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="97.144" x="2432.77" y="1351.126"/><rect fill="none" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="97.144" x="2432.77" y="1307.17"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="95.144" x="2433.77" y="1326.058">«enumeration»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="57.2636" x="2452.7102" y="1344.286">LogLevel</text><line style="stroke:#547461;stroke-width:0.5;" x1="2433.77" x2="2528.914" y1="1353.626" y2="1353.626"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="42.1925" x="2438.77" y="1371.514">Debug</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="24.3636" x="2438.77" y="1389.742">Info</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.3736" x="2438.77" y="1407.97">Warn</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="31.7487" x="2438.77" y="1426.198">Error</text><line style="stroke:#547461;stroke-width:0.5;" x1="2433.77" x2="2528.914" y1="1434.538" y2="1434.538"/></g><!--class PipelinePhase--><g class="entity" data-qualified-name="PipelinePhase" data-source-line="51" id="ent0004"><rect fill="#FAFCF9" height="190.052" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="193.3283" x="2578.68" y="1279.83"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="193.3283" x="2578.68" y="1279.83"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="193.3283" x="2578.68" y="1323.786"/><rect fill="none" height="190.052" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="193.3283" x="2578.68" y="1279.83"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="95.144" x="2627.7721" y="1298.718">«enumeration»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="89.4356" x="2630.6264" y="1316.946">PipelinePhase</text><line style="stroke:#547461;stroke-width:0.5;" x1="2579.68" x2="2771.0083" y1="1326.286" y2="1326.286"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="48.6816" x="2584.68" y="1344.174">Startup</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="101.8642" x="2584.68" y="1362.402">UserGeneration</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="181.3283" x="2584.68" y="1380.63">BreweryAndBeerGeneration</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="125.0097" x="2584.68" y="1398.858">CheckinGeneration</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="113.1377" x="2584.68" y="1417.086">RatingGeneration</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="113.5472" x="2584.68" y="1435.314">FollowGeneration</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="64.3931" x="2584.68" y="1453.542">Teardown</text><line style="stroke:#547461;stroke-width:0.5;" x1="2579.68" x2="2771.0083" y1="1461.882" y2="1461.882"/></g><!--class LogDTO--><g class="entity" data-qualified-name="LogDTO" data-source-line="61" id="ent0005"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="164.1286" x="2363.28" y="1073.57"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="164.1286" x="2363.28" y="1073.57"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="164.1286" x="2363.28" y="1099.298"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="164.1286" x="2363.28" y="1073.57"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="51.8139" x="2419.4373" y="1092.458">LogDTO</text><line style="stroke:#547461;stroke-width:0.5;" x1="2364.28" x2="2526.4086" y1="1101.798" y2="1101.798"/><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2374.28" cy="1116.412" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="97.0657" x="2382.28" y="1119.686">level : LogLevel</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2374.28" cy="1134.64" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="139.1286" x="2382.28" y="1137.914">phase : PipelinePhase</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2374.28" cy="1152.868" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="131.9748" x="2382.28" y="1156.142">message : std::string</text><line style="stroke:#547461;stroke-width:0.5;" x1="2364.28" x2="2526.4086" y1="1164.482" y2="1164.482"/></g><!--class LogEntry--><g class="entity" data-qualified-name="LogEntry" data-source-line="67" id="ent0006"><rect fill="#FAFCF9" height="153.596" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="353.9828" x="2562.35" y="1046.23"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="353.9828" x="2562.35" y="1046.23"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="353.9828" x="2562.35" y="1071.958"/><rect fill="none" height="153.596" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="353.9828" x="2562.35" y="1046.23"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="57.8762" x="2710.4033" y="1065.118">LogEntry</text><line style="stroke:#547461;stroke-width:0.5;" x1="2563.35" x2="2915.3328" y1="1074.458" y2="1074.458"/><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1089.072" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="328.9828" x="2581.35" y="1092.346">timestamp : std::chrono::system_clock::time_point</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1107.3" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="179.2073" x="2581.35" y="1110.574">origin : std::source_location</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1125.528" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="162.4842" x="2581.35" y="1128.802">thread_id : std::thread::id</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1143.756" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="97.0657" x="2581.35" y="1147.03">level : LogLevel</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1161.984" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="139.1286" x="2581.35" y="1165.258">phase : PipelinePhase</text><g data-visibility-modifier="PUBLIC_FIELD"><ellipse cx="2573.35" cy="1180.212" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="131.9748" x="2581.35" y="1183.486">message : std::string</text><line style="stroke:#547461;stroke-width:0.5;" x1="2563.35" x2="2915.3328" y1="1191.826" y2="1191.826"/></g><!--class ILogger--><g class="entity" data-qualified-name="ILogger" data-source-line="76" id="ent0007"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="218.438" x="2808.12" y="451.44"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="218.438" x="2808.12" y="451.44"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="218.438" x="2808.12" y="495.396"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="218.438" x="2808.12" y="451.44"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="2881.765" y="470.328">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="47.684" x="2893.497" y="488.556">ILogger</text><line style="stroke:#547461;stroke-width:0.5;" x1="2809.12" x2="3025.558" y1="497.896" y2="497.896"/><line style="stroke:#547461;stroke-width:0.5;" x1="2809.12" x2="3025.558" y1="505.896" y2="505.896"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="2819.12" cy="520.51" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="186.0882" x="2827.12" y="523.784">Log(payload : LogDTO) : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="2816.12" y="535.738"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="193.438" x="2827.12" y="542.012">DoLog(entry : LogEntry) : void</text></g><!--class LogProducer--><g class="entity" data-qualified-name="LogProducer" data-source-line="81" id="ent0008"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="290.0167" x="2354.33" y="767.07"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="290.0167" x="2354.33" y="767.07"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="290.0167" x="2354.33" y="792.798"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="290.0167" x="2354.33" y="767.07"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="83.0307" x="2457.823" y="785.958">LogProducer</text><line style="stroke:#547461;stroke-width:0.5;" x1="2355.33" x2="2643.3467" y1="795.298" y2="795.298"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="2362.33" y="806.912"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="265.0167" x="2373.33" y="813.186">channel_ : BoundedChannel<LogEntry>&</text><line style="stroke:#547461;stroke-width:0.5;" x1="2355.33" x2="2643.3467" y1="821.526" y2="821.526"/><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="2362.33" y="833.14"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="192.5179" x="2373.33" y="839.414">DoLog(entry : LogEntry) : void</text></g><!--class LogDispatcher--><g class="entity" data-qualified-name="LogDispatcher" data-source-line="86" id="ent0009"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="329.9764" x="2679.35" y="757.95"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="329.9764" x="2679.35" y="757.95"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="329.9764" x="2679.35" y="783.678"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="329.9764" x="2679.35" y="757.95"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="94.5561" x="2797.0601" y="776.838">LogDispatcher</text><line style="stroke:#547461;stroke-width:0.5;" x1="2680.35" x2="3008.3264" y1="786.178" y2="786.178"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="2687.35" y="797.792"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="265.0167" x="2698.35" y="804.066">channel_ : BoundedChannel<LogEntry>&</text><line style="stroke:#547461;stroke-width:0.5;" x1="2680.35" x2="3008.3264" y1="812.406" y2="812.406"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="2690.35" cy="827.02" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="72.8876" x="2698.35" y="830.294">Run() : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="2687.35" y="842.248"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="304.9764" x="2698.35" y="848.522">ToSpdlogLevel(level) : spdlog::level::level_enum</text></g><!--class IEnrichmentService--><g class="entity" data-qualified-name="IEnrichmentService" data-source-line="92" id="ent0010"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="349.5241" x="3409.58" y="460.56"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="349.5241" x="3409.58" y="460.56"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="349.5241" x="3409.58" y="504.516"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="349.5241" x="3409.58" y="460.56"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="3548.7681" y="479.448">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="125.692" x="3521.4961" y="497.676">IEnrichmentService</text><line style="stroke:#547461;stroke-width:0.5;" x1="3410.58" x2="3758.1041" y1="507.016" y2="507.016"/><line style="stroke:#547461;stroke-width:0.5;" x1="3410.58" x2="3758.1041" y1="515.016" y2="515.016"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3420.58" cy="529.63" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="324.5241" x="3428.58" y="532.904">GetLocationContext(loc : const City&) : std::string</text></g><!--class MockEnrichmentService--><g class="entity" data-qualified-name="MockEnrichmentService" data-source-line="96" id="ent0011"><rect fill="#FAFCF9" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="349.5241" x="3501.58" y="776.18"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="349.5241" x="3501.58" y="776.18"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="349.5241" x="3501.58" y="801.908"/><rect fill="none" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="349.5241" x="3501.58" y="776.18"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="157.5527" x="3597.5657" y="795.068">MockEnrichmentService</text><line style="stroke:#547461;stroke-width:0.5;" x1="3502.58" x2="3850.1041" y1="804.408" y2="804.408"/><line style="stroke:#547461;stroke-width:0.5;" x1="3502.58" x2="3850.1041" y1="812.408" y2="812.408"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3512.58" cy="827.022" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="324.5241" x="3520.58" y="830.296">GetLocationContext(loc : const City&) : std::string</text></g><!--class WikipediaEnrichmentService--><g class="entity" data-qualified-name="WikipediaEnrichmentService" data-source-line="100" id="ent0012"><rect fill="#FAFCF9" height="117.14" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="422.6147" x="3044.03" y="748.84"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="422.6147" x="3044.03" y="748.84"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="422.6147" x="3044.03" y="774.568"/><rect fill="none" height="117.14" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="422.6147" x="3044.03" y="748.84"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="186.1932" x="3162.2407" y="767.728">WikipediaEnrichmentService</text><line style="stroke:#547461;stroke-width:0.5;" x1="3045.03" x2="3465.6447" y1="777.068" y2="777.068"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3052.03" y="788.682"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="238.9101" x="3063.03" y="794.956">client_ : std::unique_ptr<WebClient></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3052.03" y="806.91"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="397.6147" x="3063.03" y="813.184">extract_cache_ : std::unordered_map<std::string, std::string></text><line style="stroke:#547461;stroke-width:0.5;" x1="3045.03" x2="3465.6447" y1="821.524" y2="821.524"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3055.03" cy="836.138" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="324.5241" x="3063.03" y="839.412">GetLocationContext(loc : const City&) : std::string</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3052.03" y="851.366"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="318.5638" x="3063.03" y="857.64">FetchExtract(query : std::string_view) : std::string</text></g><!--class WebClient--><g class="entity" data-qualified-name="WebClient" data-source-line="107" id="ent0013"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="335.0342" x="3087.82" y="1073.57"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="335.0342" x="3087.82" y="1073.57"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="335.0342" x="3087.82" y="1117.526"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="335.0342" x="3087.82" y="1073.57"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="3219.7631" y="1092.458">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="68.222" x="3221.2261" y="1110.686">WebClient</text><line style="stroke:#547461;stroke-width:0.5;" x1="3088.82" x2="3421.8542" y1="1120.026" y2="1120.026"/><line style="stroke:#547461;stroke-width:0.5;" x1="3088.82" x2="3421.8542" y1="1128.026" y2="1128.026"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3098.82" cy="1142.64" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="249.8552" x="3106.82" y="1145.914">Get(url : const std::string&) : std::string</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3098.82" cy="1160.868" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="310.0342" x="3106.82" y="1164.142">UrlEncode(value : const std::string&) : std::string</text></g><!--class HttpWebClient--><g class="entity" data-qualified-name="HttpWebClient" data-source-line="112" id="ent0014"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="335.0342" x="3087.82" y="1334.51"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="335.0342" x="3087.82" y="1334.51"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="335.0342" x="3087.82" y="1360.238"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="335.0342" x="3087.82" y="1334.51"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="97.5276" x="3206.5733" y="1353.398">HttpWebClient</text><line style="stroke:#547461;stroke-width:0.5;" x1="3088.82" x2="3421.8542" y1="1362.738" y2="1362.738"/><line style="stroke:#547461;stroke-width:0.5;" x1="3088.82" x2="3421.8542" y1="1370.738" y2="1370.738"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3098.82" cy="1385.352" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="249.8552" x="3106.82" y="1388.626">Get(url : const std::string&) : std::string</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3098.82" cy="1403.58" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="310.0342" x="3106.82" y="1406.854">UrlEncode(value : const std::string&) : std::string</text></g><!--class DataGenerator--><g class="entity" data-qualified-name="DataGenerator" data-source-line="117" id="ent0015"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="717.8332" x="3794.42" y="451.44"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="717.8332" x="3794.42" y="451.44"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="717.8332" x="3794.42" y="495.396"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="717.8332" x="3794.42" y="451.44"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="4117.7626" y="470.328">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="97.062" x="4104.8056" y="488.556">DataGenerator</text><line style="stroke:#547461;stroke-width:0.5;" x1="3795.42" x2="4511.2532" y1="497.896" y2="497.896"/><line style="stroke:#547461;stroke-width:0.5;" x1="3795.42" x2="4511.2532" y1="505.896" y2="505.896"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3805.42" cy="520.51" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="599.0823" x="3813.42" y="523.784">GenerateBrewery(location : const City&, region_context : const std::string&) : BreweryResult</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3805.42" cy="538.738" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="692.8332" x="3813.42" y="542.012">GenerateUser(city : const EnrichedCity&, persona : const UserPersona&, name : const Name&) : UserResult</text></g><!--class MockGenerator--><g class="entity" data-qualified-name="MockGenerator" data-source-line="122" id="ent0016"><rect fill="#FAFCF9" height="117.14" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="717.8332" x="4317.42" y="748.84"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="717.8332" x="4317.42" y="748.84"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="717.8332" x="4317.42" y="774.568"/><rect fill="none" height="117.14" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="717.8332" x="4317.42" y="748.84"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="101.4686" x="4625.6023" y="767.728">MockGenerator</text><line style="stroke:#547461;stroke-width:0.5;" x1="4318.42" x2="5034.2532" y1="777.068" y2="777.068"/><line style="stroke:#547461;stroke-width:0.5;" x1="4318.42" x2="5034.2532" y1="785.068" y2="785.068"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="4328.42" cy="799.682" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="599.0823" x="4336.42" y="802.956">GenerateBrewery(location : const City&, region_context : const std::string&) : BreweryResult</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="4328.42" cy="817.91" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="692.8332" x="4336.42" y="821.184">GenerateUser(city : const EnrichedCity&, persona : const UserPersona&, name : const Name&) : UserResult</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="4325.42" y="833.138"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="319.7045" x="4336.42" y="839.412">DeterministicHash(location : const City&) : size_t</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="4325.42" y="851.366"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="662.754" x="4336.42" y="857.64">DeterministicHash(location : const City&, persona : const UserPersona&, name : const Name&) : size_t</text></g><!--class LlamaGenerator--><g class="entity" data-qualified-name="LlamaGenerator" data-source-line="129" id="ent0017"><rect fill="#FAFCF9" height="226.508" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="397.138" x="3885.77" y="694.15"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="397.138" x="3885.77" y="694.15"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="397.138" x="3885.77" y="719.878"/><rect fill="none" height="226.508" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="397.138" x="3885.77" y="694.15"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="104.5242" x="4032.0769" y="713.038">LlamaGenerator</text><line style="stroke:#547461;stroke-width:0.5;" x1="3886.77" x2="4281.908" y1="722.378" y2="722.378"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="733.992"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="145.1239" x="3904.77" y="740.266">model_ : ModelHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="752.22"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="167.0061" x="3904.77" y="758.494">context_ : ContextHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="770.448"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="372.138" x="3904.77" y="776.722">prompt_formatter_ : std::unique_ptr<IPromptFormatter></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="788.676"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="365.4283" x="3904.77" y="794.95">prompt_directory_ : std::unique_ptr<IPromptDirectory></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="806.904"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="123.1442" x="3904.77" y="813.178">rng_ : std::mt19937</text><line style="stroke:#547461;stroke-width:0.5;" x1="3886.77" x2="4281.908" y1="821.518" y2="821.518"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3896.77" cy="836.132" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="236.0966" x="3904.77" y="839.406">GenerateBrewery(...) : BreweryResult</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3896.77" cy="854.36" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="188.4403" x="3904.77" y="857.634">GenerateUser(...) : UserResult</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="869.588"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="285.3309" x="3904.77" y="875.862">Load(model_path : const std::string&) : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="887.816"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="122.0454" x="3904.77" y="894.09">Infer(...) : std::string</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="3893.77" y="906.044"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="190.817" x="3904.77" y="912.318">InferFormatted(...) : std::string</text></g><!--class IPromptFormatter--><g class="entity" data-qualified-name="IPromptFormatter" data-source-line="142" id="ent0018"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="580.1605" x="3637.26" y="1082.69"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="580.1605" x="3637.26" y="1082.69"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="580.1605" x="3637.26" y="1126.646"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="580.1605" x="3637.26" y="1082.69"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="3891.7663" y="1101.578">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="116.48" x="3869.1003" y="1119.806">IPromptFormatter</text><line style="stroke:#547461;stroke-width:0.5;" x1="3638.26" x2="4216.4205" y1="1129.146" y2="1129.146"/><line style="stroke:#547461;stroke-width:0.5;" x1="3638.26" x2="4216.4205" y1="1137.146" y2="1137.146"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3648.26" cy="1151.76" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="555.1605" x="3656.26" y="1155.034">Format(system_prompt : std::string_view, user_prompt : std::string_view) : std::string</text></g><!--class Gemma4JinjaPromptFormatter--><g class="entity" data-qualified-name="Gemma4JinjaPromptFormatter" data-source-line="146" id="ent0019"><rect fill="#FAFCF9" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="580.1605" x="3626.26" y="1343.63"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="580.1605" x="3626.26" y="1343.63"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="580.1605" x="3626.26" y="1369.358"/><rect fill="none" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="580.1605" x="3626.26" y="1343.63"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="202.5557" x="3815.0624" y="1362.518">Gemma4JinjaPromptFormatter</text><line style="stroke:#547461;stroke-width:0.5;" x1="3627.26" x2="4205.4205" y1="1371.858" y2="1371.858"/><line style="stroke:#547461;stroke-width:0.5;" x1="3627.26" x2="4205.4205" y1="1379.858" y2="1379.858"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="3637.26" cy="1394.472" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="555.1605" x="3645.26" y="1397.746">Format(system_prompt : std::string_view, user_prompt : std::string_view) : std::string</text></g><!--class IPromptDirectory--><g class="entity" data-qualified-name="IPromptDirectory" data-source-line="150" id="ent0020"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="277.1055" x="4274.79" y="1082.69"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="277.1055" x="4274.79" y="1082.69"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="277.1055" x="4274.79" y="1126.646"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="277.1055" x="4274.79" y="1082.69"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="4377.7688" y="1101.578">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="112.49" x="4357.0978" y="1119.806">IPromptDirectory</text><line style="stroke:#547461;stroke-width:0.5;" x1="4275.79" x2="4550.8955" y1="1129.146" y2="1129.146"/><line style="stroke:#547461;stroke-width:0.5;" x1="4275.79" x2="4550.8955" y1="1137.146" y2="1137.146"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="4285.79" cy="1151.76" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="252.1055" x="4293.79" y="1155.034">Load(key : std::string_view) : std::string</text></g><!--class PromptDirectory--><g class="entity" data-qualified-name="PromptDirectory" data-source-line="154" id="ent0021"><rect fill="#FAFCF9" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="366.6985" x="4240.99" y="1325.4"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="366.6985" x="4240.99" y="1325.4"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="366.6985" x="4240.99" y="1351.128"/><rect fill="none" height="98.912" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="366.6985" x="4240.99" y="1325.4"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="109.2106" x="4369.7339" y="1344.288">PromptDirectory</text><line style="stroke:#547461;stroke-width:0.5;" x1="4241.99" x2="4606.6885" y1="1353.628" y2="1353.628"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="4248.99" y="1365.242"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="224.5147" x="4259.99" y="1371.516">prompt_dir_ : std::filesystem::path</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="4248.99" y="1383.47"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="341.6985" x="4259.99" y="1389.744">cache_ : std::unordered_map<std::string, std::string></text><line style="stroke:#547461;stroke-width:0.5;" x1="4241.99" x2="4606.6885" y1="1398.084" y2="1398.084"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="4251.99" cy="1412.698" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="252.1055" x="4259.99" y="1415.972">Load(key : std::string_view) : std::string</text></g><!--class ICuratedDataService--><g class="entity" data-qualified-name="ICuratedDataService" data-source-line="160" id="ent0022"><rect fill="#FAFCF9" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="1171" y="433.22"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="1171" y="433.22"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="1171" y="477.176"/><rect fill="none" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="1171" y="433.22"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="1544.7655" y="452.108">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="135.254" x="1512.7125" y="470.336">ICuratedDataService</text><line style="stroke:#547461;stroke-width:0.5;" x1="1172" x2="1988.679" y1="479.676" y2="479.676"/><line style="stroke:#547461;stroke-width:0.5;" x1="1172" x2="1988.679" y1="487.676" y2="487.676"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="502.29" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="491.8489" x="1190" y="505.564">LoadCities(filepath : const std::filesystem::path&) : const std::vector<City>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="520.518" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="568.8176" x="1190" y="523.792">LoadPersonas(filepath : const std::filesystem::path&) : const std::vector<UserPersona>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="538.746" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="793.679" x="1190" y="542.02">LoadForenamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, forename_list>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="556.974" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="780.106" x="1190" y="560.248">LoadSurnamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, surname_list>&</text></g><!--class JsonLoader--><g class="entity" data-qualified-name="JsonLoader" data-source-line="167" id="ent0023"><rect fill="#FAFCF9" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="1171" y="739.72"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="1171" y="739.72"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="1171" y="765.448"/><rect fill="none" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="1171" y="739.72"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="75.5861" x="1542.5465" y="758.608">JsonLoader</text><line style="stroke:#547461;stroke-width:0.5;" x1="1172" x2="1988.679" y1="767.948" y2="767.948"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="1179" y="779.562"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="98.7701" x="1190" y="785.836">cache_ : cache</text><line style="stroke:#547461;stroke-width:0.5;" x1="1172" x2="1988.679" y1="794.176" y2="794.176"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="808.79" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="491.8489" x="1190" y="812.064">LoadCities(filepath : const std::filesystem::path&) : const std::vector<City>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="827.018" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="568.8176" x="1190" y="830.292">LoadPersonas(filepath : const std::filesystem::path&) : const std::vector<UserPersona>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="845.246" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="793.679" x="1190" y="848.52">LoadForenamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, forename_list>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="1182" cy="863.474" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="780.106" x="1190" y="866.748">LoadSurnamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, surname_list>&</text></g><g class="entity" data-qualified-name="GMN24" data-source-line="176" id="ent0025"><path d="M2024.96,765.95 L2024.96,848.862 L2319.7268,848.862 L2319.7268,775.95 L2309.7268,765.95 L2024.96,765.95" fill="#EAF0E8" style="stroke:#547461;stroke-width:0.5;"/><path d="M2309.7268,765.95 L2309.7268,775.95 L2319.7268,775.95 L2309.7268,765.95" fill="#EAF0E8" style="stroke:#547461;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="273.7668" x="2030.96" y="784.838">Each Load* method memoizes its result in</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="238.2" x="2030.96" y="803.066">cache_ on first call; later calls on the</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="253.0399" x="2030.96" y="821.294">same instance return the cached value</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="124.3658" x="2030.96" y="839.522">without re-parsing.</text></g><!--class MockCuratedDataService--><g class="entity" data-qualified-name="MockCuratedDataService" data-source-line="182" id="ent0027"><rect fill="#FAFCF9" height="190.052" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="7" y="712.38"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="7" y="712.38"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="818.679" x="7" y="738.108"/><rect fill="none" height="190.052" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="818.679" x="7" y="712.38"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="166.5267" x="333.0762" y="731.268">MockCuratedDataService</text><line style="stroke:#547461;stroke-width:0.5;" x1="8" x2="824.679" y1="740.608" y2="740.608"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="15" y="752.222"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="190.0818" x="26" y="758.496">locations_ : std::vector<City></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="15" y="770.45"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="245.6619" x="26" y="776.724">personas_ : std::vector<UserPersona></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="15" y="788.678"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="483.921" x="26" y="794.952">forenames_by_country_ : std::unordered_map<std::string, forename_list></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="15" y="806.906"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="471.993" x="26" y="813.18">surnames_by_country_ : std::unordered_map<std::string, surname_list></text><line style="stroke:#547461;stroke-width:0.5;" x1="8" x2="824.679" y1="821.52" y2="821.52"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="18" cy="836.134" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="491.8489" x="26" y="839.408">LoadCities(filepath : const std::filesystem::path&) : const std::vector<City>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="18" cy="854.362" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="568.8176" x="26" y="857.636">LoadPersonas(filepath : const std::filesystem::path&) : const std::vector<UserPersona>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="18" cy="872.59" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="793.679" x="26" y="875.864">LoadForenamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, forename_list>&</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="18" cy="890.818" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="780.106" x="26" y="894.092">LoadSurnamesByCountry(filepath : const std::filesystem::path&) : const std::unordered_map<std::string, surname_list>&</text></g><g class="entity" data-qualified-name="GMN28" data-source-line="194" id="ent0029"><path d="M861.09,775.07 L861.09,839.754 L1135.5812,839.754 L1135.5812,785.07 L1125.5812,775.07 L861.09,775.07" fill="#EAF0E8" style="stroke:#547461;stroke-width:0.5;"/><path d="M1125.5812,775.07 L1125.5812,785.07 L1135.5812,785.07 L1125.5812,775.07" fill="#EAF0E8" style="stroke:#547461;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="241.9063" x="867.09" y="793.958">Fixed 4-location / 3-persona dataset</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="253.4912" x="867.09" y="812.186">(US, DE, FR, BE) used in --mocked runs;</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="202.8184" x="867.09" y="830.414">filepath arguments are ignored.</text></g><!--class IPostalCodeService--><g class="entity" data-qualified-name="IPostalCodeService" data-source-line="199" id="ent0031"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="385.0982" x="4731.79" y="460.56"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="385.0982" x="4731.79" y="460.56"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="385.0982" x="4731.79" y="504.516"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="385.0982" x="4731.79" y="460.56"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="4888.7651" y="479.448">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="126.532" x="4861.0731" y="497.676">IPostalCodeService</text><line style="stroke:#547461;stroke-width:0.5;" x1="4732.79" x2="5115.8882" y1="507.016" y2="507.016"/><line style="stroke:#547461;stroke-width:0.5;" x1="4732.79" x2="5115.8882" y1="515.016" y2="515.016"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="4742.79" cy="529.63" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="360.0982" x="4750.79" y="532.904">GeneratePostalCode(location : const City&) : std::string</text></g><!--class MockPostalCodeService--><g class="entity" data-qualified-name="MockPostalCodeService" data-source-line="203" id="ent0032"><rect fill="#FAFCF9" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="385.0982" x="5069.79" y="776.18"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="385.0982" x="5069.79" y="776.18"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="385.0982" x="5069.79" y="801.908"/><rect fill="none" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="385.0982" x="5069.79" y="776.18"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="157.8571" x="5183.4105" y="795.068">MockPostalCodeService</text><line style="stroke:#547461;stroke-width:0.5;" x1="5070.79" x2="5453.8882" y1="804.408" y2="804.408"/><line style="stroke:#547461;stroke-width:0.5;" x1="5070.79" x2="5453.8882" y1="812.408" y2="812.408"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5080.79" cy="827.022" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="360.0982" x="5088.79" y="830.296">GeneratePostalCode(location : const City&) : std::string</text></g><g class="entity" data-qualified-name="GMN33" data-source-line="208" id="ent0034"><path d="M5490.21,711.27 L5490.21,903.55 L5818.4685,903.55 L5818.4685,721.27 L5808.4685,711.27 L5490.21,711.27" fill="#EAF0E8" style="stroke:#547461;stroke-width:0.5;"/><path d="M5808.4685,711.27 L5808.4685,721.27 L5818.4685,721.27 L5808.4685,711.27" fill="#EAF0E8" style="stroke:#547461;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="270.4735" x="5496.21" y="730.158">Ignores location.postal_regex and returns</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="301.7808" x="5496.21" y="748.386">location.postal_code_examples.front(). Bound</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="260.7293" x="5496.21" y="766.614">unconditionally in main.cc's DI graph (no</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" text-decoration="line-through" textLength="126.8961" x="5496.21" y="784.842">mocked branch yet</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="150.0661" x="5630.5541" y="784.842">no real implementation</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="229.2784" x="5496.21" y="803.07">exists to switch to) and called from</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="286.8536" x="5496.21" y="821.298">GenerateBreweries() per brewery, stored on</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="307.2585" x="5496.21" y="839.526">BreweryRecord::address. A real implementation</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="244.8045" x="5496.21" y="857.754">needs a xeger-style generator to turn</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="271.7893" x="5496.21" y="875.982">postal_regex into a synthesized matching</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="185.9656" x="5496.21" y="894.21">string. See ROADMAP.md §9.</text></g><!--class IExportService--><g class="entity" data-qualified-name="IExportService" data-source-line="220" id="ent0036"><rect fill="#FAFCF9" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="415.1177" x="5244.78" y="433.22"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="415.1177" x="5244.78" y="433.22"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="415.1177" x="5244.78" y="477.176"/><rect fill="none" height="135.368" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="415.1177" x="5244.78" y="433.22"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="5416.7649" y="452.108">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="93.786" x="5405.4459" y="470.336">IExportService</text><line style="stroke:#547461;stroke-width:0.5;" x1="5245.78" x2="5658.8977" y1="479.676" y2="479.676"/><line style="stroke:#547461;stroke-width:0.5;" x1="5245.78" x2="5658.8977" y1="487.676" y2="487.676"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5255.78" cy="502.29" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="100.4677" x="5263.78" y="505.564">Initialize() : void</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5255.78" cy="520.518" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="390.1177" x="5263.78" y="523.792">ProcessRecord(brewery : const BreweryRecord&) : uint64_t</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5255.78" cy="538.746" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="340.981" x="5263.78" y="542.02">ProcessRecord(user : const UserRecord&) : uint64_t</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5255.78" cy="556.974" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="95.8547" x="5263.78" y="560.248">Finalize() : void</text></g><!--class SqliteExportService--><g class="entity" data-qualified-name="SqliteExportService" data-source-line="227" id="ent0037"><rect fill="#FAFCF9" height="317.648" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="424.1474" x="5853.27" y="648.58"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="424.1474" x="5853.27" y="648.58"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="424.1474" x="5853.27" y="674.308"/><rect fill="none" height="317.648" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="424.1474" x="5853.27" y="648.58"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="127.3512" x="6001.6681" y="667.468">SqliteExportService</text><line style="stroke:#547461;stroke-width:0.5;" x1="5854.27" x2="6276.4174" y1="676.808" y2="676.808"/><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="688.422"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="387.0232" x="5872.27" y="694.696">date_time_provider_ : std::unique_ptr<IDateTimeProvider></text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="706.65"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="215.2222" x="5872.27" y="712.924">run_timestamp_utc_ : std::string</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="724.878"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="249.0218" x="5872.27" y="731.152">database_path_ : std::filesystem::path</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="743.106"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="233.4325" x="5872.27" y="749.38">db_handle_ : SqliteDatabaseHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="761.334"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="280.5882" x="5872.27" y="767.608">insert_city_stmt_ : SqliteStatementHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="779.562"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="309.4563" x="5872.27" y="785.836">insert_brewery_stmt_ : SqliteStatementHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="797.79"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="284.1477" x="5872.27" y="804.064">insert_user_stmt_ : SqliteStatementHandle</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="816.018"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="164.4616" x="5872.27" y="822.292">transaction_open_ : bool</text><g data-visibility-modifier="PRIVATE_FIELD"><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="834.246"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="399.1474" x="5872.27" y="840.52">city_cache_ : std::unordered_map<std::string, sqlite3_int64></text><line style="stroke:#547461;stroke-width:0.5;" x1="5854.27" x2="6276.4174" y1="848.86" y2="848.86"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5864.27" cy="863.474" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="100.4677" x="5872.27" y="866.748">Initialize() : void</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5864.27" cy="881.702" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="390.1177" x="5872.27" y="884.976">ProcessRecord(brewery : const BreweryRecord&) : uint64_t</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5864.27" cy="899.93" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="340.981" x="5872.27" y="903.204">ProcessRecord(user : const UserRecord&) : uint64_t</text><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5864.27" cy="918.158" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="95.8547" x="5872.27" y="921.432">Finalize() : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="933.386"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="152.6842" x="5872.27" y="939.66">InitializeSchema() : void</text><g data-visibility-modifier="PRIVATE_METHOD"><rect fill="#F24D5C" height="6" style="stroke:#C82930;stroke-width:1;" width="6" x="5861.27" y="951.614"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="336.893" x="5872.27" y="957.888">ResolveCityId(location : const City&) : sqlite3_int64</text></g><!--class IDateTimeProvider--><g class="entity" data-qualified-name="IDateTimeProvider" data-source-line="245" id="ent0038"><rect fill="#FAFCF9" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="229.2673" x="5950.71" y="1082.69"/><rect fill="#EAF0E8" height="46.456" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="229.2673" x="5950.71" y="1082.69"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="229.2673" x="5950.71" y="1126.646"/><rect fill="none" height="80.684" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="229.2673" x="5950.71" y="1082.69"/><text fill="#28342A" font-family="DM Sans" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="71.148" x="6029.7697" y="1101.578">«interface»</text><text fill="#28342A" font-family="'DM Sans'" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="120.176" x="6005.2557" y="1119.806">IDateTimeProvider</text><line style="stroke:#547461;stroke-width:0.5;" x1="5951.71" x2="6178.9773" y1="1129.146" y2="1129.146"/><line style="stroke:#547461;stroke-width:0.5;" x1="5951.71" x2="6178.9773" y1="1137.146" y2="1137.146"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5961.71" cy="1151.76" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="204.2673" x="5969.71" y="1155.034">GetUtcTimestamp() : std::string</text></g><!--class SystemDateTimeProvider--><g class="entity" data-qualified-name="SystemDateTimeProvider" data-source-line="249" id="ent0039"><rect fill="#FAFCF9" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="229.2673" x="5950.71" y="1343.63"/><rect fill="#EAF0E8" height="28.228" rx="2.5" ry="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="229.2673" x="5950.71" y="1343.63"/><rect fill="#EAF0E8" height="2.5" style="stroke:#EAF0E8;stroke-width:0.5;" width="229.2673" x="5950.71" y="1369.358"/><rect fill="none" height="62.456" rx="2.5" ry="2.5" style="stroke:#547461;stroke-width:0.5;" width="229.2673" x="5950.71" y="1343.63"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="165.4241" x="5982.6316" y="1362.518">SystemDateTimeProvider</text><line style="stroke:#547461;stroke-width:0.5;" x1="5951.71" x2="6178.9773" y1="1371.858" y2="1371.858"/><line style="stroke:#547461;stroke-width:0.5;" x1="5951.71" x2="6178.9773" y1="1379.858" y2="1379.858"/><g data-visibility-modifier="PUBLIC_METHOD"><ellipse cx="5961.71" cy="1394.472" fill="#84BE84" rx="3" ry="3" style="stroke:#038048;stroke-width:1;"/></g><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="204.2673" x="5969.71" y="1397.746">GetUtcTimestamp() : std::string</text></g><!--link JsonLoader to GMN24--><g class="link" data-entity-1="ent0023" data-entity-2="ent0025" data-link-type="association" data-source-line="176" id="lnk26"><path d="M1989.94,807.41 C2001.46,807.41 2012.98,807.41 2024.5,807.41" fill="none" id="JsonLoader-GMN24" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/></g><!--link MockCuratedDataService to GMN28--><g class="link" data-entity-1="ent0027" data-entity-2="ent0029" data-link-type="association" data-source-line="194" id="lnk30"><path d="M826.13,807.41 C837.67,807.41 849.22,807.41 860.77,807.41" fill="none" id="MockCuratedDataService-GMN28" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/></g><!--link MockPostalCodeService to GMN33--><g class="link" data-entity-1="ent0032" data-entity-2="ent0034" data-link-type="association" data-source-line="208" id="lnk35"><path d="M5455.28,807.41 C5466.81,807.41 5478.35,807.41 5489.88,807.41" fill="none" id="MockPostalCodeService-GMN33" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/></g><!--reverse link BiergartenPipelineOrchestrator to ILogger--><g class="link" data-entity-1="ent0002" data-entity-2="ent0007" data-link-type="composition" data-source-line="254" id="lnk40"><path codeLine="254" d="M3512.6878,287.5025 C3352.0878,344.8025 3153.01,415.82 3026.9,460.81" fill="none" id="BiergartenPipelineOrchestrator-backto-ILogger" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3523.99,283.47,3516.9948,281.7188,3512.6878,287.5025,3519.6831,289.2536,3523.99,283.47" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="3233.83" y="398.108">owns</text></g><!--reverse link BiergartenPipelineOrchestrator to IEnrichmentService--><g class="link" data-entity-1="ent0002" data-entity-2="ent0010" data-link-type="composition" data-source-line="255" id="lnk41"><path codeLine="255" d="M3658.3873,364.0367 C3636.8973,403.4667 3621.22,432.24 3605.99,460.18" fill="none" id="BiergartenPipelineOrchestrator-backto-IEnrichmentService" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3664.13,353.5,3657.7464,356.8541,3658.3873,364.0367,3664.7709,360.6826,3664.13,353.5" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="3646.68" y="398.108">owns</text></g><!--reverse link BiergartenPipelineOrchestrator to DataGenerator--><g class="link" data-entity-1="ent0002" data-entity-2="ent0015" data-link-type="composition" data-source-line="256" id="lnk42"><path codeLine="256" d="M3960.8503,360.5368 C4009.5703,395.8068 4048.43,423.95 4085.76,450.98" fill="none" id="BiergartenPipelineOrchestrator-backto-DataGenerator" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3951.13,353.5,3953.6445,360.2585,3960.8503,360.5368,3958.3357,353.7783,3951.13,353.5" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="4010.72" y="398.108">owns</text></g><!--reverse link BiergartenPipelineOrchestrator to IExportService--><g class="link" data-entity-1="ent0002" data-entity-2="ent0036" data-link-type="composition" data-source-line="257" id="lnk43"><path codeLine="257" d="M3978.4411,239.7103 C4252.9611,281.8403 4723.25,356.31 5134.34,433.22 C5169.96,439.88 5207.74,447.4 5244.34,454.93" fill="none" id="BiergartenPipelineOrchestrator-backto-IExportService" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3966.58,237.89,3971.9038,242.7539,3978.4411,239.7103,3973.1173,234.8464,3966.58,237.89" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="4947.01" y="398.108">owns</text></g><!--reverse link BiergartenPipelineOrchestrator to ICuratedDataService--><g class="link" data-entity-1="ent0002" data-entity-2="ent0022" data-link-type="composition" data-source-line="258" id="lnk44"><path codeLine="258" d="M3512.1801,236.3222 C3152.0001,285.4622 2445.37,381.88 1990.02,444" fill="none" id="BiergartenPipelineOrchestrator-backto-ICuratedDataService" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3524.07,234.7,3517.5844,231.5478,3512.1801,236.3222,3518.6658,239.4744,3524.07,234.7" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="2406.26" y="398.108">owns</text></g><!--reverse link BiergartenPipelineOrchestrator to IPostalCodeService--><g class="link" data-entity-1="ent0002" data-entity-2="ent0031" data-link-type="composition" data-source-line="259" id="lnk45"><path codeLine="259" d="M3978.0501,262.8068 C4210.7501,321.1168 4559.66,408.53 4765.65,460.14" fill="none" id="BiergartenPipelineOrchestrator-backto-IPostalCodeService" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3966.41,259.89,3971.2578,265.2284,3978.0501,262.8068,3973.2023,257.4684,3966.41,259.89" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="4510.33" y="398.108">owns</text></g><!--reverse link LogEntry to LogLevel--><g class="link" data-entity-1="ent0006" data-entity-2="ent0003" data-link-type="composition" data-source-line="261" id="lnk46"><path codeLine="261" d="M2638.2971,1207.8754 C2609.9171,1232.5054 2588.16,1252.63 2561.34,1279.83 C2550.81,1290.51 2540.05,1302.38 2529.98,1313.99" fill="none" id="LogEntry-backto-LogLevel" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="2647.36,1200.01,2640.2068,1200.9217,2638.2971,1207.8754,2645.4503,1206.9636,2647.36,1200.01" style="stroke:#628A5B;stroke-width:1;"/></g><!--reverse link LogEntry to PipelinePhase--><g class="link" data-entity-1="ent0006" data-entity-2="ent0004" data-link-type="composition" data-source-line="262" id="lnk47"><path codeLine="262" d="M2716.8999,1211.6241 C2710.4599,1236.7441 2706.2,1253.38 2699.46,1279.7" fill="none" id="LogEntry-backto-PipelinePhase" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="2719.88,1200,2714.5153,1204.8187,2716.8999,1211.6241,2722.2647,1206.8054,2719.88,1200" style="stroke:#628A5B;stroke-width:1;"/></g><!--reverse link LogDTO to LogLevel--><g class="link" data-entity-1="ent0005" data-entity-2="ent0003" data-link-type="composition" data-source-line="263" id="lnk48"><path codeLine="263" d="M2454.0801,1184.6675 C2459.5801,1222.8675 2465.59,1264.55 2471.67,1306.79" fill="none" id="LogDTO-backto-LogLevel" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="2452.37,1172.79,2449.2659,1179.2988,2454.0801,1184.6675,2457.1842,1178.1587,2452.37,1172.79" style="stroke:#628A5B;stroke-width:1;"/></g><!--reverse link LogDTO to PipelinePhase--><g class="link" data-entity-1="ent0005" data-entity-2="ent0004" data-link-type="composition" data-source-line="264" id="lnk49"><path codeLine="264" d="M2498.3571,1181.6189 C2526.2671,1211.9389 2554.96,1243.1 2588.41,1279.43" fill="none" id="LogDTO-backto-PipelinePhase" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="2490.23,1172.79,2491.3506,1179.9135,2498.3571,1181.6189,2497.2365,1174.4954,2490.23,1172.79" style="stroke:#628A5B;stroke-width:1;"/></g><!--reverse link ILogger to LogProducer--><g class="link" data-entity-1="ent0007" data-entity-2="ent0008" data-link-type="extension" data-source-line="265" id="lnk50"><path codeLine="265" d="M2803.79,559.2324 C2754.77,585.5424 2711.39,611.63 2662.34,648.58 C2614.83,684.37 2566.66,732.85 2535.13,766.6" fill="none" id="ILogger-backto-LogProducer" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="2819.65,550.72,2800.9525,553.9457,2806.6275,564.519,2819.65,550.72" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="2736.87" y="613.468">implements</text></g><!--link LogProducer to LogEntry--><g class="link" data-entity-1="ent0008" data-entity-2="ent0006" data-link-type="dependency" data-source-line="266" id="lnk51"><path codeLine="266" d="M2529.74,848.13 C2567.64,897.66 2629.6035,978.6352 2677.3435,1041.0152" fill="none" id="LogProducer-to-LogEntry" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="#628A5B" points="2680.99,1045.78,2678.6967,1036.2019,2677.9512,1041.8094,2672.3437,1041.0639,2680.99,1045.78" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="36.2985" x="2655.86" y="1011.118">emits</text></g><!--link LogDispatcher to LogEntry--><g class="link" data-entity-1="ent0009" data-entity-2="ent0006" data-link-type="dependency" data-source-line="267" id="lnk52"><path codeLine="267" d="M2828.05,857.07 C2811.17,907.48 2786.4649,981.2704 2766.7849,1040.0504" fill="none" id="LogDispatcher-to-LogEntry" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="#628A5B" points="2764.88,1045.74,2771.5304,1038.4756,2766.4674,1040.9987,2763.9443,1035.9357,2764.88,1045.74" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="66.857" x="2780.35" y="1011.118">consumes</text></g><!--reverse link IEnrichmentService to WikipediaEnrichmentService--><g class="link" data-entity-1="ent0010" data-entity-2="ent0012" data-link-type="extension" data-source-line="269" id="lnk53"><path codeLine="269" d="M3528.1199,553.9368 C3471.1599,606.6568 3383.51,687.78 3318.06,748.35" fill="none" id="IEnrichmentService-backto-WikipediaEnrichmentService" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="3541.33,541.71,3524.0443,549.5334,3532.1955,558.3401,3541.33,541.71" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="3478.92" y="613.468">implements</text></g><!--reverse link IEnrichmentService to MockEnrichmentService--><g class="link" data-entity-1="ent0010" data-entity-2="ent0011" data-link-type="extension" data-source-line="270" id="lnk54"><path codeLine="270" d="M3601.5746,558.9411 C3620.1746,620.5211 3650.33,720.33 3667.09,775.79" fill="none" id="IEnrichmentService-backto-MockEnrichmentService" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="3596.37,541.71,3595.8309,560.676,3607.3183,557.2063,3596.37,541.71" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="3620.39" y="613.468">implements</text></g><!--reverse link WikipediaEnrichmentService to WebClient--><g class="link" data-entity-1="ent0012" data-entity-2="ent0013" data-link-type="composition" data-source-line="271" id="lnk55"><path codeLine="271" d="M3255.34,878.3 C3255.34,937.77 3255.34,1017.32 3255.34,1073.23" fill="none" id="WikipediaEnrichmentService-backto-WebClient" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="3255.34,866.3,3251.34,872.3,3255.34,878.3,3259.34,872.3,3255.34,866.3" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="3256.34" y="1011.118">owns</text></g><!--reverse link WebClient to HttpWebClient--><g class="link" data-entity-1="ent0013" data-entity-2="ent0014" data-link-type="extension" data-source-line="273" id="lnk56"><path codeLine="273" d="M3255.34,1190.79 C3255.34,1237.94 3255.34,1290.48 3255.34,1334.26" fill="none" id="WebClient-backto-HttpWebClient" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="3255.34,1172.79,3249.34,1190.79,3261.34,1190.79,3255.34,1172.79" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="3256.34" y="1244.718">implements</text></g><!--reverse link DataGenerator to MockGenerator--><g class="link" data-entity-1="ent0015" data-entity-2="ent0016" data-link-type="extension" data-source-line="275" id="lnk57"><path codeLine="275" d="M4252.9247,559.8782 C4345.4647,613.7682 4478.61,691.28 4576.89,748.5" fill="none" id="DataGenerator-backto-MockGenerator" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="4237.37,550.82,4249.9053,565.0631,4255.9441,554.6933,4237.37,550.82" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="4353.62" y="613.468">implements</text></g><!--reverse link DataGenerator to LlamaGenerator--><g class="link" data-entity-1="ent0015" data-entity-2="ent0017" data-link-type="extension" data-source-line="276" id="lnk58"><path codeLine="276" d="M4138.2738,568.3753 C4129.5538,606.8753 4121.02,644.51 4109.86,693.76" fill="none" id="DataGenerator-backto-LlamaGenerator" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="4142.25,550.82,4132.422,567.05,4144.1256,569.7007,4142.25,550.82" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="4132.02" y="613.468">implements</text></g><!--reverse link LlamaGenerator to IPromptFormatter--><g class="link" data-entity-1="ent0017" data-entity-2="ent0018" data-link-type="composition" data-source-line="278" id="lnk59"><path codeLine="278" d="M4022.7289,931.4808 C3994.4889,987.9008 3967.42,1041.96 3947.15,1082.45" fill="none" id="LlamaGenerator-backto-IPromptFormatter" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="4028.1,920.75,4021.8375,924.325,4022.7289,931.4808,4028.9914,927.9058,4028.1,920.75" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="30.044" x="3988.16" y="1011.118">uses</text></g><!--reverse link LlamaGenerator to IPromptDirectory--><g class="link" data-entity-1="ent0017" data-entity-2="ent0020" data-link-type="composition" data-source-line="279" id="lnk60"><path codeLine="279" d="M4210.8754,929.0303 C4270.0554,985.4503 4329.34,1041.96 4371.82,1082.45" fill="none" id="LlamaGenerator-backto-IPromptDirectory" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="4202.19,920.75,4203.7726,927.7853,4210.8754,929.0303,4209.2928,921.995,4202.19,920.75" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="30.044" x="4298.53" y="1011.118">uses</text></g><!--reverse link IPromptFormatter to Gemma4JinjaPromptFormatter--><g class="link" data-entity-1="ent0018" data-entity-2="ent0019" data-link-type="extension" data-source-line="281" id="lnk61"><path codeLine="281" d="M3924.8078,1181.6026 C3922.6078,1231.5426 3919.66,1298.36 3917.68,1343.49" fill="none" id="IPromptFormatter-backto-Gemma4JinjaPromptFormatter" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="3925.6,1163.62,3918.8136,1181.3385,3930.802,1181.8666,3925.6,1163.62" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="3923.5" y="1244.718">implements</text></g><!--reverse link IPromptDirectory to PromptDirectory--><g class="link" data-entity-1="ent0020" data-entity-2="ent0021" data-link-type="extension" data-source-line="282" id="lnk62"><path codeLine="282" d="M4415.8733,1181.6025 C4417.8033,1225.3525 4420.11,1277.87 4422.19,1325.02" fill="none" id="IPromptDirectory-backto-PromptDirectory" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="4415.08,1163.62,4409.8791,1181.8669,4421.8675,1181.3381,4415.08,1163.62" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="4419.84" y="1244.718">implements</text></g><!--reverse link ICuratedDataService to JsonLoader--><g class="link" data-entity-1="ent0022" data-entity-2="ent0023" data-link-type="extension" data-source-line="284" id="lnk63"><path codeLine="284" d="M1580.34,586.73 C1580.34,637.41 1580.34,688.77 1580.34,739.48" fill="none" id="ICuratedDataService-backto-JsonLoader" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="1580.34,568.73,1574.34,586.73,1586.34,586.73,1580.34,568.73" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="1581.34" y="613.468">implements</text></g><!--reverse link ICuratedDataService to MockCuratedDataService--><g class="link" data-entity-1="ent0022" data-entity-2="ent0027" data-link-type="extension" data-source-line="285" id="lnk64"><path codeLine="285" d="M1165.5129,572.5367 C1054.6729,594.4867 952.41,617.78 843.34,648.58 C780.31,666.39 713.33,689.2 651.58,711.92" fill="none" id="ICuratedDataService-backto-MockCuratedDataService" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="1183.17,569.04,1164.3473,566.651,1166.6785,578.4224,1183.17,569.04" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="1024.08" y="613.468">implements</text></g><!--reverse link IPostalCodeService to MockPostalCodeService--><g class="link" data-entity-1="ent0031" data-entity-2="ent0032" data-link-type="extension" data-source-line="287" id="lnk65"><path codeLine="287" d="M4981.903,553.7584 C5050.253,615.3384 5166.79,720.33 5228.35,775.79" fill="none" id="IPostalCodeService-backto-MockPostalCodeService" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="4968.53,541.71,4977.8868,558.216,4985.9191,549.3007,4968.53,541.71" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="5054.13" y="613.468">implements</text></g><!--reverse link IExportService to SqliteExportService--><g class="link" data-entity-1="ent0036" data-entity-2="ent0037" data-link-type="extension" data-source-line="289" id="lnk66"><path codeLine="289" d="M5671.9637,575.3874 C5731.6437,597.8774 5779.34,618.6 5836.34,648.58 C5841.9,651.51 5847.48,654.54 5853.07,657.66" fill="none" id="IExportService-backto-SqliteExportService" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="5655.12,569.04,5669.8479,581.002,5674.0795,569.7729,5655.12,569.04" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="5766.64" y="613.468">implements</text></g><!--reverse link SqliteExportService to IDateTimeProvider--><g class="link" data-entity-1="ent0037" data-entity-2="ent0038" data-link-type="composition" data-source-line="290" id="lnk67"><path codeLine="290" d="M6065.34,978.6 C6065.34,1021.68 6065.34,1052.62 6065.34,1082.42" fill="none" id="SqliteExportService-backto-IDateTimeProvider" style="stroke:#628A5B;stroke-width:1;"/><polygon fill="#628A5B" points="6065.34,966.6,6061.34,972.6,6065.34,978.6,6069.34,972.6,6065.34,966.6" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="34.0411" x="6066.34" y="1011.118">owns</text></g><!--reverse link IDateTimeProvider to SystemDateTimeProvider--><g class="link" data-entity-1="ent0038" data-entity-2="ent0039" data-link-type="extension" data-source-line="291" id="lnk68"><path codeLine="291" d="M6065.34,1181.62 C6065.34,1231.56 6065.34,1298.36 6065.34,1343.49" fill="none" id="IDateTimeProvider-backto-SystemDateTimeProvider" style="stroke:#628A5B;stroke-width:1;stroke-dasharray:7,7;"/><polygon fill="none" points="6065.34,1163.62,6059.34,1181.62,6071.34,1181.62,6065.34,1163.62" style="stroke:#628A5B;stroke-width:1;"/><text fill="#28342A" font-family="'DM Sans'" font-size="14" lengthAdjust="spacing" textLength="76.65" x="6066.34" y="1244.718">implements</text></g><?plantuml-src xHdjSjisyh-U0fERIUN6rZM9coQgnpEsPIVf91UVvLn-Sc1oBQ4c0GO0RUjoUPvxZtkosmL8Yk27OgVjpUIcVoGEi5_ONUmNp9MGETSyOyQkKi1VBM9RPEd8r3i9NF8YjITAsh_n3DY3sLisvz8yw8UPYty2UxpRsBJ2fh16_uTAhvRg-a4VX4D-yaDZwuB7Lmkj2faSgLHfzfUJWvEZanVzl4kG9y-VxZuvwAC_172WjRefDvyzUNxmu-6eiHkdt1ZsQSJOuO0qZBq2de3kx1yVdFnm_9mmbSRzSlN7tPzsdpt6rHw-Z7K5_ToKHYeB_S9yWLalNQSQThu4TYX0BxYs8DcCMyvEHGwfaC1ss95Jm4pm1Gem6dbzhE4ho7SwNWAw4BV8WoJSOQbQB417R8gkbKodPiar955kzTxhDsvhtu75A1hSsiY0lXOnrF2551yByF374drpcG5wYOVog0kGu3Zs8T51NbO07XvkSuL2wtuURZEW7nU8Z38dI6gZV4SUa5W6179bB4-ZM2Mm4V_KmHqXM83EypmLCRT2oKZbz6S8_M2z_CwlDhM1ybvek04jmDJChY56BUmTketL6SJe9Vijh08bx62ynyKr-2DsLiZn5i9SA9Kw_ByNIF18MEJsGTZb4Vga9TOEgaa9OLQUPMaLEAp47CSEl_QKdCizT0jZcJSy90wPA5uhaGH4IC2l8e0-U0O6euSNrQr_hXmSDz_0DQHiRmzaaH4drFF-ldFj6LmK2_n_BIyL_dtWMkBVCTvdlQPGNOpJ9JVGIsPkyGOLENxH6Shpu3PTOc-d0vaSGclhQ0anneDWxGm_v29OEb5fgcw2fNFWEb4tqeKKgulOqZ5dv--SD8zOwWuyhS_k5dCd_ZGyZjl9m1Y-W5hdQ7Mv26aVeokiIkfM88BbMLuXn4kjf4B4bR6GHN6guglfbC2YN0bf7PRIOY5apKCL6cyGGbPdGhfBZU4t4aa5v1UcKsVct-zKA17eInu3AwCNshHUAotwYBYCSxvA5KyyJrHlu7MV-0L5oTX-PZD5qE1qDAtLrUkBfrebHGnLP8sNN4f8wQuUKWv0z_OhUnML_OSEy1uiPW9lZSMhSaycwv1Gd_5SpVCaBVKzTWPmmS0jJgTkeVoBw5gqrDi9zhsQVWdsJUa7Hpw3ZD4la8s_ztJV7svrpUZF-nPzhSlcTo3yGLoXIoM2zrD7hQO2r_gIm0UuE7ARLQvoRXB576tIW7Vf7QDrnlEzXWZRJNdsl_eWnFa4q0sEFVlnHmhl8L1qBU1cQzCDgOyoPBbneTDQa0QP7daUiVSwFPQKGiVNF2tWJdYrGLvPcw_5-PyAiDP7K8eCwAIP4bVZAiI5rjfc6XPK39Grqw0aTPwd_1Ome5H3sN9LupOp97B8CPqgoUjjGZZrQxWhgOoljgYcT-nyaU1u1LTiVUR_irEws0fen4n8OQo8Nt6p73YEympiRQBxeNsTZ2MZTM1FUSP3C-om35tPnVMtzF6AooI5e1J7hJ9YD3PphRBSHfTAPzmE5T6d3kYaWjblOYP2kqfmjG5pLi5uJ8tHfWBExECNBvx-rEj8ayda3WvHGhNi-0PpzTYh11FWSj3RwlI6PT-QM3jukitg_4aVL9ZiMWhh3Gv-TrmMIbwRFI5vcr45Fxm_62DVGfRntL-4_9MtnVcZ1UXeedQ0WV8ARNK5g_kShattKyidQmUx52du8qwdv0d-Idnr-hsVh0r5T9l9GLtulcjCadTzjtqUvyMD_MPVzh0cMKQOtqYq4QiQjD6FWEAMELpvFd7rbLmssE6ov16b664RlEU5_gDP6y-Yubnxu2-e1X9XNLfNJkK-_hJcDs9DDtt3XdHfcRfiM9MQVpIa4-nxx23jKYNubobCneO9Qx2WeNJ31BMifV4ntryAZNB4F4r_PYcdS4lVXhQiSmj3ELwWi5nY4D1WKIJQyZGIvifHXBiHoBAm2B6JSsrG_Ca8PEB6XSrwh2UoLACwNu9qnZ_heKrPZVGEY2hVS82LoKnqiS8IpbddBW4qDBKZLPhWlfG2o_rvkxx9szNlhZJO4hVe-RixTTNyL_PqfogLQL1hWEgwyVlvDfiTRxEJisrsUBn5fKc2Tudjx6H86hzr8StF25aVZUj5GGsxmI-yTWiK7fBcHMeMA-s1xSQkRWszgKSO6bHqUVrswbrbTxZGWDFfmDJXOLBEix4_Wrk6hK4PasZ-t8PnCs-uvLcEFZAvrDXFZBScVfI4u0Ksr38HX84nRqMMoRYGapZ-ph3PQxRGF5-oiQG1Qsso2us1SCbMO74DZOBiUSe4iI33LKD1k4MdCimgPZ0o8e9LMqvQ2gz81eN94AmxXjwYACVyz7n59Hrv06jEPFqeV3hbIOAACHDsC22314ZGaTWjgahl-1Us-hc2H2Ez8LoWKVGWXJXc9J78Kok7QOHcShwvyDQRi3a0EtjtC7jxS3h94lQVVxyOSDBWHQFNGLzBj01FaLDpWlU8QkOOZ-TFEouLKZjLe0ldNGMIVhORsHvaQWc25dO8xKJ8bYJrBPX_J8M5y3W-SU65ntxNpOorkXR9G5kA8GJE4Ugq12gxoq96zLWwAcmSzJHq558kCAYuvd1phv1SH4lNBnEObtbMOZVwQCpde6r4qud8sCokWUVeFSw9kj2b2UwEu3gnBqDRl566n-KB4yYe-RJZHBnx0-IOF8sSJVU_0VVoxNebuHoFcV5mzmoCIg-1WkZhP5DmRHwzrSsrNMze9FhUnkULBuu7yy7S-Lo7vfsfVCVcxdK6CskAnqjzrRSKkS4yEWFqW0Hal4Az_0hEAqPVUEhz7WDnzI0oPUe6Sy5TCBhZyRiZXzFK-p0D0iWz47lgvdjWT_DtYJogdyW8hdwW2bR35wholQuDNgs5mFKxrRyca-0HQRfELsRKt9XCzjVFTbC6cV00ZRUX5WXT12oQy2nzppR4UCEBI23747x_Kqs0ke45QMKz_g_qtdYV81RX6q50UjGQtLSIDVsl0Tu3tPh0XjHRczvTMYEuAPMkPWFeUhHLWewwKqMIPCEOBxH4Pn97s5rUpOFq3gq8hJ7x29aC8GpqgIrsFVLtXTnttGBSLbb4U7q5He3L1-1Cq0d5fO_rn7t7g3z-1xp-2m00?></g></svg> |