Manual Harmonic Projections - With interactive inputs
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HeWhoMustNotBeNamed

//   __    __            __       __  __                  __       __                        __      __    __              __      _______             __    __                                          __ 
//  /  |  /  |          /  |  _  /  |/  |                /  \     /  |                      /  |    /  \  /  |            /  |    /       \           /  \  /  |                                        /  |
//  $$ |  $$ |  ______  $$ | / \ $$ |$$ |____    ______  $$  \   /$$ | __    __   _______  _$$ |_   $$  \ $$ |  ______   _$$ |_   $$$$$$$  |  ______  $$  \ $$ |  ______   _____  ____    ______    ____$$ |
//  $$ |__$$ | /      \ $$ |/$  \$$ |$$      \  /      \ $$$  \ /$$$ |/  |  /  | /       |/ $$   |  $$$  \$$ | /      \ / $$   |  $$ |__$$ | /      \ $$$  \$$ | /      \ /     \/    \  /      \  /    $$ |
//  $$    $$ |/$$$$$$  |$$ /$$$  $$ |$$$$$$$  |/$$$$$$  |$$$$  /$$$$ |$$ |  $$ |/$$$$$$$/ $$$$$$/   $$$$  $$ |/$$$$$$  |$$$$$$/   $$    $$< /$$$$$$  |$$$$  $$ | $$$$$$  |$$$$$$ $$$$  |/$$$$$$  |/$$$$$$$ |
//  $$$$$$$$ |$$    $$ |$$ $$/$$ $$ |$$ |  $$ |$$ |  $$ |$$ $$ $$/$$ |$$ |  $$ |$$      \   $$ | __ $$ $$ $$ |$$ |  $$ |  $$ | __ $$$$$$$  |$$    $$ |$$ $$ $$ | /    $$ |$$ | $$ | $$ |$$    $$ |$$ |  $$ |
//  $$ |  $$ |$$$$$$$$/ $$$$/  $$$$ |$$ |  $$ |$$ \__$$ |$$ |$$$/ $$ |$$ \__$$ | $$$$$$  |  $$ |/  |$$ |$$$$ |$$ \__$$ |  $$ |/  |$$ |__$$ |$$$$$$$$/ $$ |$$$$ |/$$$$$$$ |$$ | $$ | $$ |$$$$$$$$/ $$ \__$$ |
//  $$ |  $$ |$$       |$$$/    $$$ |$$ |  $$ |$$    $$/ $$ | $/  $$ |$$    $$/ /     $$/   $$  $$/ $$ | $$$ |$$    $$/   $$  $$/ $$    $$/ $$       |$$ | $$$ |$$    $$ |$$ | $$ | $$ |$$       |$$    $$ |
//  $$/   $$/  $$$$$$$/ $$/      $$/ $$/   $$/  $$$$$$/  $$/      $$/  $$$$$$/  $$$$$$$/     $$$$/  $$/   $$/  $$$$$$/     $$$$/  $$$$$$$/   $$$$$$$/ $$/   $$/  $$$$$$$/ $$/  $$/  $$/  $$$$$$$/  $$$$$$$/ 
//                                                                                                                                                                                                          
//                                                                                                                                                                                                          
//
//@version=5
indicator("Manual Harmonic Projections - With interactive inputs", overlay=true)
import HeWhoMustNotBeNamed/eHarmonicpatternsExtended/6 as hp
import HeWhoMustNotBeNamed/arrayutils/17 as pa

x = input.price(0,'X',group='XABC', inline=  '1', confirm=true)
xBarTime = input.time(0,'',group='XABC', inline=  '1', confirm=true)
a = input.price(0,'A',group='XABC', inline=  '2', confirm=true)
aBarTime = input.time(0,'',group='XABC', inline=  '2', confirm=true)
b = input.price(0,'B',group='XABC', inline=  '3', confirm=true)
bBarTime = input.time(0,'',group='XABC', inline=  '3', confirm=true)
c = input.price(0,'C',group='XABC', inline=  '4', confirm=true)
cBarTime = input.time(0,'',group='XABC', inline=  '4', confirm=true)


