def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
    rname = str(root)
    if visited is None:
        visited = {}
    if showtags:
        if showtags == 2:
            legend = (' E         = exists\n' +
                      '  R        = exists in repository only\n' +
                      '   b       = implicit builder\n' +
                      '   B       = explicit builder\n' +
                      '    S      = side effect\n' +
                      '     P     = precious\n' +
                      '      A    = always build\n' +
                      '       C   = current\n' +
                      '        N  = no clean\n' +
                      '         H = no cache\n' +
                      '\n')
            sys.stdout.write(legend)
        tags = ['[']
        tags.append(' E'[IDX(root.exists())])
        tags.append(' R'[IDX(root.rexists() and not root.exists())])
        tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
                           [0,2][IDX(root.has_builder())]])
        tags.append(' S'[IDX(root.side_effect)])
        tags.append(' P'[IDX(root.precious)])
        tags.append(' A'[IDX(root.always_build)])
        tags.append(' C'[IDX(root.is_up_to_date())])
        tags.append(' N'[IDX(root.noclean)])
        tags.append(' H'[IDX(root.nocache)])
        tags.append(']')
    else:
        tags = []
    def MMM(m):
        return ["  ","| "][m]
    margins = list(map(MMM, margin[:-1]))
    children = child_func(root)
    if prune and rname in visited and children:
        sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + '\n')
        return
    sys.stdout.write(''.join(tags + margins + ['+-', rname]) + '\n')
    visited[rname] = 1
    if children:
        margin.append(1)
        idx = IDX(showtags)
        for C in children[:-1]:
            print_tree(C, child_func, prune, idx, margin, visited)
        margin[-1] = 0
        print_tree(children[-1], child_func, prune, idx, margin, visited)
        margin.pop()