From 3b94fabb0b8338ab303b3889bac2880d6af6c510 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Fri, 2 Dec 2022 22:47:54 -0800 Subject: [PATCH] add label masks over all connections --- d2layouts/d2sequence/sequence_diagram.go | 7 +-- d2renderers/d2svg/d2svg.go | 56 ++++++++++--------- .../sanity/1_to_2/dagre/sketch.exp.svg | 2 +- .../testdata/sanity/1_to_2/elk/sketch.exp.svg | 2 +- .../sanity/basic/dagre/sketch.exp.svg | 2 +- .../testdata/sanity/basic/elk/sketch.exp.svg | 2 +- .../child_to_child/dagre/sketch.exp.svg | 2 +- .../sanity/child_to_child/elk/sketch.exp.svg | 2 +- .../connection_label/dagre/sketch.exp.svg | 6 +- .../connection_label/elk/sketch.exp.svg | 6 +- .../stable/all_shapes/dagre/sketch.exp.svg | 2 +- .../stable/all_shapes/elk/sketch.exp.svg | 2 +- .../all_shapes_multiple/dagre/sketch.exp.svg | 2 +- .../all_shapes_multiple/elk/sketch.exp.svg | 2 +- .../all_shapes_shadow/dagre/sketch.exp.svg | 2 +- .../all_shapes_shadow/elk/sketch.exp.svg | 2 +- .../arrowhead_adjustment/dagre/sketch.exp.svg | 2 +- .../arrowhead_adjustment/elk/sketch.exp.svg | 2 +- .../arrowhead_labels/dagre/sketch.exp.svg | 6 +- .../arrowhead_labels/elk/sketch.exp.svg | 6 +- .../stable/binary_tree/dagre/sketch.exp.svg | 2 +- .../stable/binary_tree/elk/sketch.exp.svg | 2 +- .../stable/chaos1/dagre/sketch.exp.svg | 8 +-- .../testdata/stable/chaos1/elk/sketch.exp.svg | 8 +-- .../stable/chaos2/dagre/sketch.exp.svg | 20 +------ .../testdata/stable/chaos2/elk/sketch.exp.svg | 20 +------ .../child_parent_edges/dagre/sketch.exp.svg | 2 +- .../child_parent_edges/elk/sketch.exp.svg | 2 +- .../circular_dependency/dagre/sketch.exp.svg | 2 +- .../circular_dependency/elk/sketch.exp.svg | 2 +- .../stable/code_snippet/dagre/sketch.exp.svg | 2 +- .../stable/code_snippet/elk/sketch.exp.svg | 2 +- .../connected_container/dagre/sketch.exp.svg | 2 +- .../connected_container/elk/sketch.exp.svg | 2 +- .../container_edges/dagre/sketch.exp.svg | 2 +- .../stable/container_edges/elk/sketch.exp.svg | 2 +- .../stable/dense/dagre/sketch.exp.svg | 2 +- .../testdata/stable/dense/elk/sketch.exp.svg | 2 +- .../different_subgraphs/dagre/sketch.exp.svg | 2 +- .../different_subgraphs/elk/sketch.exp.svg | 2 +- .../stable/direction/dagre/sketch.exp.svg | 2 +- .../stable/direction/elk/sketch.exp.svg | 2 +- .../stable/font_colors/dagre/sketch.exp.svg | 6 +- .../stable/font_colors/elk/sketch.exp.svg | 6 +- .../stable/font_sizes/dagre/sketch.exp.svg | 10 +--- .../stable/font_sizes/elk/sketch.exp.svg | 10 +--- .../giant_markdown_test/dagre/sketch.exp.svg | 2 +- .../giant_markdown_test/elk/sketch.exp.svg | 2 +- .../testdata/stable/hr/dagre/sketch.exp.svg | 2 +- .../testdata/stable/hr/elk/sketch.exp.svg | 2 +- .../stable/images/dagre/sketch.exp.svg | 2 +- .../testdata/stable/images/elk/sketch.exp.svg | 2 +- .../stable/investigate/dagre/sketch.exp.svg | 16 +----- .../stable/investigate/elk/sketch.exp.svg | 16 +----- .../stable/large_arch/dagre/sketch.exp.svg | 2 +- .../stable/large_arch/elk/sketch.exp.svg | 2 +- .../stable/latex/dagre/sketch.exp.svg | 6 +- .../testdata/stable/latex/elk/sketch.exp.svg | 6 +- .../testdata/stable/li1/dagre/sketch.exp.svg | 2 +- .../testdata/stable/li1/elk/sketch.exp.svg | 2 +- .../testdata/stable/li2/dagre/sketch.exp.svg | 2 +- .../testdata/stable/li2/elk/sketch.exp.svg | 2 +- .../testdata/stable/li3/dagre/sketch.exp.svg | 2 +- .../testdata/stable/li3/elk/sketch.exp.svg | 2 +- .../testdata/stable/li4/dagre/sketch.exp.svg | 2 +- .../testdata/stable/li4/elk/sketch.exp.svg | 2 +- .../stable/lone_h1/dagre/sketch.exp.svg | 2 +- .../stable/lone_h1/elk/sketch.exp.svg | 2 +- .../stable/markdown/dagre/sketch.exp.svg | 2 +- .../stable/markdown/elk/sketch.exp.svg | 2 +- .../md_code_block_fenced/dagre/sketch.exp.svg | 2 +- .../md_code_block_fenced/elk/sketch.exp.svg | 2 +- .../dagre/sketch.exp.svg | 2 +- .../md_code_block_indented/elk/sketch.exp.svg | 2 +- .../md_code_inline/dagre/sketch.exp.svg | 2 +- .../stable/md_code_inline/elk/sketch.exp.svg | 2 +- .../multiple_trees/dagre/sketch.exp.svg | 2 +- .../stable/multiple_trees/elk/sketch.exp.svg | 2 +- .../stable/n22_e32/dagre/sketch.exp.svg | 2 +- .../stable/n22_e32/elk/sketch.exp.svg | 2 +- .../number_connections/dagre/sketch.exp.svg | 2 +- .../number_connections/elk/sketch.exp.svg | 2 +- .../one_container_loop/dagre/sketch.exp.svg | 2 +- .../one_container_loop/elk/sketch.exp.svg | 2 +- .../dagre/sketch.exp.svg | 2 +- .../elk/sketch.exp.svg | 2 +- .../testdata/stable/p/dagre/sketch.exp.svg | 2 +- e2etests/testdata/stable/p/elk/sketch.exp.svg | 2 +- .../testdata/stable/pre/dagre/sketch.exp.svg | 2 +- .../testdata/stable/pre/elk/sketch.exp.svg | 2 +- .../self-referencing/dagre/sketch.exp.svg | 6 +- .../self-referencing/elk/sketch.exp.svg | 6 +- .../dagre/board.exp.json | 4 +- .../dagre/sketch.exp.svg | 6 +- .../elk/board.exp.json | 4 +- .../elk/sketch.exp.svg | 6 +- .../dagre/sketch.exp.svg | 2 +- .../elk/sketch.exp.svg | 2 +- .../dagre/board.exp.json | 16 +++--- .../dagre/sketch.exp.svg | 12 +++- .../elk/board.exp.json | 16 +++--- .../elk/sketch.exp.svg | 12 +++- .../dagre/board.exp.json | 24 ++++---- .../dagre/sketch.exp.svg | 16 +++++- .../sequence_diagram_span/elk/board.exp.json | 24 ++++---- .../sequence_diagram_span/elk/sketch.exp.svg | 16 +++++- .../sequence_diagrams/dagre/board.exp.json | 48 ++++++++-------- .../sequence_diagrams/dagre/sketch.exp.svg | 28 +++++++++- .../sequence_diagrams/elk/board.exp.json | 48 ++++++++-------- .../sequence_diagrams/elk/sketch.exp.svg | 28 +++++++++- .../stable/sql_tables/dagre/sketch.exp.svg | 2 +- .../stable/sql_tables/elk/sketch.exp.svg | 2 +- .../stable/square_3d/dagre/sketch.exp.svg | 2 +- .../stable/square_3d/elk/sketch.exp.svg | 2 +- .../dagre/sketch.exp.svg | 2 +- .../elk/sketch.exp.svg | 2 +- .../stable/stylish/dagre/sketch.exp.svg | 2 +- .../stable/stylish/elk/sketch.exp.svg | 2 +- .../stable/us_map/dagre/sketch.exp.svg | 2 +- .../testdata/stable/us_map/elk/sketch.exp.svg | 2 +- .../container_child_edge/dagre/sketch.exp.svg | 8 +-- .../container_child_edge/elk/sketch.exp.svg | 8 +-- .../font_sizes_large/dagre/sketch.exp.svg | 12 +--- .../todo/font_sizes_large/elk/sketch.exp.svg | 12 +--- .../todo/tall_edge_label/dagre/sketch.exp.svg | 6 +- .../todo/tall_edge_label/elk/sketch.exp.svg | 6 +- 126 files changed, 395 insertions(+), 364 deletions(-) diff --git a/d2layouts/d2sequence/sequence_diagram.go b/d2layouts/d2sequence/sequence_diagram.go index b08a89a6f..c0f3727ee 100644 --- a/d2layouts/d2sequence/sequence_diagram.go +++ b/d2layouts/d2sequence/sequence_diagram.go @@ -267,12 +267,7 @@ func (sd *sequenceDiagram) routeMessages() { } if message.Attributes.Label.Value != "" { - if isLeftToRight { - message.LabelPosition = go2.Pointer(string(label.OutsideTopCenter)) - } else { - // the label will be placed above the message because the orientation is based on the edge normal vector - message.LabelPosition = go2.Pointer(string(label.OutsideBottomCenter)) - } + message.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter)) } } } diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 692db2cca..e46a0fb79 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -337,26 +337,15 @@ func pathData(connection d2target.Connection, idToShape map[string]d2target.Shap return strings.Join(path, " ") } -func labelMask(id string, connection d2target.Connection, labelTL, tl, br *geo.Point) string { - width := br.X - tl.X - height := br.Y - tl.Y - return strings.Join([]string{ - fmt.Sprintf(``, - id, tl.X, tl.Y, width, height, - ), - fmt.Sprintf(``, - tl.X, tl.Y, width, height, - ), - fmt.Sprintf(``, - labelTL.X, labelTL.Y, - connection.LabelWidth, - connection.LabelHeight, - ), - ``, - }, "\n") +func makeLabelMask(connection d2target.Connection, labelTL, tl, br *geo.Point) string { + return fmt.Sprintf(``, + labelTL.X, labelTL.Y, + connection.LabelWidth, + connection.LabelHeight, + ) } -func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape) { +func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape) (labelMask string) { fmt.Fprintf(writer, ``, escapeText(connection.ID)) var markerStart string if connection.SrcArrow != d2target.NoArrowhead { @@ -387,7 +376,6 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma } var labelTL *geo.Point - var mask string if connection.Label != "" { labelTL = connection.GetLabelTopLeft() labelTL.X = math.Round(labelTL.X) @@ -420,18 +408,15 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma br.X = math.Max(br.X, labelTL.X+float64(connection.LabelWidth)) br.Y = math.Max(br.Y, labelTL.Y+float64(connection.LabelHeight)) - maskID := fmt.Sprintf("mask-%s", hash(connection.ID)) - fmt.Fprint(writer, labelMask(maskID, connection, labelTL, tl, br)) - mask = fmt.Sprintf(`mask="url(#%s)" `, maskID) + labelMask = makeLabelMask(connection, labelTL, tl, br) } } - fmt.Fprintf(writer, ``, + fmt.Fprintf(writer, ``, pathData(connection, idToShape), connectionStyle(connection), markerStart, markerEnd, - mask, ) if connection.Label != "" { @@ -476,6 +461,7 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma fmt.Fprint(writer, renderArrowheadLabel(connection, connection.DstLabel, position, size, size)) } fmt.Fprintf(writer, ``) + return } func renderArrowheadLabel(connection d2target.Connection, text string, position, width, height float64) string { @@ -955,7 +941,7 @@ func embedFonts(buf *bytes.Buffer) { // TODO minify output at end func Render(diagram *d2target.Diagram) ([]byte, error) { buf := &bytes.Buffer{} - _, _ = setViewbox(buf, diagram) + w, h := setViewbox(buf, diagram) buf.WriteString(fmt.Sprintf(`abc abc abc abc ab ab ab ab acbd acbd acbd acbd ab - +ab hello + -helloab - +ab hello + -hellorectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud cba * cba * cba * cba * ab - +ab To err is human, to moo bovine1* + -To err is human, to moo bovine1*ab - +ab To err is human, to moo bovine1* + -To err is human, to moo bovine1*abcdefghijklmno abcdefghijklmno abcdefghijklmno abcdefghijklmno aaadddeeebbbccc - +aaadddeeebbbccc111 222 + -111 - -222aaadddeeebbbccc - +aaadddeeebbbccc111 222 + -111 - -222aabbllmm

nn

oocciikkdd

gg

hhjj

ee

-
ff - +ff1122 334455667788 + -11 - -22 - -33 - -44 - -55 - -66 - -77 - -88aabbllmm

nn

oocciikkdd

gg

hhjj

ee

-
ff - +ff1122 334455667788 + -11 - -22 - -33 - -44 - -55 - -66 - -77 - -88abcd abcd abcd abcd abc abc abc abc acfbdhg acfbdhg acfbdhg acfbdhg agdfbhec agdfbhec agdfbhec agdfbhec abcdefghijklmnopq abcdefghijklmnopq abcdefghijklmnopq abcdefghijklmnopq finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot bacde21345abcde bacde21345abcde bacde21345abcde bacde21345abcde alphabeta - +alphabeta gamma + -gammaalphabeta - +alphabeta gamma + -gammasize XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 - +size XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 custom 10custom 15custom 48 + -custom 10 - -custom 15 - -custom 48size XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 - +size XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 custom 10custom 15custom 48 + -custom 10 - -custom 15 - -custom 48ab ab ab ab aabbccddllffwwyynniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac - +aabbccddllffwwyynniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 123456 + -1 - -2 - -3 - -4 - -5 - -6aabbccddllffwwyynniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac - +aabbccddllffwwyynniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 123456 + -1 - -2 - -3 - -4 - -5 - -6abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv mixed togethersugarsolution - +mixed togethersugarsolution we get + -we getmixed togethersugarsolution - +mixed togethersugarsolution we get + -we get

Markdown: Syntax

-
ab

Markdown: Syntax

-
ab

code

-
ab

code

-
ab abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstu abcdefghijklmnopqrstu abcdefghijklmnopqrstu abcdefghijklmnopqrstu Foo Baz12hello Foo Baz12hello Foo Baz12hello Foo Baz12hello acdefgbh acdefgbh acdefgbh acdefgbh topabcbottomstartend topabcbottomstartend topabcbottomstartend topabcbottomstartend xyz - +xyz hello + -helloxyz - +xyz hello + -helloscoreritemResponseitemessayRubricconceptitemOutcome scoreritemResponseitemessayRubricconceptitemOutcome scoreritemResponseitemessayRubricconceptitemOutcome scoreritemResponseitemessayRubricconceptitemOutcome AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication ResponseAlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response + + + + + + + + + +AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication ResponseAlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response + + + + + + + + + +scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + +scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + +a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + + + + + + + + + + + + + +a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + + + + + + + + + + + + + +acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDcontainerfirstsecond - +containerfirstsecond 1->2c->2 + -1->2 - -c->2containerfirstsecond - +containerfirstsecond 1->2c->2 + -1->2 - -c->2eightsixteenthirty twosixty fourninety nine - +eightsixteenthirty twosixty fourninety nine twelvetwenty fourforty eighteighty one + -twelve - -twenty four - -forty eight - -eighty oneeightsixteenthirty twosixty fourninety nine - +eightsixteenthirty twosixty fourninety nine twelvetwenty fourforty eighteighty one + -twelve - -twenty four - -forty eight - -eighty oneab - +ab Thereoncewasaverytalledgelabel + -Thereoncewasaverytalledgelabelab - +ab Thereoncewasaverytalledgelabel + -Thereoncewasaverytalledgelabel