xmlutils 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +77 -0
  6. data/bin/xmltogdl +88 -0
  7. data/docs/README.txt +20 -0
  8. data/lib/xmlutils/contextlistener.rb +432 -0
  9. data/lib/xmlutils/contextparser.rb +111 -0
  10. data/lib/xmlutils/dumplistener.rb +57 -0
  11. data/lib/xmlutils/gdlcontext.rb +305 -0
  12. data/lib/xmlutils/gdlcontextobjs.rb +286 -0
  13. data/lib/xmlutils/gdldoc.rb +547 -0
  14. data/lib/xmlutils/gdldocbuilder.rb +181 -0
  15. data/lib/xmlutils/gdllistener.rb +265 -0
  16. data/lib/xmlutils/gdltemplate.rb +488 -0
  17. data/lib/xmlutils/lineparser.rb +193 -0
  18. data/lib/xmlutils/listener.rb +459 -0
  19. data/lib/xmlutils/rulelistener.rb +414 -0
  20. data/lib/xmlutils/ruleparser.rb +112 -0
  21. data/lib/xmlutils/varlistener.rb +86 -0
  22. data/lib/xmlutils/version.rb +5 -0
  23. data/lib/xmlutils/xmlrulevisitor.rb +704 -0
  24. data/lib/xmlutils/xmltogdlcontroller.rb +93 -0
  25. data/lib/xmlutils/xmltogdltask.rb +23 -0
  26. data/lib/xmlutils/xmlvisitor.rb +690 -0
  27. data/lib/xmlutils.rb +40 -0
  28. data/rakefile.rb +34 -0
  29. data/unittests/2830.xml +1 -0
  30. data/unittests/chunks.rb +31 -0
  31. data/unittests/curDirTest.rb +2 -0
  32. data/unittests/data/2830-GENERATED.gdl +309 -0
  33. data/unittests/data/2830-GENERATED.xml +1 -0
  34. data/unittests/data/AUGuideline.xml +12 -0
  35. data/unittests/data/AUGuideline.xml.gdl +19190 -0
  36. data/unittests/data/BAKUP.DCTEST1.xml +1 -0
  37. data/unittests/data/DCTEST.xml +1 -0
  38. data/unittests/data/DCTEST1.xml +1 -0
  39. data/unittests/data/DCTEST1.xml.gdl +14890 -0
  40. data/unittests/data/DCTEST1.xml.rename.csv +180 -0
  41. data/unittests/data/DCTEST1wLookups.xml +174 -0
  42. data/unittests/data/DCTEST1wLookups.xml.gdl +127 -0
  43. data/unittests/data/GENERATED.gdl.xml +1 -0
  44. data/unittests/data/Message.xml +1 -0
  45. data/unittests/data/Message.xml.gdl +142 -0
  46. data/unittests/data/Pricing2ndGuideline.xml +1 -0
  47. data/unittests/data/Pricing2ndGuideline.xml.gdl +52670 -0
  48. data/unittests/data/Z-TEMP-Jeff.xml +1 -0
  49. data/unittests/data/Z-TEMP-Jeff.xml.gdl +288 -0
  50. data/unittests/tc_convert_xml_to_gdl.rb +23 -0
  51. data/unittests/ts_allTests.rb +2 -0
  52. data/xmlutils.gemspec +25 -0
  53. metadata +139 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7d719bedccfde3e165b008fe9b2c6b4f0ef6e8c5
