jdk/src/share/classes/com/sun/tools/example/debug/gui/SourceModel.java
author xdono
Wed, 02 Jul 2008 12:55:45 -0700
changeset 715 f16baef3a20e
parent 51 6fe31bc95bbc
child 5506 202f599c92aa
permissions -rw-r--r--
6719955: Update copyright year Summary: Update copyright year for files that have been modified in 2008 Reviewed-by: ohair, tbell
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
715
f16baef3a20e 6719955: Update copyright year
xdono
parents: 51
diff changeset
     2
 * Copyright 1998-2008 Sun Microsystems, Inc.  All Rights Reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package com.sun.tools.example.debug.gui;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.io.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.util.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import com.sun.jdi.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import com.sun.jdi.request.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import com.sun.tools.example.debug.bdi.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
import javax.swing.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
 * Represents and manages one source file.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 * Caches source lines.  Holds other source file info.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
public class SourceModel extends AbstractListModel {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
    private File path;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
    boolean isActuallySource = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
    private List<ReferenceType> classes = new ArrayList<ReferenceType>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
    private Environment env;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
    // Cached line-by-line access.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    //### Unify this with source model used in source view?
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
    //### What is our cache-management policy for these?
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
    //### Even with weak refs, we won't discard any part of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    //### source if the SourceModel object is reachable.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
     * List of Line.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    private List<Line> sourceLines = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    public static class Line {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
        public String text;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
        public boolean hasBreakpoint = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
        public ReferenceType refType = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
        Line(String text) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
            this.text = text;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
        public boolean isExecutable() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
            return refType != null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
        public boolean hasBreakpoint() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
            return hasBreakpoint;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
    };
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
    // 132 characters long, all printable characters.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    public static final Line prototypeCellValue = new Line(
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
                                        "abcdefghijklmnopqrstuvwxyz" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
                                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
                                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
                                        "1234567890~!@#$%^&*()_+{}|" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
                                        ":<>?`-=[];',.XXXXXXXXXXXX/\\\"");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
    SourceModel(Environment env, File path) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
        this.env = env;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
        this.path = path;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
    public SourceModel(String message) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        this.path = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
        setMessage(message);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
    private void setMessage(String message) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
        isActuallySource = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
        sourceLines = new ArrayList<Line>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
        sourceLines.add(new Line(message));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
    // **** Implement ListModel  *****
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
    public Object getElementAt(int index) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
        if (sourceLines == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
            initialize();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
        return sourceLines.get(index);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
    public int getSize() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
        if (sourceLines == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
            initialize();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
        return sourceLines.size();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
    // ***** Other functionality *****
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
    public File fileName() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
        return path;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
    public BufferedReader sourceReader() throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
        return new BufferedReader(new FileReader(path));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
    public Line line(int lineNo) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        if (sourceLines == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
            initialize();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
        int index = lineNo - 1; // list is 0-indexed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
        if (index >= sourceLines.size() || index < 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
            return sourceLines.get(index);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
    public String sourceLine(int lineNo) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
        Line line = line(lineNo);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        if (line == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
            return line.text;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
    void addClass(ReferenceType refType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
        // Logically is Set
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
        if (classes.indexOf(refType) == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
            classes.add(refType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
            if (sourceLines != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
                markClassLines(refType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
     * @return List of currently known {@link com.sun.jdi.ReferenceType}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
     * in this source file.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
    public List<ReferenceType> referenceTypes() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
        return Collections.unmodifiableList(classes);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
    private void initialize() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
            rawInit();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
        } catch (IOException exc) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
            setMessage("[Error reading source code]");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
    public void showBreakpoint(int ln, boolean hasBreakpoint) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
        line(ln).hasBreakpoint = hasBreakpoint;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
        fireContentsChanged(this, ln, ln);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
    public void showExecutable(int ln, ReferenceType refType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
        line(ln).refType = refType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
        fireContentsChanged(this, ln, ln);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
     * Mark executable lines and breakpoints, but only
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
     * when sourceLines is set.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
    private void markClassLines(ReferenceType refType) {
51
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   190
        for (Method meth : refType.methods()) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
            try {
51
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   192
                for (Location loc : meth.allLineLocations()) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
                    showExecutable(loc.lineNumber(), refType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
            } catch (AbsentInformationException exc) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
                // do nothing
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
        }
51
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   199
        for (BreakpointRequest bp :
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   200
                 env.getExecutionManager().eventRequestManager().breakpointRequests()) {
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
            if (bp.location() != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
                Location loc = bp.location();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
                if (loc.declaringType().equals(refType)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
                    showBreakpoint(loc.lineNumber(),true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
    private void rawInit() throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
        sourceLines = new ArrayList<Line>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
        BufferedReader reader = sourceReader();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
            String line = reader.readLine();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
            while (line != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
                sourceLines.add(new Line(expandTabs(line)));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                line = reader.readLine();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
        } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
            reader.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
        }
51
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   222
        for (ReferenceType refType : classes) {
6fe31bc95bbc 6600143: Remove another 450 unnecessary casts
martin
parents: 2
diff changeset
   223
            markClassLines(refType);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
    private String expandTabs(String s) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
        int col = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
        int len = s.length();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        StringBuffer sb = new StringBuffer(132);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
        for (int i = 0; i < len; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
            char c = s.charAt(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
            sb.append(c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
            if (c == '\t') {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
                int pad = (8 - (col % 8));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
                for (int j = 0; j < pad; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
                    sb.append(' ');
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
                col += pad;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
                col++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
        return sb.toString();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
}