psych 3.0.0.beta2-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +20 -0
  4. data/CHANGELOG.rdoc +576 -0
  5. data/Gemfile +3 -0
  6. data/Mavenfile +7 -0
  7. data/README.md +73 -0
  8. data/Rakefile +46 -0
  9. data/bin/console +7 -0
  10. data/bin/setup +6 -0
  11. data/ext/psych/.gitignore +11 -0
  12. data/ext/psych/depend +3 -0
  13. data/ext/psych/extconf.rb +39 -0
  14. data/ext/psych/psych.c +34 -0
  15. data/ext/psych/psych.h +17 -0
  16. data/ext/psych/psych_emitter.c +554 -0
  17. data/ext/psych/psych_emitter.h +8 -0
  18. data/ext/psych/psych_parser.c +568 -0
  19. data/ext/psych/psych_parser.h +6 -0
  20. data/ext/psych/psych_to_ruby.c +39 -0
  21. data/ext/psych/psych_to_ruby.h +8 -0
  22. data/ext/psych/psych_yaml_tree.c +24 -0
  23. data/ext/psych/psych_yaml_tree.h +8 -0
  24. data/ext/psych/yaml/LICENSE +19 -0
  25. data/ext/psych/yaml/api.c +1392 -0
  26. data/ext/psych/yaml/config.h +10 -0
  27. data/ext/psych/yaml/dumper.c +394 -0
  28. data/ext/psych/yaml/emitter.c +2329 -0
  29. data/ext/psych/yaml/loader.c +444 -0
  30. data/ext/psych/yaml/parser.c +1374 -0
  31. data/ext/psych/yaml/reader.c +469 -0
  32. data/ext/psych/yaml/scanner.c +3576 -0
  33. data/ext/psych/yaml/writer.c +141 -0
  34. data/ext/psych/yaml/yaml.h +1971 -0
  35. data/ext/psych/yaml/yaml_private.h +662 -0
  36. data/lib/psych.rb +511 -0
  37. data/lib/psych/class_loader.rb +102 -0
  38. data/lib/psych/coder.rb +95 -0
  39. data/lib/psych/core_ext.rb +19 -0
  40. data/lib/psych/exception.rb +14 -0
  41. data/lib/psych/handler.rb +250 -0
  42. data/lib/psych/handlers/document_stream.rb +23 -0
  43. data/lib/psych/handlers/recorder.rb +40 -0
  44. data/lib/psych/json/ruby_events.rb +20 -0
  45. data/lib/psych/json/stream.rb +17 -0
  46. data/lib/psych/json/tree_builder.rb +13 -0
  47. data/lib/psych/json/yaml_events.rb +30 -0
  48. data/lib/psych/nodes.rb +78 -0
  49. data/lib/psych/nodes/alias.rb +19 -0
  50. data/lib/psych/nodes/document.rb +61 -0
  51. data/lib/psych/nodes/mapping.rb +57 -0
  52. data/lib/psych/nodes/node.rb +56 -0
  53. data/lib/psych/nodes/scalar.rb +68 -0
  54. data/lib/psych/nodes/sequence.rb +82 -0
  55. data/lib/psych/nodes/stream.rb +38 -0
  56. data/lib/psych/omap.rb +5 -0
  57. data/lib/psych/parser.rb +52 -0
  58. data/lib/psych/scalar_scanner.rb +149 -0
  59. data/lib/psych/set.rb +5 -0
  60. data/lib/psych/stream.rb +38 -0
  61. data/lib/psych/streaming.rb +28 -0
  62. data/lib/psych/syntax_error.rb +22 -0
  63. data/lib/psych/tree_builder.rb +97 -0
  64. data/lib/psych/versions.rb +9 -0
  65. data/lib/psych/visitors.rb +7 -0
  66. data/lib/psych/visitors/depth_first.rb +27 -0
  67. data/lib/psych/visitors/emitter.rb +52 -0
  68. data/lib/psych/visitors/json_tree.rb +25 -0
  69. data/lib/psych/visitors/to_ruby.rb +401 -0
  70. data/lib/psych/visitors/visitor.rb +20 -0
  71. data/lib/psych/visitors/yaml_tree.rb +551 -0
  72. data/lib/psych/y.rb +10 -0
  73. data/psych.gemspec +64 -0
  74. metadata +175 -0
