From 46d3941013861a730e430200a0cc12cd6e0e1172 Mon Sep 17 00:00:00 2001 From: KIRCHSTH Date: Sun, 11 Feb 2024 01:53:49 +0100 Subject: [PATCH 1/2] Update C4-PlantUML to v2.9.0 --- C4/C4.puml | 96 ++++++++++++++++++++++++++++++++++++++++++- C4/C4_Component.puml | 8 ++-- C4/C4_Container.puml | 8 ++-- C4/C4_Context.puml | 8 ++-- C4/C4_Deployment.puml | 2 +- C4/C4_Sequence.puml | 12 +++--- C4/INFO | 2 +- README.md | 30 ++++++++++++++ 8 files changed, 144 insertions(+), 22 deletions(-) diff --git a/C4/C4.puml b/C4/C4.puml index 755acd22..9ddb8cba 100644 --- a/C4/C4.puml +++ b/C4/C4.puml @@ -1,10 +1,19 @@ ' C4-PlantUML +' Global pre-settings +' ################################## +' ENABLE_ALL_PLANT_ELEMENTS +' If ENABLE_ALL_PLANT_ELEMENTS is set BEFORE the first C4_* file is loaded, nearly "all" PlantUML elements can be used like +' Component(StorageA, "Storage A ", $baseShape="storage") +' ENABLE_ALL_PLANT_ELEMENTS can be set via +' !ENABLE_ALL_PLANT_ELEMENTS = 1 +' or with additional command line argument -DENABLE_ALL_PLANT_ELEMENTS=1 + 'Version ' ################################## !function C4Version() ' 2 spaces and ' are used as unique marker, that the release scripts makes the correct version update - !$c4Version = "2.8.0" + !$c4Version = "2.9.0" !return $c4Version !end function @@ -159,6 +168,66 @@ skinparam actor { style awesome } +!if %variable_exists("ENABLE_ALL_PLANT_ELEMENTS") +skinparam agent { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam artifact { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam boundary { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam card { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam circle { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam cloud { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam collections { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam control { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam entity { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam file { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam folder { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam frame { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam hexagon { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam interface { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam label { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam stack { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam storage { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam usecase { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +skinparam person { + StereotypeFontSize $STEREOTYPE_FONT_SIZE +} +!endif + ' Some boundary skinparams have to be set as package skinparams too (PlantUML uses internal packages) ' UpdateBoundaryStyle() called in boundary section below skinparam rectangle<> { @@ -378,6 +447,29 @@ skinparam package { !$tagSkin = $tagSkin + "skinparam package<<" + $tagStereo + ">>StereotypeFontColor " + $bgColor + %newline() !$tagSkin = $tagSkin + "skinparam rectangle<<" + $tagStereo + ">>StereotypeFontColor " + $bgColor + %newline() !endif + !if %variable_exists("ENABLE_ALL_PLANT_ELEMENTS") + !$tagSkin = $tagSkin + $elementTagSkinparams("agent", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("artifact", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("card", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("cloud", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("collections", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("file", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("folder", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("frame", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("hexagon", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("package", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("stack", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("storage", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("usecase", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + ' elements without background: font uses $bgColor + !$tagSkin = $tagSkin + $elementTagSkinparams("boundary", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("circle", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("control", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("entity", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !$tagSkin = $tagSkin + $elementTagSkinparams("interface", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + ' label uses wrong font color? (should be $bgColor too) + !$tagSkin = $tagSkin + $elementTagSkinparams("label", $tagStereo, $bgColor, $bgColor, $borderColor, $shadowing, "", $borderStyle, $borderThickness) + !endif $tagSkin !endprocedure @@ -1274,7 +1366,7 @@ SHOW_LEGEND($hideStereotype) !endfunction ' enables that legend can be located in drawing area of the diagram. It has to be last call in diagram followed by Lay_Distance() -!unquoted procedure SHOW_FLOATING_LEGEND($alias=LEGEND(), $hideStereotype="true", $details=Normal()) +!unquoted procedure SHOW_FLOATING_LEGEND($alias=LEGEND(), $hideStereotype="true", $details=Small()) $getLegendArea($alias, $hideStereotype, $details) !endprocedure diff --git a/C4/C4_Component.puml b/C4/C4_Component.puml index c0934809..185b924d 100644 --- a/C4/C4_Component.puml +++ b/C4/C4_Component.puml @@ -53,8 +53,8 @@ endlegend ' Elements ' ################################## -!unquoted procedure Component($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") - $getElementLine("rectangle", "component", $alias, $label, $techn, $descr, $sprite, $tags, $link) +!unquoted procedure Component($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") + $getElementLine($baseShape, "component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure ComponentDb($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") @@ -65,8 +65,8 @@ endlegend $getElementLine("queue", "component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") - $getElementLine("rectangle", "external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link) +!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") + $getElementLine($baseShape, "external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure ComponentDb_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") diff --git a/C4/C4_Container.puml b/C4/C4_Container.puml index afafcef1..3706f023 100644 --- a/C4/C4_Container.puml +++ b/C4/C4_Container.puml @@ -60,8 +60,8 @@ endlegend ' Elements ' ################################## -!unquoted procedure Container($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") - $getElementLine("rectangle", "container", $alias, $label, $techn, $descr, $sprite, $tags, $link) +!unquoted procedure Container($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") + $getElementLine($baseShape , "container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure ContainerDb($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") @@ -72,8 +72,8 @@ endlegend $getElementLine("queue", "container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") - $getElementLine("rectangle", "external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link) +!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") + $getElementLine($baseShape , "external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure ContainerDb_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") diff --git a/C4/C4_Context.puml b/C4/C4_Context.puml index 32a84415..6e97729f 100644 --- a/C4/C4_Context.puml +++ b/C4/C4_Context.puml @@ -375,9 +375,9 @@ rectangle "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("ex !endif !endprocedure -!unquoted procedure System($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") +!unquoted procedure System($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle") ' $type reuses $techn definition of $tags - $getElementLine("rectangle", "system", $alias, $label, $type, $descr, $sprite, $tags, $link) + $getElementLine($baseShape, "system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure SystemDb($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") @@ -390,9 +390,9 @@ rectangle "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("ex $getElementLine("queue", "system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure System_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") +!unquoted procedure System_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle") ' $type reuses $techn definition of $tags - $getElementLine("rectangle", "external_system", $alias, $label, $type, $descr, $sprite, $tags, $link) + $getElementLine($baseShape , "external_system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure !unquoted procedure SystemDb_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") diff --git a/C4/C4_Deployment.puml b/C4/C4_Deployment.puml index 2d51fa0d..a4f501b0 100644 --- a/C4/C4_Deployment.puml +++ b/C4/C4_Deployment.puml @@ -26,7 +26,7 @@ skinparam rectangle<> { ' node specific: $techn is only used in old scripts, new scripts uses $type ($techn has to remain, it could be called via named argument) !unquoted procedure AddNodeTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $type="", $legendText="", $legendSprite="", $techn="", $borderStyle="", $borderThickness="") !$type=$type+$techn - $addElementTagInclReuse("node", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, "", $borderStyle, $borderThickness) + $addElementTagInclReuse("node", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, $borderStyle, $borderThickness) !endprocedure ' Layout diff --git a/C4/C4_Sequence.puml b/C4/C4_Sequence.puml index 1445b869..49cbc4ab 100644 --- a/C4/C4_Sequence.puml +++ b/C4/C4_Sequence.puml @@ -227,7 +227,7 @@ $calcDescr $getParticipant("external_person", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure System($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") +!unquoted procedure System($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle") ' $type reuses $techn definition of $tags $getParticipant("system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure @@ -242,7 +242,7 @@ $calcDescr $getParticipant("system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure System_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="") +!unquoted procedure System_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle") ' $type reuses $techn definition of $tags $getParticipant("external_system", $alias, $label, $type, $descr, $sprite, $tags, $link) !endprocedure @@ -259,7 +259,7 @@ $calcDescr -!unquoted procedure Container($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") +!unquoted procedure Container($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") $getParticipant("container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure @@ -271,7 +271,7 @@ $calcDescr $getParticipant("container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") +!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") $getParticipant("external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure @@ -285,7 +285,7 @@ $calcDescr -!unquoted procedure Component($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") +!unquoted procedure Component($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") $getParticipant("component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure @@ -297,7 +297,7 @@ $calcDescr $getParticipant("component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure -!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="") +!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle") $getParticipant("external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link) !endprocedure diff --git a/C4/INFO b/C4/INFO index 3553424d..10a6c12c 100644 --- a/C4/INFO +++ b/C4/INFO @@ -1,2 +1,2 @@ -VERSION=2.8.0 +VERSION=2.9.0 SOURCE=https://github.com/plantuml-stdlib/C4-PlantUML diff --git a/README.md b/README.md index db9bf109..c112eca9 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,36 @@ This example renders the following image: ![Example](http://www.plantuml.com/plantuml/proxy?idx=0&src=https%3A%2F%2Fraw.githubusercontent.com%2FRicardoNiepel%2FAzure-PlantUML%2Fmaster%2Fsamples%2FBasic%2520usage%2520-%2520Stream%2520processing%2520with%2520Azure%2520Stream%2520Analytics.puml "Example") +## C4 library (C4-PlantUML) + +The C4 library enables a simple way of describing and communicate software architectures with an intuitive language. + +It is the PlantUML integrated version of [C4-PlantUML](https://github.com/plantuml-stdlib/C4-PlantUML) and has the big advantage that it can be used without additional external includes. +(E.g. container diagrams can be drawn with `!include ` and no `!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml` is required.) + +Example of usage: + +```plantuml +@startuml +!include + +Person(admin, "Administrator") +System_Boundary(c1, "Sample System") { + Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines") +} +System(twitter, "Twitter") + +Rel(admin, web_app, "Uses", "HTTPS") +Rel(web_app, twitter, "Gets tweets from", "HTTPS") + +SHOW_LEGEND() +@enduml +``` + +This example renders the following image: + +[![Example](https://www.plantuml.com/plantuml/png/JOzVIyCm5CNVyockzQM3CPdiKMIrbkr1Px7LFPQilK8WVq9oGndYT_UMpSsyN9BpE-UUh2F9GCbeSQDihzE0y52kxifLLpfBKbaCZqBK6AApkHoCidF8YccgI46I2zbCDCT8QBedb-mWmp7lbmmrqdYDSDAo6NmBu7D9pKSyTD9x9lTuWC9xhNf9ojcCdyhREHHDlTXLBLi2mlrY2Q-VvQGLMhinGefS2iX1xuoNZ9YaIKqhsr4HOG1I1ZNlYbpnvrmofvF8EMUCHV6E-kzprreVaPqyjsrRDqnDq4MzncoG8bzn6b_1cVyMqMpVzjrBjQbsp_bChD4EoUXV)](https://www.plantuml.com/plantuml/uml/JOzVIyCm5CNVyockzQM3CPdiKMIrbkr1Px7LFPQilK8WVq9oGndYT_UMpSsyN9BpE-UUh2F9GCbeSQDihzE0y52kxifLLpfBKbaCZqBK6AApkHoCidF8YccgI46I2zbCDCT8QBedb-mWmp7lbmmrqdYDSDAo6NmBu7D9pKSyTD9x9lTuWC9xhNf9ojcCdyhREHHDlTXLBLi2mlrY2Q-VvQGLMhinGefS2iX1xuoNZ9YaIKqhsr4HOG1I1ZNlYbpnvrmofvF8EMUCHV6E-kzprreVaPqyjsrRDqnDq4MzncoG8bzn6b_1cVyMqMpVzjrBjQbsp_bChD4EoUXV) + ## Classy library The Classy library allows for using an Object Oriented approach to diagramming From 281819515919b84c06056560d05626bb53340455 Mon Sep 17 00:00:00 2001 From: KIRCHSTH Date: Sun, 11 Feb 2024 02:13:03 +0100 Subject: [PATCH 2/2] Update C4-PlantUML to v2.9.0 (change layout in README.md) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c112eca9..8d96b6de 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Example of usage: ```plantuml @startuml !include +LAYOUT_LEFT_RIGHT() Person(admin, "Administrator") System_Boundary(c1, "Sample System") { @@ -108,7 +109,7 @@ SHOW_LEGEND() This example renders the following image: -[![Example](https://www.plantuml.com/plantuml/png/JOzVIyCm5CNVyockzQM3CPdiKMIrbkr1Px7LFPQilK8WVq9oGndYT_UMpSsyN9BpE-UUh2F9GCbeSQDihzE0y52kxifLLpfBKbaCZqBK6AApkHoCidF8YccgI46I2zbCDCT8QBedb-mWmp7lbmmrqdYDSDAo6NmBu7D9pKSyTD9x9lTuWC9xhNf9ojcCdyhREHHDlTXLBLi2mlrY2Q-VvQGLMhinGefS2iX1xuoNZ9YaIKqhsr4HOG1I1ZNlYbpnvrmofvF8EMUCHV6E-kzprreVaPqyjsrRDqnDq4MzncoG8bzn6b_1cVyMqMpVzjrBjQbsp_bChD4EoUXV)](https://www.plantuml.com/plantuml/uml/JOzVIyCm5CNVyockzQM3CPdiKMIrbkr1Px7LFPQilK8WVq9oGndYT_UMpSsyN9BpE-UUh2F9GCbeSQDihzE0y52kxifLLpfBKbaCZqBK6AApkHoCidF8YccgI46I2zbCDCT8QBedb-mWmp7lbmmrqdYDSDAo6NmBu7D9pKSyTD9x9lTuWC9xhNf9ojcCdyhREHHDlTXLBLi2mlrY2Q-VvQGLMhinGefS2iX1xuoNZ9YaIKqhsr4HOG1I1ZNlYbpnvrmofvF8EMUCHV6E-kzprreVaPqyjsrRDqnDq4MzncoG8bzn6b_1cVyMqMpVzjrBjQbsp_bChD4EoUXV) +[![Example](https://www.plantuml.com/plantuml/png/JL1TQy9047o_Nx5DNn8GYyN7KanJgmMhOivAdyAPRE7WFiBT1f7I_zvDjTfxMUvcPcTk9f5KeCuQSQDTRRe6uQ4OtnNZgl2Eb7OO7iKY_rXjPRMOliXgypgRopGJOeqXUfUgncetW2JlfuuK5FcGPA8yHa9RFVdEDIeSqth4f5BPrY2Si2I3Bm5yBaxf0VULQbjcxd0FUTiQNIlItYNyLDmE82_Nm-LKiYGWt0z7yFPUz5XkZ3z4w2A62EIXzhPLJB6T8TrRoeCcmW2aBHhsYXpn-nmofHF8Uyuq1iK6pT_dhh6saPKyvrAkooJx9LtGwvePKkGhzkCpUFjV8ihvQiTTpgRBP-vnWgxX-dy0)](https://www.plantuml.com/plantuml/uml/JL1TQy9047o_Nx5DNn8GYyN7KanJgmMhOivAdyAPRE7WFiBT1f7I_zvDjTfxMUvcPcTk9f5KeCuQSQDTRRe6uQ4OtnNZgl2Eb7OO7iKY_rXjPRMOliXgypgRopGJOeqXUfUgncetW2JlfuuK5FcGPA8yHa9RFVdEDIeSqth4f5BPrY2Si2I3Bm5yBaxf0VULQbjcxd0FUTiQNIlItYNyLDmE82_Nm-LKiYGWt0z7yFPUz5XkZ3z4w2A62EIXzhPLJB6T8TrRoeCcmW2aBHhsYXpn-nmofHF8Uyuq1iK6pT_dhh6saPKyvrAkooJx9LtGwvePKkGhzkCpUFjV8ihvQiTTpgRBP-vnWgxX-dy0) ## Classy library