1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/* Useful for dumping out the input stream after doing some
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  augmentation or other manipulations.
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  You can insert stuff, replace, and delete chunks.  Note that the
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  operations are done lazily--only if you convert the buffer to a
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  String.  This is very efficient because you are not moving data around
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  all the time.  As the buffer of tokens is converted to strings, the
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  toString() method(s) check to see if there is an operation at the
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  current index.  If so, the operation is done and then normal String
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  rendering continues on the buffer.  This is like having multiple Turing
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  machine instruction streams (programs) operating on a single input tape. :)
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Since the operations are done lazily at toString-time, operations do not
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  screw up the token index values.  That is, an insert operation at token
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  index i does not change the index values for tokens i+1..n-1.
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Because operations never actually alter the buffer, you may always get
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  the original token stream back without undoing anything.  Since
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  the instructions are queued up, you can easily simulate transactions and
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  roll back any changes if there is an error just by removing instructions.
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  For example,
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *   CharStream input = new ANTLRFileStream("input");
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *   TLexer lex = new TLexer(input);
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *   TokenRewriteStream tokens = new TokenRewriteStream(lex);
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *   T parser = new T(tokens);
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *   parser.startRule();
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      Then in the rules, you can execute
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      Token t,u;
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      ...
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      input.insertAfter(t, "text to put after t");}
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *         input.insertAfter(u, "text after u");}
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *         System.out.println(tokens.toString());
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  You can also have multiple "instruction streams" and get multiple
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  rewrites from a single pass over the input.  Just name the instruction
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  streams and use that name again when printing the buffer.  This could be
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  useful for generating a C file and also its header file--all from the
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  same buffer:
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *      tokens.insertAfter("pass1", t, "text to put after t");}
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *         tokens.insertAfter("pass2", u, "text after u");}
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *         System.out.println(tokens.toString("pass1"));
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *         System.out.println(tokens.toString("pass2"));
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  If you don't use named rewrite streams, a "default" stream is used as
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  the first example shows.
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.runtime.TokenRewriteStream = function() {
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    var sup = org.antlr.runtime.TokenRewriteStream.superclass;
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** You may have multiple, named streams of rewrite operations.
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  I'm calling these things "programs."
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Maps String (name) -> rewrite (List)
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     */
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    this.programs = null;
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Map String (program name) -> Integer index */
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    this.lastRewriteTokenIndexes = null;
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    if (arguments.length===0) {
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.init();
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    } else {
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        sup.constructor.apply(this, arguments);
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.init();
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver(function(){
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvervar trs = org.antlr.runtime.TokenRewriteStream;
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.lang.augmentObject(trs, {
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    DEFAULT_PROGRAM_NAME: "default",
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    PROGRAM_INIT_SIZE: 100,
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    MIN_TOKEN_INDEX: 0
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver});
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver//
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver// Define the rewrite operation hierarchy
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver//
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertrs.RewriteOperation = function(index, text) {
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    this.index = index;
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    this.text = text;
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/** Execute the rewrite operation by possibly adding to the buffer.
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  Return the index of the next token to operate on.
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertrs.RewriteOperation.prototype = {
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    execute: function(buf) {
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return this.index;
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    toString: function() {
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /*String opName = getClass().getName();
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        int $index = opName.indexOf('$');
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        opName = opName.substring($index+1, opName.length());
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return opName+"@"+index+'"'+text+'"';*/
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return this.text;
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertrs.InsertBeforeOp = function(index, text) {
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    trs.InsertBeforeOp.superclass.constructor.call(this, index, text);
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.lang.extend(trs.InsertBeforeOp, trs.RewriteOperation, {
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    execute: function(buf) {
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        buf.push(this.text);
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return this.index;
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver});
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/** I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *  instructions.
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertrs.ReplaceOp = function(from, to, text) {
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    trs.ReplaceOp.superclass.constructor.call(this, from, text);
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    this.lastIndex = to;
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.lang.extend(trs.ReplaceOp, trs.RewriteOperation, {
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    execute: function(buf) {
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (org.antlr.lang.isValue(this.text)) {
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            buf.push(this.text);
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return this.lastIndex+1;
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver});
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvertrs.DeleteOp = function(from, to) {
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    trs.DeleteOp.superclass.constructor.call(this, from, to);
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver};
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.lang.extend(trs.DeleteOp, trs.ReplaceOp);
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverorg.antlr.lang.extend(trs, org.antlr.runtime.CommonTokenStream, {
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    init: function() {
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.programs = {};
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.programs[trs.DEFAULT_PROGRAM_NAME] = [];
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.lastRewriteTokenIndexes = {};
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Rollback the instruction stream for a program so that
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the indicated instruction (via instructionIndex) is no
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  longer in the stream.  UNTESTED!
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     */
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    rollback: function() {
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var programName,
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            instructionIndex;
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===1) {
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            instructionIndex = arguments[0];
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===2) {
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            instructionIndex = arguments[1];
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var is = this.programs[programName];
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (is) {
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs[programName] = is.slice(trs.MIN_TOKEN_INDEX, this.instructionIndex);
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Reset the program so that no instructions exist */
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    deleteProgram: function(programName) {
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        programName = programName || trs.DEFAULT_PROGRAM_NAME;
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.rollback(programName, trs.MIN_TOKEN_INDEX);
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Add an instruction to the rewrite instruction list ordered by
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the instruction number (use a binary search for efficiency).
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  The list is ordered so that toString() can be done efficiently.
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  When there are multiple instructions at the same index, the instructions
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  must be ordered to ensure proper behavior.  For example, a delete at
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  index i must kill any replace operation at i.  Insert-before operations
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  must come before any replace / delete instructions.  If there are
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  multiple insert instructions for a single index, they are done in
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  reverse insertion order so that "insert foo" then "insert bar" yields
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  "foobar" in front rather than "barfoo".  This is convenient because
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  I can insert new InsertOp instructions at the index returned by
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the binary search.  A ReplaceOp kills any previous replace op.  Since
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  delete is the same as replace with null text, i can check for
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  ReplaceOp and cover DeleteOp at same time. :)
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     */
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    addToSortedRewriteList: function() {
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var programName,
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op;
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===1) {
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op = arguments[0];
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===2) {
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op = arguments[1];
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var rewrites = this.getProgram(programName);
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var len, pos, searchOp, replaced, prevOp, i;
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        for (pos=0, len=rewrites.length; pos<len; pos++) {
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            searchOp = rewrites[pos];
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (searchOp.index===op.index) {
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // now pos is the index in rewrites of first op with op.index
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // an instruction operating already on that index was found;
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // make this one happen after all the others
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op instanceof trs.ReplaceOp) {
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    replaced = false;
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // look for an existing replace
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    for (i=pos; i<rewrites.length; i++) {
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        prevOp = rewrites[pos];
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        if (prevOp.index!==op.index) {
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                            break;
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        }
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        if (prevOp instanceof trs.ReplaceOp) {
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                            rewrites[pos] = op; // replace old with new
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                            replaced=true;
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                            break;
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        }
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // keep going; must be an insert
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( !replaced ) {
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // add replace op to the end of all the inserts
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites.splice(i, 0, op);
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                } else {
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // inserts are added in front of existing inserts
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    rewrites.splice(pos, 0, op);
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                break;
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            } else if (searchOp.index > op.index) {
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                rewrites.splice(pos, 0, op);
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                break;
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (pos===len) {
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            rewrites.push(op);
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    insertAfter: function() {
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var index, programName, text;
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===2) {
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = arguments[0];
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[1];
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===3) {
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = arguments[1];
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[2];
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (index instanceof org.antlr.runtime.Token) {
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // index is a Token, grab it's stream index
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = index.index; // that's ugly
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        // insert after is the same as insert before the next index
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.insertBefore(programName, index+1, text);
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    insertBefore: function() {
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var index, programName, text;
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===2) {
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = arguments[0];
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[1];
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===3) {
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = arguments[1];
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[2];
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (index instanceof org.antlr.runtime.Token) {
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // index is a Token, grab it's stream index
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            index = index.index; // that's ugly
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.addToSortedRewriteList(
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                programName,
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                new trs.InsertBeforeOp(index,text)
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                );
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    replace: function() {
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var programName, first, last, text;
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===2) {
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            first = arguments[0];
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            last = arguments[0];
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[1];
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===3) {
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            first = arguments[0];
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            last = arguments[1];
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[2];
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } if (arguments.length===4) {
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            first = arguments[1];
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            last = arguments[2];
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            text = arguments[3];
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (first instanceof org.antlr.runtime.Token) {
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            first = first.index;
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (last instanceof org.antlr.runtime.Token) {
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            last = last.index; // that's ugly
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if ( first > last || last<0 || first<0 ) {
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return;
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.addToSortedRewriteList(
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                programName,
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                new trs.ReplaceOp(first, last, text));
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    // !!! API Break: delete is a JS keyword, so using remove instead.
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    remove: function() {
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        // convert arguments to a real array
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var args=[], i=arguments.length-1;
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        while (i>=0) {
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            args[i] = arguments[i];
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            i--;
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        args.push("");
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.replace.apply(this, args);
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    getLastRewriteTokenIndex: function(programName) {
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        programName = programName || trs.DEFAULT_PROGRAM_NAME;
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return this.lastRewriteTokenIndexes[programName] || -1;
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    setLastRewriteTokenIndex: function(programName, i) {
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.lastRewriteTokenIndexes[programName] = i;
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    getProgram: function(name) {
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var is = this.programs[name];
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if ( !is ) {
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            is = this.initializeProgram(name);
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return is;
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    initializeProgram: function(name) {
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var is = [];
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        this.programs[name] = is;
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return is;
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    toOriginalString: function(start, end) {
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (!org.antlr.lang.isNumber(start)) {
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            start = trs.MIN_TOKEN_INDEX;
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (!org.antlr.lang.isNumber(end)) {
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end = this.size()-1;
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var buf = [], i;
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        for (i=start; i>=trs.MIN_TOKEN_INDEX && i<=end && i<this.tokens.length; i++) {
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            buf.push(this.get(i).getText());
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return buf.join("");
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    toString: function() {
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var programName, start, end;
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (arguments.length===0) {
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            start = trs.MIN_TOKEN_INDEX;
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end = this.size() - 1;
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===1) {
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = arguments[0];
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            start = trs.MIN_TOKEN_INDEX;
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end = this.size() - 1;
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        } else if (arguments.length===2) {
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programName = trs.DEFAULT_PROGRAM_NAME;
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            start = arguments[0];
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end = arguments[1];
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var rewrites = this.programs[programName];
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if ( !rewrites || rewrites.length===0 ) {
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return this.toOriginalString(start,end);
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /// Index of first rewrite we have not done
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var rewriteOpIndex = 0,
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            tokenCursor=start,
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            buf = [],
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op;
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        while ( tokenCursor>=trs.MIN_TOKEN_INDEX &&
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                tokenCursor<=end &&
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                tokenCursor<this.tokens.length )
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // execute instructions associated with this token index
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( rewriteOpIndex<rewrites.length ) {
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                op = rewrites[rewriteOpIndex];
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // skip all ops at lower index
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                while (op.index<tokenCursor && rewriteOpIndex<rewrites.length) {
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    rewriteOpIndex++;
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( rewriteOpIndex<rewrites.length ) {
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        op = rewrites[rewriteOpIndex];
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // while we have ops for this token index, exec them
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                while (tokenCursor===op.index && rewriteOpIndex<rewrites.length) {
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    //System.out.println("execute "+op+" at instruction "+rewriteOpIndex);
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    tokenCursor = op.execute(buf);
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    //System.out.println("after execute tokenCursor = "+tokenCursor);
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    rewriteOpIndex++;
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( rewriteOpIndex<rewrites.length ) {
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        op = rewrites[rewriteOpIndex];
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // dump the token at this index
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( tokenCursor<=end ) {
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                buf.push(this.get(tokenCursor).getText());
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                tokenCursor++;
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        // now see if there are operations (append) beyond last token index
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var opi;
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        for (opi=rewriteOpIndex; opi<rewrites.length; opi++) {
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op = rewrites[opi];
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( op.index>=this.size() ) {
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                op.execute(buf); // must be insertions if after last token
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return buf.join("");
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    },
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    toDebugString: function(start, end) {
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (!org.antlr.lang.isNumber(start)) {
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            start = trs.MIN_TOKEN_INDEX;
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if (!org.antlr.lang.isNumber(end)) {
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            end = this.size()-1;
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        var buf = [],
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            i;
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        for (i=start; i>=trs.MIN_TOKEN_INDEX && i<=end && i<this.tokens.length; i++) {
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            buf.push(this.get(i));
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return buf.join("");
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver});
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver})();
462