Files
ota-reference-design/diagrams/rendered/ab-trial-boot.svg
T
2026-10-11 07:21:11 -04:00

81 lines
21 KiB
XML

<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1165px" preserveAspectRatio="none" style="width:1029px;height:1165px;" version="1.1" viewBox="0 0 1029 1165" width="1029px" zoomAndPan="magnify"><defs/><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="229" x="404" y="19.2419">A/B trial boot and recovery</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="102" x="683.79" y="169.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="683.79" x2="785.79" y1="198.5838" y2="198.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="82" x="693.79" y="189.4818">A confirmed</text><rect fill="#F8F8F8" height="58.1358" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="247" x="466.29" y="32.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="466.29" x2="713.29" y1="80.6517" y2="80.6517"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="66" x="556.79" y="52.4818">Prepare B</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="227" x="476.29" y="71.5497">A remains the normal boot choice</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="181" x="237.29" y="169.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="237.29" x2="418.29" y1="198.5838" y2="198.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="161" x="247.29" y="189.4818">B prepared and verified</text><rect fill="#F8F8F8" height="58.1358" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="226" x="214.79" y="310.0158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="214.79" x2="440.79" y1="358.1517" y2="358.1517"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="101" x="277.29" y="329.9818">B trial pending</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="206" x="224.79" y="349.0497">Saved target and attempt limit</text><rect fill="#F8F8F8" height="58.1358" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="119" x="121.29" y="476.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="121.29" x2="240.29" y1="524.6517" y2="524.6517"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="99" x="131.29" y="496.4818">B trial running</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="88" x="136.79" y="515.5497">Unconfirmed</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="102" x="7.79" y="711.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="7.79" x2="109.79" y1="740.5838" y2="740.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="82" x="17.79" y="731.4818">B confirmed</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="171" x="291.29" y="631.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="291.29" x2="462.29" y1="660.5838" y2="660.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="151" x="301.29" y="651.4818">Recovery to A pending</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="149" x="302.29" y="791.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="302.29" x2="451.29" y1="820.5838" y2="820.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="129" x="312.29" y="811.4818">A recovery running</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="149" x="368.29" y="938.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="368.29" x2="517.29" y1="967.5838" y2="967.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="129" x="378.29" y="958.4818">A recovery checked</text><rect fill="#F8F8F8" height="50" rx="12.5" ry="12.5" style="stroke: #383838; stroke-width: 1.5;" width="204" x="111.79" y="938.5158"/><line style="stroke: #383838; stroke-width: 1.5;" x1="111.79" x2="315.79" y1="967.5838" y2="967.5838"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="184" x="121.79" y="958.4818">Separate recovery required</text><ellipse cx="1008.79" cy="61.5158" fill="#000000" rx="10" ry="10" style="stroke: none; stroke-width: 1.0;"/><ellipse cx="213.79" cy="1059.5158" fill="none" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="214.29" cy="1060.0158" fill="#000000" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><path d="M476.29,298.5158 L476.29,335.0158 L441.07,339.0158 L476.29,343.0158 L476.29,379.3399 A0,0 0 0 0 476.29,379.3399 L749.29,379.3399 A0,0 0 0 0 749.29,379.3399 L749.29,308.5158 L739.29,298.5158 L476.29,298.5158 A0,0 0 0 0 476.29,298.5158 " fill="#ECECEC" style="stroke: #383838; stroke-width: 1.0;"/><path d="M739.29,298.5158 L739.29,308.5158 L749.29,308.5158 L739.29,298.5158 " fill="#ECECEC" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="173" x="482.29" y="317.4129">Boot state is outside A and B.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="250" x="482.29" y="335.1189">Attempts are consumed before starting B.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="248" x="482.29" y="352.8249">Invalid records require a platform-defined</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="252" x="482.29" y="370.5309">recovery path, never implicit confirmation.</text><path d="M486.79,794.0158 L486.79,812.5158 L451.5,816.5158 L486.79,820.5158 L486.79,839.4279 A0,0 0 0 0 486.79,839.4279 L766.79,839.4279 A0,0 0 0 0 766.79,839.4279 L766.79,804.0158 L756.79,794.0158 L486.79,794.0158 A0,0 0 0 0 486.79,794.0158 " fill="#ECECEC" style="stroke: #383838; stroke-width: 1.0;"/><path d="M756.79,794.0158 L756.79,804.0158 L766.79,804.0158 L756.79,794.0158 " fill="#ECECEC" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="259" x="492.79" y="812.9129">A must still be compatible with shared data.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="246" x="492.79" y="830.6189">Do not endlessly alternate failed systems.</text><!--MD5=[ba0fdac9700f9825b754e67fda8ee1b2]
link *start to A--><path d="M1006.77,71.4758 C1002.61,87.7058 991.54,121.8958 968.79,139.5158 C917.66,179.1458 842.54,190.5658 791.3,193.4258 " fill="none" id="*start-&gt;A" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="786.11,193.6858,795.3036,197.2183,791.1034,193.429,794.8927,189.2289,786.11,193.6858" style="stroke: #383838; stroke-width: 1.0;"/><!--MD5=[c262a729ace56793ce804c80164b78bb]
link A to Preparing--><path d="M683.6,189.4458 C650.05,183.8158 608.51,170.5558 586.79,139.5158 C578.12,127.1158 577.7,110.6458 579.93,96.1158 " fill="none" id="A-&gt;Preparing" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="580.86,90.8658,575.3541,99.0319,579.9894,95.7895,583.2319,100.4248,580.86,90.8658" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="103" x="587.79" y="135.4129">begin installation</text><!--MD5=[8ac39ec8ceeada5156d86e8c940ca0fe]
link Preparing to A--><path d="M655.3,90.6258 C669.76,98.8358 684.21,108.8158 695.79,120.5158 C708.06,132.8958 717.45,149.9358 723.95,164.4358 " fill="none" id="Preparing-&gt;A" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="726.04,169.2458,726.1343,159.3974,724.0532,164.6575,718.7931,162.5764,726.04,169.2458" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="249" x="710.79" y="135.4129">abandon incomplete or failed preparation</text><!--MD5=[07f470d462742561469e04f57962dde0]
link Preparing to Preparing--><path d="M713.4,49.6658 C734.05,51.3258 748.29,55.2758 748.29,61.5158 C748.29,67.2258 736.39,71.0158 718.58,72.8858 " fill="none" id="Preparing-&gt;Preparing" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="713.4,73.3658,722.7285,76.5249,718.379,72.908,721.9959,68.5585,713.4,73.3658" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="193" x="754.29" y="57.9129">reset during preparation; boot A</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="135" x="783.29" y="75.6189">B is not eligible for trial</text><!--MD5=[14c61493ce9a076f09f2189989cfcc27]
link Preparing to Prepared--><path d="M466.24,80.8158 C416.86,90.4458 367.51,103.7658 349.79,120.5158 C337.87,131.7958 332.34,149.2658 329.8,164.2958 " fill="none" id="Preparing-&gt;Prepared" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="329.05,169.2858,334.3666,160.9953,329.8071,164.3435,326.4588,159.784,329.05,169.2858" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="220" x="350.79" y="135.4129">installation and verification complete</text><!--MD5=[9d3566f475c31f8d28eabcacf9587b86]
link Prepared to Pending--><path d="M327.79,219.6858 C327.79,243.0658 327.79,278.6758 327.79,304.7258 " fill="none" id="Prepared-&gt;Pending" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="327.79,309.8058,331.79,300.8058,327.79,304.8058,323.79,300.8058,327.79,309.8058" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="233" x="328.79" y="264.4129">save trial request through boot control</text><!--MD5=[2b80e139dec28a8ca7d421262724a74e]
link Pending to Trial--><path d="M214.47,350.3858 C135.44,360.2358 39.83,378.3058 14.79,409.5158 C-18.81,451.3958 56.27,478.2758 116.14,492.3858 " fill="none" id="Pending-&gt;Trial" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="121.15,493.5458,113.285,487.6178,116.279,492.4174,111.4794,495.4114,121.15,493.5458" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="268" x="15.79" y="424.4129">reset [attempts left &gt; 0]; save attempts left - 1</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="165" x="67.29" y="442.1189">before handing control to B</text><!--MD5=[83187eb056d347350e70da73cc8be795]
link Trial to Pending--><path d="M240.34,482.2458 C257.83,473.3358 275.76,461.5458 288.79,446.5158 C306.79,425.7758 316.75,396.0258 322.09,373.2358 " fill="none" id="Trial-&gt;Pending" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="323.23,368.1958,317.3509,376.0975,322.1318,373.0737,325.1555,377.8547,323.23,368.1958" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="152" x="336.79" y="424.4129">reset before confirmation</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="202" x="311.79" y="442.1189">(power loss or covered watchdog)</text><!--MD5=[123c6cef540f58bde17912cb320a2a04]
link Trial to Confirmed--><path d="M121.13,518.1258 C95.2,526.4458 67.26,540.5958 51.79,564.5158 C24.03,607.4358 36.74,669.8958 48.07,706.2458 " fill="none" id="Trial-&gt;Confirmed" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="49.73,711.4158,50.7935,701.6246,48.2046,706.6542,43.1749,704.0653,49.73,711.4158" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="202" x="52.79" y="579.4129">local checks pass within time limit;</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="107" x="100.29" y="597.1189">save confirmation</text><!--MD5=[788b26dbcee76df69ae24d57af56fb68]
link Trial to Recovering--><path d="M224.17,534.5358 C237.29,543.6058 251.47,554.0458 263.79,564.5158 C281.28,579.3758 282.32,586.6458 299.79,601.5158 C310.76,610.8458 323.3,620.1558 335.04,628.3558 " fill="none" id="Trial-&gt;Recovering" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="339.32,631.3258,334.2093,622.9068,335.2132,628.4739,329.6461,629.4778,339.32,631.3258" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="227" x="300.79" y="588.4129">local checks fail; save recovery request</text><!--MD5=[8cd5eda113903aa9882c5f6ff29c10bf]
link Pending to Recovering--><path d="M420.65,368.0558 C467.5,383.0958 515.89,400.3758 522.79,409.5158 C574.26,477.7258 582.36,531.9058 532.79,601.5158 C517.44,623.0758 492.87,636.1058 467.72,643.9558 " fill="none" id="Pending-&gt;Recovering" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="462.69,645.4558,472.4581,646.7144,467.4811,644.0257,470.1698,639.0487,462.69,645.4558" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="132" x="567.79" y="510.9129">reset; no attempts left</text><!--MD5=[09dc23c1c901f79ee75b5b595eb0935b]
link Recovering to Recovery--><path d="M376.79,681.8558 C376.79,710.0058 376.79,756.3158 376.79,786.3658 " fill="none" id="Recovering-&gt;Recovery" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="376.79,791.4058,380.79,782.4058,376.79,786.4058,372.79,782.4058,376.79,791.4058" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="181" x="377.79" y="741.9129">boot control selects A on reset</text><!--MD5=[0ce13a800b8a1f17080f923bfff08aab]
link Recovery to Recovered--><path d="M394.33,841.7658 C400.38,850.8158 406.87,861.3658 411.79,871.5158 C421.45,891.4158 429.42,915.1058 434.86,933.3258 " fill="none" id="Recovery-&gt;Recovered" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="436.32,938.3058,437.6132,928.5423,434.9069,933.5097,429.9394,930.8033,436.32,938.3058" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="158" x="427.79" y="886.4129">local recovery checks pass;</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="84" x="464.79" y="904.1189">save outcome</text><!--MD5=[f5fa9e9e750dea8a99a710e758197f77]
link Recovery to Failed--><path d="M302.24,820.0058 C264.54,825.5258 221.8,839.2058 197.79,871.5158 C184.65,889.2058 190.22,914.1058 198.2,933.3958 " fill="none" id="Recovery-&gt;Failed" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="200.28,938.1658,200.3743,928.3174,198.2932,933.5775,193.0331,931.4964,200.28,938.1658" style="stroke: #383838; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="204" x="198.79" y="886.4129">recovery checks fail or startup fails</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="153" x="224.29" y="904.1189">(platform recovery policy)</text><!--MD5=[4470f671c244ee8b6362840b5fcd1a01]
link Confirmed to *end--><path d="M55.63,761.7058 C50.69,809.4758 46.14,917.4358 93.79,988.5158 C119.37,1026.6658 173.31,1046.7958 199.25,1054.6058 " fill="none" id="Confirmed-&gt;*end" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="204.34,1056.0858,196.82,1049.7258,199.54,1054.6858,194.58,1057.4058,204.34,1056.0858" style="stroke: #383838; stroke-width: 1.0;"/><!--MD5=[95cc10cd26e44889f83ba83c5e220ef1]
link Recovered to *end--><path d="M384.12,988.6058 C331.5,1010.1958 258.07,1040.3458 227.74,1052.7858 " fill="none" id="Recovered-&gt;*end" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="222.92,1054.7658,232.764,1055.0745,227.5505,1052.8794,229.7456,1047.6658,222.92,1054.7658" style="stroke: #383838; stroke-width: 1.0;"/><!--MD5=[3c91aadb35076bbec70261ad1b979304]
link Failed to *end--><path d="M213.79,988.7258 C213.79,1006.3558 213.79,1029.6458 213.79,1044.3558 " fill="none" id="Failed-&gt;*end" style="stroke: #383838; stroke-width: 1.0;"/><polygon fill="#383838" points="213.79,1049.3558,217.79,1040.3558,213.79,1044.3558,209.79,1040.3558,213.79,1049.3558" style="stroke: #383838; stroke-width: 1.0;"/><rect fill="#DDDDDD" height="67.2038" rx="5" ry="5" style="stroke: #000000; stroke-width: 1.0;" width="562" x="237" y="1087.5158"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="501" x="243" y="1107.4818">Preparation interruption assumes the installer preserves A and boot state.</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="550" x="243" y="1126.5497">State transitions assume valid durable records; torn writes need platform testing.</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="399" x="243" y="1145.6176">Checks and recovery are local; reports wait for connectivity.</text><!--MD5=[d4e2cf11ff88427b3c50e83f198cfc1a]
@startuml
title A/B trial boot and recovery
skinparam shadowing false
skinparam monochrome true
state "A confirmed" as A
state "Prepare B\nA remains the normal boot choice" as Preparing
state "B prepared and verified" as Prepared
state "B trial pending\nSaved target and attempt limit" as Pending
state "B trial running\nUnconfirmed" as Trial
state "B confirmed" as Confirmed
state "Recovery to A pending" as Recovering
state "A recovery running" as Recovery
state "A recovery checked" as Recovered
state "Separate recovery required" as Failed
[*] - -> A
A - -> Preparing : begin installation
Preparing - -> Preparing : reset during preparation; boot A\nB is not eligible for trial
Preparing - -> A : abandon incomplete or failed preparation
Preparing - -> Prepared : installation and verification complete
Prepared - -> Pending : save trial request through boot control
Pending - -> Trial : reset [attempts left > 0]; save attempts left - 1\nbefore handing control to B
Trial - -> Confirmed : local checks pass within time limit;\nsave confirmation
Trial - -> Recovering : local checks fail; save recovery request
Trial - -> Pending : reset before confirmation\n(power loss or covered watchdog)
Pending - -> Recovering : reset; no attempts left
Recovering - -> Recovery : boot control selects A on reset
Recovery - -> Recovered : local recovery checks pass;\nsave outcome
Recovery - -> Failed : recovery checks fail or startup fails\n(platform recovery policy)
Confirmed - -> [*]
Recovered - -> [*]
Failed - -> [*]
note right of Pending
Boot state is outside A and B.
Attempts are consumed before starting B.
Invalid records require a platform-defined
recovery path, never implicit confirmation.
end note
note right of Recovery
A must still be compatible with shared data.
Do not endlessly alternate failed systems.
end note
legend bottom
Preparation interruption assumes the installer preserves A and boot state.
State transitions assume valid durable records; torn writes need platform testing.
Checks and recovery are local; reports wait for connectivity.
endlegend
@enduml
PlantUML version 1.2020.02(Sun Mar 01 05:22:07 EST 2020)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Java Version: 21.0.12.1+1-1-deb13u1-Debian
Operating System: Linux
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>