@@ -0,0 +1,511 @@
1
+ # frozen_string_literal: true
2
+ require 'psych/versions'
3
+ case RUBY_ENGINE
4
+ when 'jruby'
5
+ require 'psych_jars'
6
+ org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
7
+ else
8
+ begin
9
+ require "#{RUBY_VERSION[/\d+\.\d+/]}/psych.so"
10
+ rescue LoadError
11
+ require 'psych.so'
12
+ end
13
+ end
14
+ require 'psych/nodes'
15
+ require 'psych/streaming'
16
+ require 'psych/visitors'
17
+ require 'psych/handler'
18
+ require 'psych/tree_builder'
19
+ require 'psych/parser'
20
+ require 'psych/omap'
21
+ require 'psych/set'
22
+ require 'psych/coder'
23
+ require 'psych/core_ext'
24
+ require 'psych/stream'
25
+ require 'psych/json/tree_builder'
26
+ require 'psych/json/stream'
27
+ require 'psych/handlers/document_stream'
28
+ require 'psych/class_loader'
29
+
30
+ ###
31
+ # = Overview
32
+ #
33
+ # Psych is a YAML parser and emitter.
34
+ # Psych leverages libyaml [Home page: http://pyyaml.org/wiki/LibYAML]
35
+ # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing
36
+ # and emitting capabilities. In addition to wrapping libyaml, Psych also
37
+ # knows how to serialize and de-serialize most Ruby objects to and from
38
+ # the YAML format.
39
+ #
40
+ # = I NEED TO PARSE OR EMIT YAML RIGHT NOW!
41
+ #
42
+ # # Parse some YAML
43
+ # Psych.load("--- foo") # => "foo"
44
+ #
45
+ # # Emit some YAML
46
+ # Psych.dump("foo") # => "--- foo\n...\n"
47
+ # { :a => 'b'}.to_yaml # => "---\n:a: b\n"
48
+ #
49
+ # Got more time on your hands? Keep on reading!
50
+ #
51
+ # == YAML Parsing
52
+ #
53
+ # Psych provides a range of interfaces for parsing a YAML document ranging from
54
+ # low level to high level, depending on your parsing needs. At the lowest
55
+ # level, is an event based parser. Mid level is access to the raw YAML AST,
56
+ # and at the highest level is the ability to unmarshal YAML to Ruby objects.
57
+ #
58
+ # == YAML Emitting
59
+ #
60
+ # Psych provides a range of interfaces ranging from low to high level for
61
+ # producing YAML documents. Very similar to the YAML parsing interfaces, Psych
62
+ # provides at the lowest level, an event based system, mid-level is building
63
+ # a YAML AST, and the highest level is converting a Ruby object straight to
64
+ # a YAML document.
65
+ #
66
+ # == High-level API
67
+ #
68
+ # === Parsing
69
+ #
70
+ # The high level YAML parser provided by Psych simply takes YAML as input and
71
+ # returns a Ruby data structure. For information on using the high level parser
72
+ # see Psych.load
73
+ #
74
+ # ==== Reading from a string
75
+ #
76
+ # Psych.load("--- a") # => 'a'
77
+ # Psych.load("---\n - a\n - b") # => ['a', 'b']
78
+ #
79
+ # ==== Reading from a file
80
+ #
81
+ # Psych.load_file("database.yml")
82
+ #
83
+ # ==== Exception handling
84
+ #
85
+ # begin
86
+ # # The second argument changes only the exception contents
87
+ # Psych.parse("--- `", "file.txt")
88
+ # rescue Psych::SyntaxError => ex
89
+ # ex.file # => 'file.txt'
90
+ # ex.message # => "(file.txt): found character that cannot start any token"
91
+ # end
92
+ #
93
+ # === Emitting
94
+ #
95
+ # The high level emitter has the easiest interface. Psych simply takes a Ruby
96
+ # data structure and converts it to a YAML document. See Psych.dump for more
97
+ # information on dumping a Ruby data structure.
98
+ #
99
+ # ==== Writing to a string
100
+ #
101
+ # # Dump an array, get back a YAML string
102
+ # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n"
103
+ #
104
+ # # Dump an array to an IO object
105
+ # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
106
+ #
107
+ # # Dump an array with indentation set
108
+ # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n"
109
+ #
110
+ # # Dump an array to an IO with indentation set
111
+ # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)
112
+ #
113
+ # ==== Writing to a file
114
+ #
115
+ # Currently there is no direct API for dumping Ruby structure to file:
116
+ #
117
+ # File.open('database.yml', 'w') do |file|
118
+ # file.write(Psych.dump(['a', 'b']))
119
+ # end
120
+ #
121
+ # == Mid-level API
122
+ #
123
+ # === Parsing
124
+ #
125
+ # Psych provides access to an AST produced from parsing a YAML document. This
126
+ # tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can
127
+ # be examined and manipulated freely. Please see Psych::parse_stream,
128
+ # Psych::Nodes, and Psych::Nodes::Node for more information on dealing with
129
+ # YAML syntax trees.
130
+ #
131
+ # ==== Reading from a string
132
+ #
133
+ # # Returns Psych::Nodes::Stream
134
+ # Psych.parse_stream("---\n - a\n - b")
135
+ #
136
+ # # Returns Psych::Nodes::Document
137
+ # Psych.parse("---\n - a\n - b")
138
+ #
139
+ # ==== Reading from a file
140
+ #
141
+ # # Returns Psych::Nodes::Stream
142
+ # Psych.parse_stream(File.read('database.yml'))
143
+ #
144
+ # # Returns Psych::Nodes::Document
145
+ # Psych.parse_file('database.yml')
146
+ #
147
+ # ==== Exception handling
148
+ #
149
+ # begin
150
+ # # The second argument changes only the exception contents
151
+ # Psych.parse("--- `", "file.txt")
152
+ # rescue Psych::SyntaxError => ex
153
+ # ex.file # => 'file.txt'
154
+ # ex.message # => "(file.txt): found character that cannot start any token"
155
+ # end
156
+ #
157
+ # === Emitting
158
+ #
159
+ # At the mid level is building an AST. This AST is exactly the same as the AST
160
+ # used when parsing a YAML document. Users can build an AST by hand and the
161
+ # AST knows how to emit itself as a YAML document. See Psych::Nodes,
162
+ # Psych::Nodes::Node, and Psych::TreeBuilder for more information on building
163
+ # a YAML AST.
164
+ #
165
+ # ==== Writing to a string
166
+ #
167
+ # # We need Psych::Nodes::Stream (not Psych::Nodes::Document)
168
+ # stream = Psych.parse_stream("---\n - a\n - b")
169
+ #
170
+ # stream.to_yaml # => "---\n- a\n- b\n"
171
+ #
172
+ # ==== Writing to a file
173
+ #
174
+ # # We need Psych::Nodes::Stream (not Psych::Nodes::Document)
175
+ # stream = Psych.parse_stream(File.read('database.yml'))
176
+ #
177
+ # File.open('database.yml', 'w') do |file|
178
+ # file.write(stream.to_yaml)
179
+ # end
180
+ #
181
+ # == Low-level API
182
+ #
183
+ # === Parsing
184
+ #
185
+ # The lowest level parser should be used when the YAML input is already known,
186
+ # and the developer does not want to pay the price of building an AST or
187
+ # automatic detection and conversion to Ruby objects. See Psych::Parser for
188
+ # more information on using the event based parser.
189
+ #
190
+ # ==== Reading to Psych::Nodes::Stream structure
191
+ #
192
+ # parser = Psych::Parser.new(TreeBuilder.new) # => #<Psych::Parser>
193
+ # parser = Psych.parser # it's an alias for the above
194
+ #
195
+ # parser.parse("---\n - a\n - b") # => #<Psych::Parser>
196
+ # parser.handler # => #<Psych::TreeBuilder>
197
+ # parser.handler.root # => #<Psych::Nodes::Stream>
198
+ #
199
+ # ==== Receiving an events stream
200
+ #
201
+ # parser = Psych::Parser.new(Psych::Handlers::Recorder.new)
202
+ #
203
+ # parser.parse("---\n - a\n - b")
204
+ # parser.events # => [list of [event, args] lists]
205
+ # # event is one of: Psych::Handler::EVENTS
206
+ # # args are the arguments passed to the event
207
+ #
208
+ # === Emitting
209
+ #
210
+ # The lowest level emitter is an event based system. Events are sent to a
211
+ # Psych::Emitter object. That object knows how to convert the events to a YAML
212
+ # document. This interface should be used when document format is known in
213
+ # advance or speed is a concern. See Psych::Emitter for more information.
214
+ #
215
+ # ==== Writing to a Ruby structure
216
+ #
217
+ # Psych.parser.parse("--- a") # => #<Psych::Parser>
218
+ #
219
+ # parser.handler.first # => #<Psych::Nodes::Stream>
220
+ # parser.handler.first.to_ruby # => ["a"]
221
+ #
222
+ # parser.handler.root.first # => #<Psych::Nodes::Document>
223
+ # parser.handler.root.first.to_ruby # => "a"
224
+ #
225
+ # # You can instantiate an Emitter manually
226
+ # Psych::Visitors::ToRuby.new.accept(parser.handler.root.first)
227
+ # # => "a"
228
+
229
+ module Psych
230
+ # The version of libyaml Psych is using
231
+ LIBYAML_VERSION = Psych.libyaml_version.join '.'
232
+
233
+ FALLBACK = Struct.new :to_ruby # :nodoc:
234
+
235
+ ###
236
+ # Load +yaml+ in to a Ruby data structure. If multiple documents are
237
+ # provided, the object contained in the first document will be returned.
238
+ # +filename+ will be used in the exception message if any exception is raised
239
+ # while parsing.
240
+ #
241
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
242
+ #
243
+ # Example:
244
+ #
245
+ # Psych.load("--- a") # => 'a'
246
+ # Psych.load("---\n - a\n - b") # => ['a', 'b']
247
+ #
248
+ # begin
249
+ # Psych.load("--- `", "file.txt")
250
+ # rescue Psych::SyntaxError => ex
251
+ # ex.file # => 'file.txt'
252
+ # ex.message # => "(file.txt): found character that cannot start any token"
253
+ # end
254
+ def self.load yaml, filename = nil, fallback = false
255
+ result = parse(yaml, filename, fallback)
256
+ result ? result.to_ruby : result
257
+ end
258
+
259
+ ###
260
+ # Safely load the yaml string in +yaml+. By default, only the following
261
+ # classes are allowed to be deserialized:
262
+ #
263
+ # * TrueClass
264
+ # * FalseClass
265
+ # * NilClass
266
+ # * Numeric
267
+ # * String
268
+ # * Array
269
+ # * Hash
270
+ #
271
+ # Recursive data structures are not allowed by default. Arbitrary classes
272
+ # can be allowed by adding those classes to the +whitelist+. They are
273
+ # additive. For example, to allow Date deserialization:
274
+ #
275
+ # Psych.safe_load(yaml, [Date])
276
+ #
277
+ # Now the Date class can be loaded in addition to the classes listed above.
278
+ #
279
+ # Aliases can be explicitly allowed by changing the +aliases+ parameter.
280
+ # For example:
281
+ #
282
+ # x = []
283
+ # x << x
284
+ # yaml = Psych.dump x
285
+ # Psych.safe_load yaml # => raises an exception
286
+ # Psych.safe_load yaml, [], [], true # => loads the aliases
287
+ #
288
+ # A Psych::DisallowedClass exception will be raised if the yaml contains a
289
+ # class that isn't in the whitelist.
290
+ #
291
+ # A Psych::BadAlias exception will be raised if the yaml contains aliases
292
+ # but the +aliases+ parameter is set to false.
293
+ def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil
294
+ result = parse(yaml, filename)
295
+ return unless result
296
+
297
+ class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s),
298
+ whitelist_symbols.map(&:to_s))
299
+ scanner = ScalarScanner.new class_loader
300
+ if aliases
301
+ visitor = Visitors::ToRuby.new scanner, class_loader
302
+ else
303
+ visitor = Visitors::NoAliasRuby.new scanner, class_loader
304
+ end
305
+ visitor.accept result
306
+ end
307
+
308
+ ###
309
+ # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document.
310
+ # +filename+ is used in the exception message if a Psych::SyntaxError is
311
+ # raised.
312
+ #
313
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
314
+ #
315
+ # Example:
316
+ #
317
+ # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00>
318
+ #
319
+ # begin
320
+ # Psych.parse("--- `", "file.txt")
321
+ # rescue Psych::SyntaxError => ex
322
+ # ex.file # => 'file.txt'
323
+ # ex.message # => "(file.txt): found character that cannot start any token"
324
+ # end
325
+ #
326
+ # See Psych::Nodes for more information about YAML AST.
327
+ def self.parse yaml, filename = nil, fallback = false
328
+ parse_stream(yaml, filename) do |node|
329
+ return node
330
+ end
331
+ fallback
332
+ end
333
+
334
+ ###
335
+ # Parse a file at +filename+. Returns the Psych::Nodes::Document.
336
+ #
337
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
338
+ def self.parse_file filename
339
+ File.open filename, 'r:bom|utf-8' do |f|
340
+ parse f, filename
341
+ end
342
+ end
343
+
344
+ ###
345
+ # Returns a default parser
346
+ def self.parser
347
+ Psych::Parser.new(TreeBuilder.new)
348
+ end
349
+
350
+ ###
351
+ # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream.
352
+ # This method can handle multiple YAML documents contained in +yaml+.
353
+ # +filename+ is used in the exception message if a Psych::SyntaxError is
354
+ # raised.
355
+ #
356
+ # If a block is given, a Psych::Nodes::Document node will be yielded to the
357
+ # block as it's being parsed.
358
+ #
359
+ # Raises a Psych::SyntaxError when a YAML syntax error is detected.
360
+ #
361
+ # Example:
362
+ #
363
+ # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00>
364
+ #
365
+ # Psych.parse_stream("--- a\n--- b") do |node|
366
+ # node # => #<Psych::Nodes::Document:0x00>
367
+ # end
368
+ #
369
+ # begin
370
+ # Psych.parse_stream("--- `", "file.txt")
371
+ # rescue Psych::SyntaxError => ex
372
+ # ex.file # => 'file.txt'
373
+ # ex.message # => "(file.txt): found character that cannot start any token"
374
+ # end
375
+ #
376
+ # See Psych::Nodes for more information about YAML AST.
377
+ def self.parse_stream yaml, filename = nil, &block
378
+ if block_given?
379
+ parser = Psych::Parser.new(Handlers::DocumentStream.new(&block))
380
+ parser.parse yaml, filename
381
+ else
382
+ parser = self.parser
383
+ parser.parse yaml, filename
384
+ parser.handler.root
385
+ end
386
+ end
387
+
388
+ ###
389
+ # call-seq:
390
+ # Psych.dump(o) -> string of yaml
391
+ # Psych.dump(o, options) -> string of yaml
392
+ # Psych.dump(o, io) -> io object passed in
393
+ # Psych.dump(o, io, options) -> io object passed in
394
+ #
395
+ # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
396
+ # to control the output format. If an IO object is passed in, the YAML will
397
+ # be dumped to that IO object.
398
+ #
399
+ # Example:
400
+ #
401
+ # # Dump an array, get back a YAML string
402
+ # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n"
403
+ #
404
+ # # Dump an array to an IO object
405
+ # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
406
+ #
407
+ # # Dump an array with indentation set
408
+ # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n"
409
+ #
410
+ # # Dump an array to an IO with indentation set
411
+ # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)
412
+ def self.dump o, io = nil, options = {}
413
+ if Hash === io
414
+ options = io
415
+ io = nil
416
+ end
417
+
418
+ visitor = Psych::Visitors::YAMLTree.create options
419
+ visitor << o
420
+ visitor.tree.yaml io, options
421
+ end
422
+
423
+ ###
424
+ # Dump a list of objects as separate documents to a document stream.
425
+ #
426
+ # Example:
427
+ #
428
+ # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
429
+ def self.dump_stream *objects
430
+ visitor = Psych::Visitors::YAMLTree.create({})
431
+ objects.each do |o|
432
+ visitor << o
433
+ end
434
+ visitor.tree.yaml
435
+ end
436
+
437
+ ###
438
+ # Dump Ruby +object+ to a JSON string.
439
+ def self.to_json object
440
+ visitor = Psych::Visitors::JSONTree.create
441
+ visitor << object
442
+ visitor.tree.yaml
443
+ end
444
+
445
+ ###
446
+ # Load multiple documents given in +yaml+. Returns the parsed documents
447
+ # as a list. If a block is given, each document will be converted to Ruby
448
+ # and passed to the block during parsing
449
+ #
450
+ # Example:
451
+ #
452
+ # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
453
+ #
454
+ # list = []
455
+ # Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby|
456
+ # list << ruby
457
+ # end
458
+ # list # => ['foo', 'bar']
459
+ #
460
+ def self.load_stream yaml, filename = nil
461
+ if block_given?
462
+ parse_stream(yaml, filename) do |node|
463
+ yield node.to_ruby
464
+ end
465
+ else
466
+ parse_stream(yaml, filename).children.map { |child| child.to_ruby }
467
+ end
468
+ end
469
+
470
+ ###
471
+ # Load the document contained in +filename+. Returns the yaml contained in
472
+ # +filename+ as a Ruby object, or if the file is empty, it returns
473
+ # the specified default return value, which defaults to an empty Hash
474
+ def self.load_file filename, fallback = false
475
+ File.open(filename, 'r:bom|utf-8') { |f|
476
+ self.load f, filename, FALLBACK.new(fallback)
477
+ }
478
+ end
479
+
480
+ # :stopdoc:
481
+ @domain_types = {}
482
+ def self.add_domain_type domain, type_tag, &block
483
+ key = ['tag', domain, type_tag].join ':'
484
+ @domain_types[key] = [key, block]
485
+ @domain_types["tag:#{type_tag}"] = [key, block]
486
+ end
487
+
488
+ def self.add_builtin_type type_tag, &block
489
+ domain = 'yaml.org,2002'
490
+ key = ['tag', domain, type_tag].join ':'
491
+ @domain_types[key] = [key, block]
492
+ end
493
+
494
+ def self.remove_type type_tag
495
+ @domain_types.delete type_tag
496
+ end
497
+
498
+ @load_tags = {}
499
+ @dump_tags = {}
500
+ def self.add_tag tag, klass
501
+ @load_tags[tag] = klass.name
502
+ @dump_tags[klass] = tag
503
+ end
504
+
505
+ class << self
506
+ attr_accessor :load_tags
507
+ attr_accessor :dump_tags
508
+ attr_accessor :domain_types
509
+ end
510
+ # :startdoc:
511
+ end