You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
C4-PlantUML/C4.puml

632 lines
20 KiB
Plaintext

' C4-PlantUML
' Colors
' ##################################
!global $ELEMENT_FONT_COLOR = "#FFFFFF"
!global $ARROW_COLOR = "#666666"
!global $BOUNDARY_COLOR = "#444444"
!global $LEGEND_FONT_COLOR = "#FFFFFF"
!global $LEGEND_TITLE_COLOR = "#000000"
!global $LEGEND_UNDEFINED_BG_COLOR = "#D5CFEE"
!global $LEGEND_UNDEFINED_FONT_COLOR = "#8B77E4"
!global $LEGEND_SHADOW_TEXT = "(shadow) "
!global $LEGEND_NO_SHADOW_TEXT = "(no shadow) "
!global $LEGEND_NO_FONT_BG_TEXT = "(no text, no back color) "
!global $LEGEND_NO_FONT_TEXT = "(no text color) "
!global $LEGEND_NO_BG_TEXT = "(no back color) "
!global $LEGEND_NO_LINE_TEXT = "(no line color) "
' Styling
' ##################################
!global $TECHN_FONT_SIZE = 12
skinparam defaultTextAlignment center
skinparam wrapWidth 200
skinparam maxMessageSize 150
skinparam LegendBorderColor transparent
skinparam LegendBackgroundColor transparent
skinparam LegendFontColor $LEGEND_FONT_COLOR
skinparam rectangle {
StereotypeFontSize 12
shadowing false
}
skinparam database {
StereotypeFontSize 12
shadowing false
}
skinparam queue {
StereotypeFontSize 12
shadowing false
}
skinparam Arrow {
Color $ARROW_COLOR
FontColor $ARROW_COLOR
FontSize 12
}
skinparam rectangle<<boundary>> {
Shadowing false
StereotypeFontSize 0
FontColor $BOUNDARY_COLOR
BorderColor $BOUNDARY_COLOR
BorderStyle dashed
}
' Legend and Tags
' ##################################
!global $tagDefaultLegend = ""
!global $tagCustomLegend = ""
' rel specific
!unquoted function $toStereos($tags)
!if (%strlen($tags) == 0)
!return ''
!endif
!$stereos = ''
!$brPos = %strpos($tags, "+")
!while ($brPos >= 0)
!$tag = %substr($tags, 0, $brPos)
!$stereos = $stereos + '<<' + $tag + '>>'
%set_variable_value("$" + $tag + "_LineLegend", %true())
!$tags = %substr($tags, $brPos+1)
!$brPos = %strpos($tags, "+")
!endwhile
!if (%strlen($tags)>0)
!$stereos = $stereos + '<<' + $tags + '>>'
%set_variable_value("$" + $tags + "_LineLegend", %true())
!endif
!return $stereos
!endfunction
!unquoted function $toStereos($elementType, $tags)
!if (%strlen($tags) == 0)
!$stereos = '<<' + $elementType + '>>'
%set_variable_value("$" + $elementType + "Legend", %true())
!return $stereos
!endif
!$stereos = ''
!$brPos = %strpos($tags, "+")
!while ($brPos >= 0)
!$tag = %substr($tags, 0, $brPos)
!$stereos = $stereos + '<<' + $tag + '>>'
%set_variable_value("$" + $tag + "Legend", %true())
!$tags = %substr($tags, $brPos+1)
!$brPos = %strpos($tags, "+")
!endwhile
!if (%strlen($tags)>0)
!$stereos = $stereos + '<<' + $tags + '>>'
%set_variable_value("$" + $tags + "Legend", %true())
!endif
' has to be last, otherwise PlantUML overwrites all tag specific skinparams
!$stereos = $stereos + '<<' + $elementType + '>>'
%set_variable_value("$" + $elementType + "Legend", %true())
!return $stereos
!endfunction
!function $elementTagSkinparams($element, $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!$elementSkin = "skinparam " + $element +"<<" + $tagStereo + ">> {" + %newline()
!if ($fontColor!="")
!$elementSkin = $elementSkin + " StereotypeFontColor " + $fontColor + %newline()
!$elementSkin = $elementSkin + " FontColor " + $fontColor + %newline()
!endif
!if ($bgColor!="")
!$elementSkin = $elementSkin + " BackgroundColor " + $bgColor + %newline()
!endif
!if ($borderColor!="")
!$elementSkin = $elementSkin + " BorderColor " + $borderColor+ %newline()
!endif
!if ($shadowing == "true")
!$elementSkin = $elementSkin + " Shadowing<<" + $tagStereo + ">> " + "true" + %newline()
!endif
!if ($shadowing == "false")
!$elementSkin = $elementSkin + " Shadowing<<" + $tagStereo + ">> " + "false" + %newline()
!endif
!$elementSkin = $elementSkin + "}" + %newline()
!return $elementSkin
!endfunction
!unquoted procedure $defineSkinparams($tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!$tagSkin = $elementTagSkinparams("rectangle", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!$tagSkin = $tagSkin + $elementTagSkinparams("database", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!$tagSkin = $tagSkin + $elementTagSkinparams("queue", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
$tagSkin
!endprocedure
' arrow colors cannot start with # (legend background has to start with #)
!function ColorNoHash($c)
!if (%substr($c, 0, 1) == "#")
!$c = %substr($c,1)
!endif
!return $c
!endfunction
!unquoted procedure $defineRelSkinparams($tagStereo, $textColor, $lineColor)
!$elementSkin = "skinparam Arrow<<" + $tagStereo + ">> {" + %newline()
!$elementSkin = $elementSkin + " Color "
!if ($lineColor!="")
!$elementSkin = $elementSkin + ColorNoHash($lineColor)
!endif
!if ($textColor!="")
!$elementSkin = $elementSkin + ";text:" + ColorNoHash($textColor)
!endif
!$elementSkin = $elementSkin + %newline()
!$elementSkin = $elementSkin + "}" + %newline()
$elementSkin
!endprocedure
!function $tagLegendEntry($tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!$tagEntry = "|"
!if ($bgColor!="")
!$bg = $bgColor
!else
!$bg = $LEGEND_UNDEFINED_BG_COLOR
!endif
' named colors have to start with # too
!if (%substr($bg, 0, 1) != "#")
!$bg = "#" + $bg
!endif
!$tagEntry = $tagEntry + "<" + $bg +">"
' <U+25AF> ..white rectangle
!if ($borderColor!="")
!$tagEntry = $tagEntry + "<color:"+$borderColor+"> <U+25AF></color> "
!else
!$tagEntry = $tagEntry + "<color:"+$bg+"> <U+25AF></color> "
!endif
!if ($fontColor!="")
!$tagEntry = $tagEntry + "<color:"+$fontColor+">"
!else
!$tagEntry = $tagEntry + "<color:"+$LEGEND_UNDEFINED_FONT_COLOR+">"
!endif
!$tagEntry = $tagEntry + " " + $tagStereo + " "
!if ($shadowing == "true")
!$tagEntry = $tagEntry + $LEGEND_SHADOW_TEXT
!endif
!if ($shadowing == "false")
!$tagEntry = $tagEntry + $LEGEND_NO_SHADOW_TEXT
!endif
!if ($fontColor == "" && $bgColor == "")
!$tagEntry = $tagEntry + $LEGEND_NO_FONT_BG_TEXT
!else
!if ($fontColor == "")
!$tagEntry = $tagEntry + $LEGEND_NO_FONT_TEXT
!endif
!if ($bgColor == "")
!$tagEntry = $tagEntry + $LEGEND_NO_BG_TEXT
!endif
!endif
!$tagEntry = $tagEntry + "</color> "
!$tagEntry = $tagEntry + "|"
!return $tagEntry
!endfunction
!function $tagRelLegendEntry($tagStereo, $textColor, $lineColor)
!$tagEntry = "|"
!$bg = $LEGEND_UNDEFINED_BG_COLOR
' named colors have to start with # too
!if (%substr($bg, 0, 1) != "#")
!$bg = "#" + $bg
!endif
' !$tagEntry = $tagEntry + "<" + $bg +">"
' <U+2500> ..white line
!if ($lineColor!="")
!$tagEntry = $tagEntry + "<color:"+$lineColor+"> <U+2500></color> "
!else
' !$tagEntry = $tagEntry + "<color:"+$bg+"> <U+2500></color> "
!$tagEntry = $tagEntry + " <U+2500> "
!endif
!if ($textColor!="")
!$tagEntry = $tagEntry + "<color:"+$textColor+">"
!else
!$tagEntry = $tagEntry + "<color:"+$LEGEND_UNDEFINED_FONT_COLOR+">"
!endif
!$tagEntry = $tagEntry + " " + $tagStereo + " "
!if ($textColor == "")
!$tagEntry = $tagEntry + $LEGEND_NO_FONT_TEXT
!endif
!if ($lineColor == "")
!$tagEntry = $tagEntry + $LEGEND_NO_LINE_TEXT
!endif
!$tagEntry = $tagEntry + "</color> "
!$tagEntry = $tagEntry + "|"
!return $tagEntry
!endfunction
!unquoted procedure $addTagToLegend($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="")
'' ignore workaround tags with &
' !if (%strpos($tagStereo, "&")<0)
!$tagEntry = $tagLegendEntry($tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
%set_variable_value("$" + $tagStereo + "LegendEntry", $tagEntry)
!$tagCustomLegend = $tagCustomLegend + $tagStereo + "\n"
' !endif
!endprocedure
!unquoted procedure $addRelTagToLegend($tagStereo, $textColor="", $lineColor="")
'' ignore workaround tags with &
' !if (%strpos($tagStereo, "&")<0)
!$tagEntry = $tagRelLegendEntry($tagStereo, $textColor, $lineColor)
%set_variable_value("$" + $tagStereo + "_LineLegendEntry", $tagEntry)
!$tagCustomLegend = $tagCustomLegend + $tagStereo + "_Line\n"
' !endif
!endprocedure
!procedure $showActiveLegendEntries($allDefined)
!$brPos = %strpos($allDefined, "\n")
!while ($brPos >= 0)
!$tagStereo = %substr($allDefined, 0, $brPos)
!$allDefined = %substr($allDefined, $brPos+2)
!$brPos = %strpos($allDefined, "\n")
!if (%variable_exists("$" + $tagStereo + "Legend"))
%get_variable_value("$" + $tagStereo + "LegendEntry")
!endif
!endwhile
!if (%strlen($allDefined)>0)
!$tagStereo = $allDefined
!if (%variable_exists("$" + $tagStereo + "Legend"))
%get_variable_value("$" + $tagStereo + "LegendEntry")
!endif
!endif
!endprocedure
' used by new defined tags
!unquoted procedure AddElementTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="")
$defineSkinparams($tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
$addTagToLegend($tagStereo, $bgColor, $fontColor, $borderColor, $shadowing)
!endprocedure
' used by new defined rel tags
!unquoted procedure AddRelTag($tagStereo, $textColor="", $lineColor="")
$defineRelSkinparams($tagStereo, $textColor, $lineColor)
$addRelTagToLegend($tagStereo, $textColor, $lineColor)
!endprocedure
' update the style of existing elements like person, ...
!unquoted procedure UpdateElementStyle($elementName, $bgColor="", $fontColor="", $borderColor="", $shadowing="")
$defineSkinparams($elementName, $bgColor, $fontColor, $borderColor, $shadowing)
!$tagEntry = $tagLegendEntry($elementName, $bgColor, $fontColor, $borderColor, $shadowing)
%set_variable_value("$" + $elementName + "LegendEntry", $tagEntry)
!endprocedure
' update the style of default relation, it has to set both properties (combined statement not working)
!unquoted procedure UpdateRelStyle($textColor, $lineColor)
!$elementSkin = "skinparam Arrow {" + %newline()
!$elementSkin = $elementSkin + " Color " + $lineColor + %newline()
!$elementSkin = $elementSkin + " FontColor " + $textColor + %newline()
!$elementSkin = $elementSkin + "}" + %newline()
$elementSkin
!endprocedure
' tags/stereotypes have to be delimited with \n
!unquoted procedure SetDefaultLegendEntries($tagStereoEntries)
!$tagDefaultLegend = $tagStereoEntries
!endprocedure
' Line breaks
' ##################################
' PlantUML supports no DETERMINISTIC/automatic line breaks of "PlantUML line" (C4 Relashionships)
' therefore Rel...() implements an automatic line break based on spaces (like in all other objects).
' If a $type contains \n then these are used (and no automatic space based line breaks are done)
' $REL_TECHN_MAX_CHAR_WIDTH defines the automatic line break position
!global $REL_TECHN_MAX_CHAR_WIDTH = 35
!global $REL_DESCR_MAX_CHAR_WIDTH = 32
!unquoted function $breakDescr($descr, $widthStr)
!$width = %intval($widthStr)
!$multiLine = ""
!if (%strpos($descr, "\n") >= 0)
!else
!while (%strlen($descr)>$width)
!$brPos = $width
!while ($brPos>0 && %substr($descr, $brPos, 1)!= ' ')
!$brPos = $brPos - 1
!endwhile
!if ($brPos < 1)
!$brPos = %strpos($descr, " ")
!else
!endif
!if ($brPos > 0)
!$multiLine = $multiLine + %substr($descr, 0, $brPos) + "\n"
!$descr = %substr($descr, $brPos + 1)
!else
!$multiLine = $multiLine+ $descr
!$descr = ""
!endif
!endwhile
!endif
!if (%strlen($descr)>0)
!$multiLine = $multiLine + $descr
!endif
!return $multiLine
!endfunction
' $breakTechn() supports //...//; $breakNode() in C4_Deployment supports no //....//
!unquoted function $breakTechn($techn, $widthStr)
!$width = %intval($widthStr)
!$multiLine = ""
!if (%strpos($techn, "\n") >= 0)
!while (%strpos($techn, "\n") >= 0)
!$brPos = %strpos($techn, "\n")
!$multiLine = $multiLine + %substr($techn, 0, $brPos) + '</size>//\n//<size:'+$TECHN_FONT_SIZE+'>'
!$techn = %substr($techn, $brPos+2)
!endwhile
!else
!while (%strlen($techn)>$width)
!$brPos = $width
!while ($brPos>0 && %substr($techn, $brPos, 1)!= ' ')
!$brPos = $brPos - 1
!endwhile
!if ($brPos < 1)
!$brPos = %strpos($techn, " ")
!else
!endif
!if ($brPos > 0)
!$multiLine = $multiLine + %substr($techn, 0, $brPos) + '</size>//\n//<size:'+$TECHN_FONT_SIZE+'>'
!$techn = %substr($techn, $brPos + 1)
!else
!$multiLine = $multiLine+ $techn
!$techn = ""
!endif
!endwhile
!endif
!if (%strlen($techn)>0)
!$multiLine = $multiLine + $techn
!endif
!return $multiLine
!endfunction
' Element properties
' ##################################
' collect all defined properties as table rows
!global $propTable = ""
!global $propTableCaption = ""
!global $propColCaption = "="
!unquoted function SetPropertyHeader($col1Name, $col2Name, $col3Name = "", $col4Name = "")
!$propColCaption = ""
!$propTableCaption = "|= " + $col1Name + " |= " + $col2Name + " |"
!if ($col3Name != "")
!$propTableCaption = $propTableCaption + "= " + $col3Name + " |"
!endif
!if ($col4Name != "")
!$propTableCaption = $propTableCaption + "= " + $col4Name + " |"
!endif
!return ""
!endfunction
!unquoted function WithoutPropertyHeader()
!$propTableCaption = ""
!$propColCaption = "="
!return ""
!endfunction
!unquoted function AddProperty($col1, $col2, $col3 = "", $col4 = "")
!if ($propTable == "")
!if ($propTableCaption != "")
!$propTable = $propTableCaption + "\n"
!endif
!else
!$propTable = $propTable + "\n"
!endif
!$propTable = $propTable + "| " + $col1 + " |" + $propColCaption + " " + $col2 + " |"
!if ($col3 != "")
!$propTable = $propTable + " " + $col3 + " |"
!endif
!if ($col4 != "")
!$propTable = $propTable + " " + $col4 + " |"
!endif
!return ""
!endfunction
!unquoted function $getProps($alignedNL = "\n")
!if ($propTable != "")
!$retTable = $alignedNL + $propTable
!$propTable = ""
!return $retTable
!endif
!return ""
!endfunction
!unquoted function $getProps_L()
!return $getProps("\l")
!endfunction
!unquoted function $getProps_R()
!return $getProps("\r")
!endfunction
SetPropertyHeader("Property","Value")
' Layout
' ##################################
!procedure HIDE_STEREOTYPE()
hide stereotype
!endprocedure
!procedure LAYOUT_AS_SKETCH()
skinparam backgroundColor #EEEBDC
skinparam handwritten true
skinparam defaultFontName "Comic Sans MS"
center footer <font color=red>Warning:</font> Created for discussion, needs to be validated
!endprocedure
!procedure LAYOUT_TOP_DOWN()
top to bottom direction
!endprocedure
!procedure LAYOUT_LEFT_RIGHT()
left to right direction
!endprocedure
' has to be last call in diagram
!unquoted procedure SHOW_LEGEND($hideStereotype="true")
!if ($hideStereotype=="true")
hide stereotype
!endif
legend right
|<color:$LEGEND_TITLE_COLOR>**Legend**</color> |
$showActiveLegendEntries($tagDefaultLegend)
$showActiveLegendEntries($tagCustomLegend)
endlegend
!endprocedure
' Boundaries
' ##################################
!function $getBoundary($label, $type)
!if ($type == "")
!return '==' + $label
!endif
!if (type != "")
!return '==' + $label + '\n<size:' + $TECHN_FONT_SIZE + '>[' + $type + ']</size>'
!endif
!endfunction
!unquoted procedure Boundary($alias, $label, $type="", $tags="")
rectangle "$getBoundary($label, $type)" $toStereos("boundary", $tags) as $alias
!endprocedure
' Relationship
' ##################################
!function $getRel($direction, $alias1, $alias2, $label, $techn, $descr, $sprite, $tags)
!$rel = $alias1 + ' ' + $direction + ' ' + $alias2
!if ($tags != "")
!$rel = $rel + ' ' + $toStereos($tags)
!endif
!$rel = $rel + ' : '
!if ($sprite != "")
' if it starts with & it's a OpenIconic, details see https://useiconic.com/open/
!if (%substr($sprite, 0, 1) != "&")
!$rel = $rel + '<$'+$sprite+'> '
!else
!$rel = $rel + '<'+$sprite+'> '
!endif
!endif
!$rel = $rel + '**' + $label + '**'
!if ($techn != "")
' line break is not deterministic, calculate it
!$rel = $rel + '\n//<size:' + $TECHN_FONT_SIZE + '>[' + $breakTechn($techn, $REL_TECHN_MAX_CHAR_WIDTH) + ']</size>//'
!endif
!if ($descr != "")
' line break is not deterministic, calculate it
!$rel = $rel + '\n\n' + $breakDescr($descr, $REL_DESCR_MAX_CHAR_WIDTH)
!endif
!return $rel
!endfunction
!unquoted procedure Rel_($alias1, $alias2, $label, $direction)
$alias1 $direction $alias2 : **$label**
!endprocedure
!unquoted procedure Rel_($alias1, $alias2, $label, $techn, $direction)
$alias1 $direction $alias2 : **$label**\n//<size:$TECHN_FONT_SIZE>[$techn]</size>//
!endprocedure
!unquoted procedure Rel($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Back($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<--", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Neighbor($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Back_Neighbor($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_D($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-DOWN->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Down($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-DOWN->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_D($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-DOWN->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_Down($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-DOWN->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_U($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-UP->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Up($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-UP->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_U($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-UP->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_Up($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-UP->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_L($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-LEFT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Left($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-LEFT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_L($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-LEFT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_Left($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-LEFT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_R($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-RIGHT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure Rel_Right($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("-RIGHT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_R($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-RIGHT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
!unquoted procedure BiRel_Right($from, $to, $label, $techn="", $descr="", $sprite="", $tags="")
$getRel("<<-RIGHT->>", $from, $to, $label, $techn, $descr, $sprite, $tags)
!endprocedure
' Layout Helpers
' ##################################
!unquoted procedure Lay_D($from, $to)
$from -[hidden]D- $to
!endprocedure
!unquoted procedure Lay_U($from, $to)
$from -[hidden]U- $to
!endprocedure
!unquoted procedure Lay_R($from, $to)
$from -[hidden]R- $to
!endprocedure
!unquoted procedure Lay_L($from, $to)
$from -[hidden]L- $to
!endprocedure