showXABCD = input.bool(true, title='Show XABCD', group='Display', inline='showHide')
showRatios = input.bool(true, title='Show Ratios', group='Display', inline='showHide')

fillMajorTriangles = input.bool(true, title="Fill XAB/BCD", group="Display", inline="fill1")
majorFillTransparency = input.int(70, step=5, title="", group="Display", inline="fill1")
fillMinorTriangles = input.bool(true, title="Fill ABC/XBD", group="Display", inline="fill2")
minorFillTransparency = input.int(90, step=5, title="", group="Display", inline="fill2")

errorPercent = input.int(8, group="Miscellaneous")
patternColor = input.color(color.purple, group="Miscellaneous")

classic = input.bool(true, title="Classic Patterns", group="Category", inline="ca")
anti = input.bool(true, title="Anti/Alternate Patterns", group="Category", inline="ca")
nonStandard = input.bool(true, title="Nonstandard",  group="Category", inline="ca")

gartley = input.bool(true, title='Gartley       ', group='Classic Patterns', inline="c1")
bat = input.bool(true, title='Bat      ', group='Classic Patterns', inline="c1")
butterfly = input.bool(true, title='Butterfly   ', group='Classic Patterns', inline="c1")
crab = input.bool(true, title='Crab', group='Classic Patterns', inline="c1")
deepCrab = input.bool(true, title='Deep Crab   ', group='Classic Patterns', inline="c2")
cypher = input.bool(true, title='Cypher   ', group='Classic Patterns', inline="c2")
shark = input.bool(true, title='Shark      ', group='Classic Patterns', inline="c2")
nenStar = input.bool(true, title='Nenstar', group='Classic Patterns', inline="c2")

antiNenStar = input.bool(true, title='Anti Nenstar   ', group='Anti Patterns', inline="a1")
antiShark = input.bool(true, title='Anti Shark', group='Anti Patterns', inline="a1")
antiCypher = input.bool(true, title='Anti Cypher ', group='Anti Patterns', inline="a1")
antiCrab = input.bool(true, title='Anti Crab', group='Anti Patterns', inline="a1")
antiButterfly = input.bool(true, title='Anti Butterfly', group='Anti Patterns', inline="a2")
antiBat = input.bool(true, title='Anti Bat  ', group='Anti Patterns', inline="a2")
antiGartley = input.bool(true, title='Anti Gartley', group='Anti Patterns', inline="a2")
navarro200 = input.bool(true, title='Navarro 200', group='Anti Patterns', inline="a2")

fiveZero = input.bool(true, title='Five Zero', group='Non Standard', inline="a1")
threeDrives = input.bool(true, title='Three Drives', group='Non Standard', inline="a1")
whiteSwann = input.bool(true, title='White Swann', group='Non Standard', inline="a1")
blackSwann = input.bool(true, title='Black Swann', group='Non Standard', inline="a1")
seaPony = input.bool(true, title='Sea Pony', group='Non Standard', inline="a2")
leonardo = input.bool(true, title='Leonardo', group='Non Standard', inline="a2")
oneTwoOne = input.bool(true, title='121', group='Non Standard', inline="a2")
snorm = input.bool(true, title='Snorm', group='Non Standard', inline="a2")
totalPattern = input.bool(true, title='Total', group='Non Standard', inline="a2")

NUMBER_OF_PATTERNS = 25
enableGartley = classic and gartley
enableBat = classic and bat
enableButterfly = classic and butterfly
enableCrab = classic and crab
enableDeepCrab = classic and deepCrab
enableCypher = classic and cypher
enableShark = classic and shark
enableNenStar = classic and nenStar