4
+ data.tar.gz: e2ab6f96b483cfd0506d1a7d870d344dff60e139
5
+ SHA512:
6
+ metadata.gz: 892232ad6620675da30f3155109ddcb2f48a48077d9601759c9ff01a3e41bdcb4430376338aa054ad842030fb074b646cee4e0a05c4b541746a0953e885ffe33
7
+ data.tar.gz: 4ffcefc03b8fb81e0d53166dff35bce911fba1fd6ae6c1d0e6efda387905ee0376da17069afe6d0f8d97c9c5d123ecf6f6b3ff33affb87e97cc4650888b33ae1
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ # .gitignore
2
+
3
+ buildgem
4
+ buildgem.cmd
5
+ pkg/
6
+ tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in test.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Jeff McAffee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # XmlUtils
2
+
3
+ ## Summary
4
+
5
+ The XmlUtils library provides XML related helper objects.
6
+
7
+ An application (`xmltogdl`) is also provided to convert AMS XML guidelines
8
+ to the GDL language. See [GDLC](https://github.com/jmcaffee/gdlc) for more
9
+ information about GDL.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your gemfile:
14
+
15
+ gem 'xmlutils'
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ or install it yourself as:
22
+
23
+ $ gem install xmlutils
24
+
25
+ ## Usage
26
+
27
+ ### Command Line Application
28
+
29
+ Usage info can be retrieved from the application by calling it with the `-h` or `--help`
30
+ options:
31
+
32
+ $ xmltogdl --help
33
+
34
+ ### Rake Task Usage
35
+
36
+ The rake task can be included in a rakefile by requiring `xmlutils/xmltogdltask`:
37
+
38
+ require `xmlutils/xmltogdltask`
39
+
40
+ and called as:
41
+
42
+ XmlToGdlTask.new.execute(src_path, dest_path, verbose_true_or_false);
43
+
44
+ ## Testing
45
+
46
+ XmlUtils will use RSpec for testing, but it currently only has simple
47
+ hand-rolled tests in the `unittests` directory.
48
+
49
+ To run all existing specs (none at this time):
50
+
51
+ $ rake spec
52
+
53
+ or directly:
54
+
55
+ $ bundle exec rspec
56
+
57
+ ## TODO
58
+
59
+ Update the naming convention of methods to the ruby standard.
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork it ( https://github.com/jmcaffee/xmlutils/fork )
64
+ 1. Clone it (`git clone git@github.com:[my-github-username]/xmlutils.git`)
65
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
66
+ 3. Create tests for your feature branch
67
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 5. Push to the branch (`git push origin my-new-feature`)
69
+ 6. Create a new Pull Request
70
+
71
+ ## LICENSE
72
+
73
+ XmlUtils is licensed under the MIT license.
74
+
75
+ See [LICENSE](https://github.com/jmcaffee/xmlutils/blob/master/LICENSE) for
76
+ details.
77
+
data/bin/xmltogdl ADDED
@@ -0,0 +1,88 @@
1
+ #! C:/tools/Ruby/bin/ruby.exe
2
+ ##############################################################################
3
+ # File:: xmltogdl
4
+ # Purpose:: Utility to convert XML guideline files to gdl source
5
+ #
6
+ # Author:: Jeff McAffee 03/07/2010
7
+ # Copyright:: Copyright (c) 2010, kTech Systems LLC. All rights reserved.
8
+ # Website:: http://ktechsystems.com
9
+ ##############################################################################
10
+
11
+ require 'xmlUtils'
12
+ require 'user-choices'
13
+
14
+
15
+ class XmlToGdlApp < UserChoices::Command
16
+ include UserChoices
17
+
18
+
19
+ def initialize()
20
+ super
21
+ @controller = XmlToGdlController.new
22
+ end
23
+
24
+
25
+ def add_sources(builder)
26
+ builder.add_source(CommandLineSource, :usage,
27
+ "Usage: #{$0} [options] SRC_XML_FILE OUTPUT_FILE",
28
+ "XmlToGdl can parse a guideline.xml file and generate GDL source code from it.",
29
+ "If SRC_XML_FILE does not end with an xml extension, .xml will be added.")
30
+ end # def add_sources
31
+
32
+
33
+ def add_choices(builder)
34
+ # Arguments
35
+ builder.add_choice(:cmdArg, :length=>2) { |command_line| # Use length to REQUIRE args.
36
+ #builder.add_choice(:cmdArg) { |command_line|
37
+ command_line.uses_arglist
38
+ }
39
+
40
+ # Switches
41
+ builder.add_choice(:verbose, :type=>:boolean, :default=>false) { |command_line|
42
+ command_line.uses_switch("-v", "--verbose",
43
+ "Turn on verbose output.")
44
+ }
45
+
46
+ # Options
47
+ builder.add_choice(:includes, :type=>[:string]) { |command_line|
48
+ command_line.uses_option("-i", "--includes ARG1[,ARG2,ARG3,ARGn]",
49
+ "Include external variable definition files.",
50
+ "Seperate multiple files with a comma (NO SPACES).")
51
+ }
52
+
53
+ end # def add_choices
54
+
55
+
56
+ # Execute the XmlToGdl application.
57
+ # This method is called automatically when 'xmltogdl(.rb)' is executed from the command line.
58
+ def execute
59
+ $LOG.debug "XmlToGdlApp::execute"
60
+
61
+ if(@user_choices[:includes])
62
+ @user_choices[:includes].each do |inc|
63
+ @controller.addInclude(inc)
64
+ end
65
+ end
66
+
67
+ if(@user_choices[:verbose])
68
+ @controller.setVerbose(@user_choices[:verbose])
69
+ end
70
+
71
+ if(@user_choices[:cmdArg].empty?) # If no cmd line arg...
72
+ @controller.noCmdLineArg()
73
+ return
74
+ end
75
+
76
+ result = @controller.setFilenames(@user_choices[:cmdArg])
77
+
78
+ @controller.doSomething()
79
+ end # def execute
80
+
81
+
82
+ end # class XmlToGdlApp
83
+
84
+
85
+ #if $0 == __FILE__
86
+ XmlToGdlApp.new.execute
87
+ #end
88
+
data/docs/README.txt ADDED
@@ -0,0 +1,20 @@
1
+ XmlToGdl README
2
+ ===============
3
+
4
+ XlmToGdl consists of the following files:
5
+
6
+ bin/xmlToGdl.rb - Main()
7
+
8
+ lib/xmlToGdl.rb - project lib include file
9
+
10
+ lib/xmlToGdl/gdlDocBuilder.rb
11
+ lib/xmlToGdl/contextListener.rb
12
+ lib/xmlToGdl/contextParser.rb
13
+
14
+ ContextParser
15
+ parses the raw XML file into the CtxListener (context object).
16
+ parses the context using:
17
+ GdlListener
18
+ RuleListener
19
+
20
+
@@ -0,0 +1,432 @@
1
+ #
2
+ # File: contextListener.rb
3
+ #
4
+ # This class is used to convert XML to GDL
5
+ #
6
+ #
7
+
8
+ require 'rexml/streamlistener'
9
+ require 'xmlutils/gdlcontext'
10
+ require 'xmlutils/gdlcontextobjs'
11
+ require 'xmlutils/listener'
12
+
13
+ include REXML
14
+
15
+
16
+
17
+
18
+ #################################################
19
+ #
20
+ # class ContextListener
21
+ #
22
+ #################################################
23
+ class ContextListener < Listener
24
+
25
+ attr_reader :context
26
+ attr_writer :curRuleset
27
+ attr_writer :curLookup
28
+
29
+ attr_writer :curParam
30
+
31
+ attr_writer :inMsg
32
+
33
+
34
+
35
+
36
+
37
+ def initialize(ctx)
38
+ super()
39
+ @context = ctx
40
+ @curRuleset = nil
41
+ @curLookup = nil
42
+ @curParam = nil
43
+ @curMsg = nil
44
+
45
+ @inMsg = false
46
+
47
+ end
48
+
49
+
50
+
51
+
52
+ def inMsg?
53
+ return @inMsg
54
+ end
55
+
56
+
57
+
58
+
59
+ def processingRuleset?
60
+ return true unless (nil == @curRuleset)
61
+ return false
62
+ end
63
+
64
+
65
+
66
+
67
+ def processingLookup?
68
+ return true unless (nil == @curLookup)
69
+ return false
70
+ end
71
+
72
+
73
+
74
+
75
+ def isXParam?
76
+ return true unless ('X' != @curParam)
77
+ return false
78
+ end
79
+
80
+
81
+
82
+
83
+ def isYParam?
84
+ return true unless ('Y' != @curParam)
85
+ return false
86
+ end
87
+
88
+
89
+
90
+
91
+ #-------------------------------------------------------------------------------------------------------------#
92
+ # cdata - A cdata node has been parsed
93
+ # Called when <![CDATA[ � ]]> is encountered in a document. @p content "�"
94
+ # txt - node text
95
+ #------------------------------------------------------------------------------------------------------------#
96
+ def cdata(txt)
97
+ if (inMsg?)
98
+ raise "Message object has not yet been created." if (nil == @curMsg)
99
+ @curMsg.msg = txt
100
+
101
+ end # if inMsg
102
+ end
103
+
104
+
105
+
106
+
107
+ #-------------------------------------------------------------------------------------------------------------#
108
+ # openDPM - Add a DPM variable to the context object
109
+ #
110
+ # attributes - DPM element attributes
111
+ #
112
+ #------------------------------------------------------------------------------------------------------------#
113
+ def openDPM(attributes)
114
+ dpmAlias = attributes["Name"]
115
+ confName = @context.createValidName(dpmAlias)
116
+ # varType = attributes["Type"]
117
+ # dataType = attributes["DataType"] if attributes.has_key?("DataType")
118
+ # prodType = attributes["ProductType"]
119
+ #
120
+ # dataType = prodType if nil == dataType
121
+ #
122
+ # dpm = Dpm.new(confName, dpmAlias, varType, dataType, prodType)
123
+ dpm = Dpm.new(confName, attributes)
124
+
125
+ @context.dpms[dpmAlias] = dpm
126
+
127
+ if (processingLookup?)
128
+ addLookupParam(dpm)
129
+ end
130
+
131
+ end # openDPM
132
+
133
+
134
+
135
+
136
+ #-------------------------------------------------------------------------------------------------------------#
137
+ # openPPM - Add a PPM variable to the context object
138
+ #
139
+ # attributes - PPM element attributes
140
+ #
141
+ #------------------------------------------------------------------------------------------------------------#
142
+ def openPPM(attributes)
143
+ ppmAlias = attributes["Name"]
144
+ confName = "p" + @context.createValidName(ppmAlias)
145
+ # varType = attributes["Type"]
146
+ # dataType = attributes["DataType"] if attributes.has_key?("DataType")
147
+
148
+ # dataType = "Text" if nil == dataType
149
+
150
+ # ppm = Ppm.new(confName, ppmAlias, varType, dataType)
151
+ ppm = Ppm.new(confName, attributes)
152
+
153
+ @context.ppms[ppmAlias] = ppm
154
+
155
+ if (processingLookup?)
156
+ addLookupParam(ppm)
157
+ end
158
+
159
+ end # openPPM
160
+
161
+
162
+
163
+
164
+ #-------------------------------------------------------------------------------------------------------------#
165
+ # openRule - Add a rule to the context object
166
+ #
167
+ # attributes - rule element attributes
168
+ #
169
+ #------------------------------------------------------------------------------------------------------------#
170
+ def openRule(attributes)
171
+ ruleAlias = attributes["Name"]
172
+ confName = @context.createValidName(ruleAlias)
173
+
174
+ rule = Rule.new(confName, ruleAlias)
175
+
176
+ @context.rules[ruleAlias] = rule
177
+
178
+ @curRuleset.addRule(ruleAlias) if (processingRuleset?)
179
+
180
+ end # openRule
181
+
182
+
183
+
184
+ #-------------------------------------------------------------------------------------------------------------#
185
+ # openRuleset - Open a ruleset object
186
+ #
187
+ # attributes - ruleset element attributes
188
+ #
189
+ #------------------------------------------------------------------------------------------------------------#
190
+ def openRuleset(attributes)
191
+ if (processingRuleset?)
192
+ closeRuleset
193
+ end # if
194
+
195
+ rs = Ruleset.new(attributes)
196
+ rs.name = @context.createValidName(rs.alias)
197
+
198
+ @curRuleset = rs
199
+
200
+ end # openRuleset
201
+
202
+
203
+
204
+ #-------------------------------------------------------------------------------------------------------------#
205
+ # closeRuleset - Close a ruleset object
206
+ #
207
+ #
208
+ #------------------------------------------------------------------------------------------------------------#
209
+ def closeRuleset()
210
+ if (processingRuleset?)
211
+ rsAlias = @curRuleset.alias
212
+ @context.rulesets[rsAlias] = @curRuleset
213
+ end # if
214
+
215
+ @curRuleset = nil
216
+
217
+ end # closeRuleset
218
+
219
+
220
+
221
+ #-------------------------------------------------------------------------------------------------------------#
222
+ # openMessage - A Message element has been started
223
+ #
224
+ # name - Tag name of unknown element
225
+ # attributes - Message element attributes
226
+ #
227
+ #------------------------------------------------------------------------------------------------------------#
228
+ def openMessage(attributes)
229
+ if ($DEBUG)
230
+ puts "openMessage"
231
+
232
+ if(!attributes.empty?)
233
+ puts " Attr:"
234
+ attributes.each do |attr|
235
+ puts " #{attr[0]}: #{attr[1]}"
236
+ end
237
+ end
238
+ end # if $DEBUG
239
+
240
+ if (inMsg?)
241
+ closeMessage()
242
+ end # if inMsg
243
+
244
+ @inMsg = true
245
+
246
+ @curMsg = Message.new(attributes)
247
+
248
+ end # openMessage
249
+
250
+
251
+
252
+
253
+ #-------------------------------------------------------------------------------------------------------------#
254
+ # closeMessage - A Message element has been ended
255
+ #
256
+ # name - Tag name of unknown element
257
+ #
258
+ #------------------------------------------------------------------------------------------------------------#
259
+ def closeMessage()
260
+ puts "closeMessage" if $DEBUG
261
+ if (inMsg?)
262
+ msgDone(@curMsg) # Close out the msg
263
+ @curMsg = nil
264
+ @inMsg = false
265
+ end # if inMsg
266
+ end # closeMessage
267
+
268
+
269
+
270
+
271
+ #-------------------------------------------------------------------------------------------------------------#
272
+ # msgDone - A message is finished. Handle it by putting it in the If que or the Else que
273
+ #
274
+ # msg - Complete Message object
275
+ #
276
+ #------------------------------------------------------------------------------------------------------------#
277
+ def msgDone(msg)
278
+ puts "msgDone" if $DEBUG
279
+
280
+ if (msg.msg == nil || msg.msg.length < 1)
281
+ #raise "Blank message text. Unable to store message in context."
282
+ puts "Blank message text. Unable to store message in context."
283
+ return
284
+ end # if msg blank
285
+
286
+ @context.messages[msg.msg] = msg
287
+
288
+ puts msg.inspect if $DEBUG
289
+ end # msgDone
290
+
291
+
292
+
293
+
294
+ #-------------------------------------------------------------------------------------------------------------#
295
+ # openLOOKUP - A LOOKUP element has been started
296
+ #
297
+ # attributes - LOOKUP element attributes
298
+ #
299
+ #------------------------------------------------------------------------------------------------------------#
300
+ def openLOOKUP(attributes)
301
+ if (processingLookup?)
302
+ closeLOOKUP
303
+ end # if
304
+
305
+ lk = Lookup.new(attributes)
306
+
307
+ @curLookup = lk
308
+
309
+ end # openLOOKUP
310
+
311
+
312
+
313
+
314
+ #-------------------------------------------------------------------------------------------------------------#
315
+ # closeLOOKUP - A LOOKUP element has been ended
316
+ #
317
+ #
318
+ #------------------------------------------------------------------------------------------------------------#
319
+ def closeLOOKUP()
320
+ if (processingLookup?)
321
+ lkName = @curLookup.name
322
+ @context.lookups[lkName] = @curLookup
323
+ end # if
324
+
325
+ @curLookup = nil
326
+
327
+ end # closeUnknown
328
+
329
+
330
+
331
+
332
+ #-------------------------------------------------------------------------------------------------------------#
333
+ # addLookupParam - A LOOKUP parameter element has been ended
334
+ #
335
+ #
336
+ #------------------------------------------------------------------------------------------------------------#
337
+ def addLookupParam(var)
338
+ if (processingLookup?)
339
+ if (isXParam?)
340
+ @curLookup.xParam = var
341
+ end
342
+
343
+ if (isYParam?)
344
+ @curLookup.yParam = var
345
+ end
346
+
347
+ end # if
348
+
349
+ end # addLookupParam
350
+
351
+
352
+
353
+
354
+ #-------------------------------------------------------------------------------------------------------------#
355
+ # openXParameter - A XParameter element has been started
356
+ #
357
+ # attributes - XParameter element attributes
358
+ #
359
+ #------------------------------------------------------------------------------------------------------------#
360
+ def openXParameter(attributes)
361
+ @curParam = "X"
362
+ end # openXParameter
363
+
364
+
365
+
366
+
367
+ #-------------------------------------------------------------------------------------------------------------#
368
+ # closeXParameter - A XParameter element has been ended
369
+ #
370
+ #
371
+ #------------------------------------------------------------------------------------------------------------#
372
+ def closeXParameter()
373
+ @curParam = ""
374
+ end # closeUnknown
375
+
376
+
377
+
378
+
379
+ #-------------------------------------------------------------------------------------------------------------#
380
+ # openYParameter - A YParameter element has been started
381
+ #
382
+ # attributes - YParameter element attributes
383
+ #
384
+ #------------------------------------------------------------------------------------------------------------#
385
+ def openYParameter(attributes)
386
+ @curParam = "Y"
387
+ end # openYParameter
388
+
389
+
390
+
391
+
392
+ #-------------------------------------------------------------------------------------------------------------#
393
+ # closeYParameter - A YParameter element has been ended
394
+ #
395
+ #
396
+ #------------------------------------------------------------------------------------------------------------#
397
+ def closeYParameter()
398
+ @curParam = ""
399
+ end # closeYParameter
400
+
401
+
402
+
403
+
404
+ #-------------------------------------------------------------------------------------------------------------#
405
+ # openXmlFunction - A XmlFunction element has been started
406
+ #
407
+ # attributes - XmlFunction element attributes
408
+ #
409
+ #------------------------------------------------------------------------------------------------------------#
410
+ def openXmlFunction(attributes)
411
+ @curParam = "Y"
412
+ end # openXmlFunction
413
+
414
+
415
+
416
+
417
+ #-------------------------------------------------------------------------------------------------------------#
418
+ # closeXmlFunction - A XmlFunction element has been ended
419
+ #
420
+ #
421
+ #------------------------------------------------------------------------------------------------------------#
422
+ def closeXmlFunction()
423
+ @curParam = ""
424
+ end # closeXmlFunction
425
+
426
+
427
+
428
+
429
+ end # class ContextListener
430
+
431
+
432
+