enableAntiNenStar = anti and antiNenStar
enableAntiShark = anti and antiShark
enableAntiCypher = anti and antiCypher
enableAntiCrab = anti and antiCrab
enableAntiButterfly = anti and antiButterfly
enableAntiBat = anti and antiBat
enableAntiGartley = anti and antiGartley
enableNavarro200 = anti and navarro200
enableFiveZero = nonStandard and fiveZero
enableThreeDrives = nonStandard and threeDrives
enableWhiteSwann = nonStandard and whiteSwann
enableBlackSwann = nonStandard and blackSwann
enableSeaPony = nonStandard and seaPony
enableLeonardo = nonStandard and leonardo
enableOneTwoOne = nonStandard and oneTwoOne
enableSnorm = nonStandard and snorm
enableTotal = nonStandard and totalPattern

flags = array.new_bool()
array.push(flags, enableGartley)
array.push(flags, enableCrab)
array.push(flags, enableDeepCrab)
array.push(flags, enableBat)
array.push(flags, enableButterfly)
array.push(flags, enableShark)
array.push(flags, enableCypher)
array.push(flags, enableNenStar)

array.push(flags, enableAntiNenStar)
array.push(flags, enableAntiShark)
array.push(flags, enableAntiCypher)
array.push(flags, enableAntiCrab)
array.push(flags, enableAntiButterfly)
array.push(flags, enableAntiBat)
array.push(flags, enableAntiGartley)
array.push(flags, enableNavarro200)

array.push(flags, enableFiveZero)
array.push(flags, enableThreeDrives)
array.push(flags, enableWhiteSwann)
array.push(flags, enableBlackSwann)
array.push(flags, enableSeaPony)
array.push(flags, enableLeonardo)
array.push(flags, enableOneTwoOne)
array.push(flags, enableSnorm)
array.push(flags, enableTotal)


f_draw_pattern_line(y1, y2, x1, x2, lineColor, width, style) =>
    targetLine = line.new(y1=y1, y2=y2, x1=x1, x2=x2, color=lineColor, width=width, style=style)
    targetLine

f_draw_pattern_label(y, x, txt, textcolor, style, yloc, size) =>
    targetLabel = label.new(y=y, x=x, text=txt, textcolor=textcolor, style=style, yloc=yloc, size=size)
    targetLabel

f_draw_entry_box(y1, y2, x1, linecolor, labelColor, labelText) =>
    x2 = x1 + 20
    y = (y1 + y2) / 2
    xloc = xloc.bar_index
    transp = 70
    entryBox = box.new(x1, y1, x2, y2, linecolor, 1, line.style_dotted, xloc=xloc, bgcolor=color.new(labelColor, transp), text=labelText,
                         text_color=color.silver, text_size=size.small)

draw_xabc(x, a, b, c, xBar, aBar, bBar, cBar, dir, labelColor, patterns, consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels) =>
    hasPatterns = array.includes(patterns, true), 
    isCypher = array.get(patterns, 6)
    xa = f_draw_pattern_line(y1=x, y2=a, x1=xBar, x2=aBar, lineColor=labelColor, width=1, style=line.style_solid)
    ab = f_draw_pattern_line(y1=a, y2=b, x1=aBar, x2=bBar, lineColor=labelColor, width=1, style=line.style_solid)
    bc = f_draw_pattern_line(y1=b, y2=c, x1=bBar, x2=cBar, lineColor=labelColor, width=1, style=line.style_solid)
    xb = f_draw_pattern_line(y1=x, y2=b, x1=xBar, x2=bBar, lineColor=labelColor, width=1, style=line.style_dashed)
    ac = f_draw_pattern_line(y1=a, y2=c, x1=aBar, x2=cBar, lineColor=labelColor, width=1, style=line.style_dotted)

    if(fillMajorTriangles and hasPatterns)
        xaab = linefill.new(xa, ab, color.new(labelColor, majorFillTransparency))
        xbab = linefill.new(xb, ab, color.new(labelColor, majorFillTransparency))

    if(fillMinorTriangles and hasPatterns)
        abbc = linefill.new(ab, bc, color.new(labelColor, minorFillTransparency))
        acbc = linefill.new(ac, bc, color.new(labelColor, minorFillTransparency))

    if showXABCD
        gap = ta.tr
        xLabel = f_draw_pattern_label(y=(dir>0?x-gap:x+gap), x=xBar, txt='X', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
        aLabel = f_draw_pattern_label(y=(dir>0?a+gap:a-gap), x=aBar, txt='A', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
        bLabel = f_draw_pattern_label(y=(dir>0?b-gap:b+gap), x=bBar, txt='B', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
        cLabel = f_draw_pattern_label(y=(dir>0?c+gap:c-gap), x=cBar, txt='C', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)

    if showRatios
        xabRatio = math.round(math.abs(a - b) / math.abs(x - a), 3)
        xabRatioBar = (xBar + bBar) / 2

        abcRatio = math.round(math.abs(b - c) / math.abs(a - b), 3)
        abcRatioBar = (aBar + cBar) / 2

        axcRatio = math.round(math.abs(x - c) / math.abs(x - a), 3)

        xabRatioPrice = line.get_price(xb, xabRatioBar)
        abcRatioPrice = line.get_price(ac, abcRatioBar)

        abcRatioLabelText = str.tostring(abcRatio) + '(ABC)' + (isCypher ? '\n' + str.tostring(axcRatio) + '(AXC)' : '')
        xabLabel = f_draw_pattern_label(y=xabRatioPrice, x=xabRatioBar, txt=str.tostring(xabRatio) + '(XAB)', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
        abcLabel = f_draw_pattern_label(y=abcRatioPrice, x=abcRatioBar, txt=abcRatioLabelText, textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)

    if(hasPatterns)
        sortOrder = pa.get_sort_order(consolidatedStartRange, -dir)
        for i=0 to array.size(consolidatedStartRange)-1
            index = array.get(sortOrder, i)
            y1 = array.get(consolidatedStartRange, index)
            y2 = array.get(consolidatedEndRange, index)
            if(i==0)
                d = (y1+y2)/2
                dBar = bar_index
                cd = f_draw_pattern_line(y1=c, y2=d, x1=cBar, x2=dBar, lineColor=labelColor, width=1, style=line.style_solid)
                bd = f_draw_pattern_line(y1=b, y2=d, x1=bBar, x2=dBar, lineColor=labelColor, width=1, style=line.style_dashed)
                xd = f_draw_pattern_line(y1=x, y2=d, x1=xBar, x2=dBar, lineColor=labelColor, width=1, style=line.style_dotted)
                if showRatios
                    bcdRatio = math.round(math.abs(c - d) / math.abs(b - c), 3)
                    bcdRatioBar = (bBar + dBar) / 2
            
                    xadRatio = math.round(math.abs(a - d) / math.abs(x - a), 3)
                    xadRatioBar = (xBar + dBar) / 2
                    
                    xcdRatio = math.round(math.abs(d - c) / math.abs(x - c), 3)
                    
                    bcdRatioPrice = line.get_price(bd, bcdRatioBar)
                    xadRatioPrice = line.get_price(xd, xadRatioBar)

                    xadRatioLabelText = str.tostring(xadRatio) + '(XAD)' + (isCypher ? '\n' + str.tostring(xcdRatio) + '(XCD)' : '')
        
                    bcdLabel = f_draw_pattern_label(y=bcdRatioPrice, x=bcdRatioBar, txt=str.tostring(bcdRatio) + '(BCD)', textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
                    xadLabel = f_draw_pattern_label(y=xadRatioPrice, x=xadRatioBar, txt=xadRatioLabelText, textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=size.small)
                if fillMajorTriangles
                    bccd = linefill.new(bc, cd, color.new(labelColor, majorFillTransparency))
                    bdcd = linefill.new(bd, cd, color.new(labelColor, majorFillTransparency))
                if fillMinorTriangles
                    xbbd = linefill.new(xb, bd, color.new(labelColor, minorFillTransparency))
                    xdbd = linefill.new(xd, bd, color.new(labelColor, minorFillTransparency))
            labelText = array.get(consolidatedPatternLabels, index)
            f_draw_entry_box(y1, y2, bar_index, labelColor, labelColor, labelText)
            
            
get_prz_range(float x, float a, float b, float c, bool[] patternArray, simple int start_adj=0, simple int end_adj=0)=>
    startRange = array.new_float(16, na)
    endRange = array.new_float(16, na)
    if(array.includes(patternArray, true))
        //Gartley
        pa.getrange(x, a, 0.786, 0.786, b, c, 1.272, 1.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 0)
        //Crab
        pa.getrange(x, a, 1.618, 1.618, b, c, 2.240, 3.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 1)
        //DeepCrab
        pa.getrange(x, a, 1.618, 1.618, b, c, 2.000, 3.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 2)
        //Bat
        pa.getrange(x, a, 0.886, 0.886, b, c, 1.618, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 3)
        //Butterfly
        pa.getrange(x, a, 1.272, 1.618, b, c, 1.618, 2.618, 0, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 4)
        //Shark
        pa.getrange(x, a, 0.886, 0.886, b, c, 1.618, 2.236, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 5)
        //Cypher
        pa.getrange(x, c, 0.786, 0.786, x, c, 0.786, 0.786, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 6)
        //NenStar
        pa.getrange(x, a, 1.272, 1.272, b, c, 1.272, 2.000, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 7)
        //Anti NenStar
        pa.getrange(x, a, 0.786, 0.786, b, c, 1.618, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 8)
        //Anti Shark
        pa.getrange(x, a, 1.130, 1.130, b, c, 1.618, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 9)
        //Anti Cypher
        pa.getrange(x, a, 1.272, 1.272, b, c, 1.618, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 10)
        //Anti Crab
        pa.getrange(x, a, 0.618, 0.618, b, c, 1.618, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 11)
        //Anti Butterfly
        pa.getrange(x, a, 0.618, 0.786, b, c, 1.272, 1.272, 0, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 12)
        //Anti Bat
        pa.getrange(x, a, 1.128, 1.128, b, c, 2.000, 2.618, errorPercent, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 13)
        //Anti Gartley
        pa.getrange(x, a, 1.272, 1.618, b, c, 1.168, 1.618, 0, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 14)
        //Navarro200
        pa.getrange(x, a, 0.886, 1.127, b, c, 0.886, 3.618, 0, errorPercent, start_adj, end_adj, patternArray, startRange, endRange, 15)
    [startRange, endRange]


normalize_prz_range(patterns, patternLabels, startRange, endRange)=>
    consolidatedStartRange = array.new_float()
    consolidatedEndRange = array.new_float()
    consolidatedPatternLabels = array.new_string()
    merged = false
    for idx=0 to array.size(patterns)-1
        flag = array.get(patterns, idx)
        if(flag)
            lbl = array.get(patternLabels, idx)
            start = array.get(startRange, idx)
            end = array.get(endRange, idx)
            dir = start > end ? 1 : -1
            createNewRange = true
            for i =0 to array.size(consolidatedStartRange)==0? na : array.size(consolidatedStartRange)-1
                oStart = array.get(consolidatedStartRange, i)
                oEnd = array.get(consolidatedEndRange, i)
                overlappingStart = (start*dir < oStart*dir and start*dir > oEnd*dir) or (oStart*dir < start*dir and oStart*dir > end*dir)
                overlappingEnd = (end*dir < oStart*dir and end*dir > oEnd*dir) or (oEnd*dir < start*dir and oEnd*dir > end*dir)
                if(overlappingStart or overlappingEnd)
                    newStart = dir > 0? math.max(start, oStart) : math.min(start, oStart)
                    newEnd = dir > 0? math.min(end, oEnd) : math.max(end, oEnd)
                    array.set(consolidatedStartRange, i, newStart)
                    array.set(consolidatedEndRange, i, newEnd)
                    newLabel=array.get(consolidatedPatternLabels, i)+'\n'+lbl
                    array.set(consolidatedPatternLabels, i, newLabel)
                    createNewRange := false
                    merged := true
                    break
            if(createNewRange)
                array.push(consolidatedStartRange, start)
                array.push(consolidatedEndRange, end)
                array.push(consolidatedPatternLabels, lbl)
    
    [consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels, merged]


merge_ranges(StartRange, EndRange, PatternLabels)=>
    consolidatedStartRange = array.new_float()
    consolidatedEndRange = array.new_float()
    consolidatedPatternLabels = array.new_string()
    merged = false
    for idx = 0 to (array.size(StartRange)==0? na :  array.size(EndRange)-1)
        start = array.get(StartRange, idx)
        end = array.get(EndRange, idx)
        lbl = array.get(PatternLabels, idx)
        dir = start > end ? 1 : -1
        createNewRange = true

        for i =0 to array.size(consolidatedStartRange)==0? na : array.size(consolidatedStartRange)-1
            oStart = array.get(consolidatedStartRange, i)
            oEnd = array.get(consolidatedEndRange, i)
            overlappingStart = (start*dir < oStart*dir and start*dir > oEnd*dir) or (oStart*dir < start*dir and oStart*dir > end*dir)
            overlappingEnd = (end*dir < oStart*dir and end*dir > oEnd*dir) or (oEnd*dir < start*dir and oEnd*dir > end*dir)
            if(overlappingStart or overlappingEnd)
                newStart = dir > 0? math.max(start, oStart) : math.min(start, oStart)
                newEnd = dir > 0? math.min(end, oEnd) : math.max(end, oEnd)
                array.set(consolidatedStartRange, i, newStart)
                array.set(consolidatedEndRange, i, newEnd)
                newLabel=array.get(consolidatedPatternLabels, i)+'\n'+lbl
                array.set(consolidatedPatternLabels, i, newLabel)
                createNewRange := false
                merged := true
                break
        if(createNewRange)
            array.push(consolidatedStartRange, start)
            array.push(consolidatedEndRange, end)
            array.push(consolidatedPatternLabels, lbl)
            
    [consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels, merged]


var printed = false
patternLabels = hp.getSupportedPatterns()
if(barstate.islast and not printed)
    patterns = hp.isHarmonicProjection(x, a, b, c, flags, errorPercent = errorPercent)

    int xBar = na
    int aBar = na
    int bBar = na
    int cBar = na

    offset = 0
    while(na(xBar) or na(aBar) or na(bBar) or na(cBar))
        bartime = time[offset]
        if(na(xBar) and bartime == xBarTime)
            xBar := bar_index - offset
        if(na(aBar) and bartime == aBarTime)
            aBar := bar_index - offset
        if(na(bBar) and bartime == bBarTime)
            bBar := bar_index - offset
        if(na(cBar) and bartime == cBarTime)
            cBar := bar_index - offset
        offset+=1

    [startRange, endRange] = hp.get_projection_range(x, a, b, c, patterns)
    [consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels, merged] = normalize_prz_range(patterns, patternLabels, startRange, endRange)
    while(merged)
        [newStartRange, newEndRange, newLabels, newMerged] = merge_ranges(consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels)
        consolidatedStartRange := newStartRange
        consolidatedEndRange := newEndRange
        consolidatedPatternLabels := newLabels
        merged := newMerged
    dir = c > b? 1 : -1
    draw_xabc(x, a, b, c, xBar, aBar, bBar, cBar, dir, patternColor, patterns, consolidatedStartRange, consolidatedEndRange, consolidatedPatternLabels)
    printed := true
