jsduck 5.3.4 → 6.0.0beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/bin/jsduck +3 -3
  4. data/lib/jsduck/app.rb +1 -1
  5. data/lib/jsduck/assets.rb +3 -3
  6. data/lib/jsduck/base_type.rb +2 -2
  7. data/lib/jsduck/batch_processor.rb +3 -1
  8. data/lib/jsduck/categories/file.rb +2 -2
  9. data/lib/jsduck/class_doc_expander.rb +1 -1
  10. data/lib/jsduck/css/parser.rb +59 -90
  11. data/lib/jsduck/css/type.rb +55 -0
  12. data/lib/jsduck/doc/parser.rb +1 -1
  13. data/lib/jsduck/doc/scanner.rb +2 -2
  14. data/lib/jsduck/doc/subproperties.rb +1 -1
  15. data/lib/jsduck/export_writer.rb +4 -4
  16. data/lib/jsduck/exporter/app.rb +2 -1
  17. data/lib/jsduck/exporter/full.rb +5 -3
  18. data/lib/jsduck/external_classes.rb +337 -5
  19. data/lib/jsduck/format/class.rb +3 -3
  20. data/lib/jsduck/format/doc.rb +6 -5
  21. data/lib/jsduck/format/subproperties.rb +1 -1
  22. data/lib/jsduck/guide_toc.rb +45 -27
  23. data/lib/jsduck/guide_toc_entry.rb +54 -0
  24. data/lib/jsduck/guides.rb +9 -5
  25. data/lib/jsduck/img/dir.rb +1 -1
  26. data/lib/jsduck/inline/example.rb +3 -1
  27. data/lib/jsduck/inline/img.rb +3 -3
  28. data/lib/jsduck/inline/link.rb +2 -2
  29. data/lib/jsduck/inline/link_renderer.rb +3 -2
  30. data/lib/jsduck/inline/video.rb +2 -1
  31. data/lib/jsduck/js/class.rb +6 -11
  32. data/lib/jsduck/js/ext_define.rb +46 -0
  33. data/lib/jsduck/js/ext_patterns.rb +7 -2
  34. data/lib/jsduck/js/rkelly_adapter.rb +16 -2
  35. data/lib/jsduck/logger.rb +40 -25
  36. data/lib/jsduck/member_registry.rb +41 -0
  37. data/lib/jsduck/news.rb +18 -5
  38. data/lib/jsduck/options/config.rb +35 -0
  39. data/lib/jsduck/options/helpful_parser.rb +111 -0
  40. data/lib/jsduck/options/input_files.rb +60 -0
  41. data/lib/jsduck/options/jsb.rb +25 -0
  42. data/lib/jsduck/{options.rb → options/parser.rb} +436 -484
  43. data/lib/jsduck/options/processor.rb +47 -0
  44. data/lib/jsduck/options/record.rb +51 -0
  45. data/lib/jsduck/output_dir.rb +4 -4
  46. data/lib/jsduck/parser.rb +5 -5
  47. data/lib/jsduck/process/components.rb +19 -0
  48. data/lib/jsduck/process/ext4_events.rb +4 -2
  49. data/lib/jsduck/process/importer.rb +5 -2
  50. data/lib/jsduck/process/inherit_members.rb +2 -0
  51. data/lib/jsduck/process/lint.rb +3 -3
  52. data/lib/jsduck/process/no_doc.rb +1 -1
  53. data/lib/jsduck/process/overrides.rb +4 -3
  54. data/lib/jsduck/process/versions.rb +86 -51
  55. data/lib/jsduck/render/class.rb +3 -2
  56. data/lib/jsduck/render/subproperties.rb +18 -0
  57. data/lib/jsduck/render/tags.rb +13 -1
  58. data/lib/jsduck/source/file.rb +2 -2
  59. data/lib/jsduck/tag/class.rb +6 -0
  60. data/lib/jsduck/tag/component.rb +19 -0
  61. data/lib/jsduck/tag/css_mixin.rb +10 -0
  62. data/lib/jsduck/tag/deprecated.rb +1 -1
  63. data/{template-min/resources/images/class-m.png → lib/jsduck/tag/icons/class-large.png} +0 -0
  64. data/lib/jsduck/tag/icons/class-redirect.png +0 -0
  65. data/lib/jsduck/tag/icons/class.png +0 -0
  66. data/{template-min/resources/images/component-m.png → lib/jsduck/tag/icons/component-large.png} +0 -0
  67. data/lib/jsduck/tag/icons/component-redirect.png +0 -0
  68. data/lib/jsduck/tag/icons/component.png +0 -0
  69. data/{template-min/resources/images/singleton-m.png → lib/jsduck/tag/icons/singleton-large.png} +0 -0
  70. data/lib/jsduck/tag/icons/singleton-redirect.png +0 -0
  71. data/lib/jsduck/tag/icons/singleton.png +0 -0
  72. data/lib/jsduck/tag/inheritdoc.rb +2 -2
  73. data/lib/jsduck/tag/new.rb +13 -0
  74. data/lib/jsduck/tag/since.rb +2 -2
  75. data/lib/jsduck/tag/singleton.rb +13 -0
  76. data/lib/jsduck/tag/tag.rb +19 -0
  77. data/lib/jsduck/tag_registry.rb +20 -81
  78. data/lib/jsduck/util/io.rb +5 -0
  79. data/lib/jsduck/util/json.rb +3 -3
  80. data/lib/jsduck/util/null_object.rb +14 -1
  81. data/lib/jsduck/util/parallel.rb +7 -3
  82. data/lib/jsduck/version.rb +1 -1
  83. data/lib/jsduck/warning/registry.rb +4 -2
  84. data/lib/jsduck/warning/tag.rb +57 -0
  85. data/lib/jsduck/web/class_icons.rb +76 -0
  86. data/lib/jsduck/web/css.rb +12 -1
  87. data/lib/jsduck/web/data.rb +4 -3
  88. data/lib/jsduck/web/index_html.rb +26 -10
  89. data/lib/jsduck/web/member_icons.rb +3 -3
  90. data/lib/jsduck/web/search.rb +4 -4
  91. data/lib/jsduck/web/source.rb +1 -1
  92. data/lib/jsduck/web/template.rb +6 -6
  93. data/lib/jsduck/web/tree.rb +22 -0
  94. data/lib/jsduck/web/writer.rb +11 -9
  95. data/template-min/app-0f524ddd276c4019a11a6128932a9c96.js +1 -0
  96. data/template-min/index-template.html +1 -1
  97. data/template-min/print-template.html +1 -1
  98. data/template-min/resources/css/{app-4689d2a5522dcd3c9e9923ca59c33f27.css → app-de670120f43fdad3091a0cc2c10daadb.css} +1 -1
  99. data/template-min/resources/images/icons.xcf +0 -0
  100. data/template-min/template.html +2 -2
  101. metadata +46 -13
  102. data/lib/jsduck/css/lexer.rb +0 -203
  103. data/lib/jsduck/option_parser.rb +0 -109
  104. data/lib/jsduck/web/icons.rb +0 -31
  105. data/template-min/app-0c945a27f43452df695771ddb60b3d14.js +0 -1
@@ -0,0 +1,47 @@
1
+ require 'jsduck/options/parser'
2
+ require 'jsduck/options/input_files'
3
+ require 'jsduck/logger'
4
+ require 'jsduck/util/json'
5
+ require 'jsduck/util/io'
6
+ require 'jsduck/util/parallel'
7
+ require 'jsduck/tag_registry'
8
+ require 'jsduck/js/ext_patterns'
9
+
10
+ module JsDuck
11
+ module Options
12
+
13
+ # A facade for all the command line options processing.
14
+ class Processor
15
+ # Takes a list of command line options, parses it to an
16
+ # Options::Record object, validates the options, applies it to
17
+ # various singleton classes and returns the Options::Record.
18
+ def self.process(args)
19
+ # HACK! First establish warnings defaults.
20
+ Logger.configure_defaults
21
+
22
+ opts = Options::Parser.new.parse(args)
23
+
24
+ # Expand list of input files
25
+ Options::InputFiles.new(opts).expand!
26
+
27
+ # Validate the options.
28
+ # Exit program when there's an error.
29
+ if err = opts.validate!
30
+ Array(err).each {|line| Logger.fatal(line) }
31
+ exit(1)
32
+ end
33
+
34
+ # Configure various objects with these options
35
+ Logger.configure(opts)
36
+ Util::Parallel.configure(opts)
37
+ TagRegistry.configure(opts)
38
+ Js::ExtPatterns.configure(opts)
39
+ Util::Json.configure(opts)
40
+ Util::IO.configure(opts)
41
+
42
+ opts
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,51 @@
1
+ module JsDuck
2
+ module Options
3
+
4
+ # Stores values of command line options.
5
+ #
6
+ # All options are initially defined with an #attribute method, which
7
+ # ensures that accessing an unexisting option will result in an
8
+ # error.
9
+ class Record
10
+ def initialize
11
+ @validators = {}
12
+ end
13
+
14
+ # Defines accessor for an option,
15
+ # and assigns a default value for it.
16
+ def attribute(name, default=nil)
17
+ instance_variable_set("@#{name}", default)
18
+ # Use `send` to invoke private attr_accessor method. As we only
19
+ # expect a single OptionsRecord to exist for the lifetime of the
20
+ # app, it should be safe to define a method on a class.
21
+ self.class.send(:attr_accessor, name)
22
+ end
23
+
24
+ # Defines a validator function that gets run after all the
25
+ # options have been parsed. When validation fails, the function
26
+ # should return an error message string (or an array of string
27
+ # for multi-line error message) otherwise nil, to signify
28
+ # success.
29
+ def validator(name, &block)
30
+ @validators[name] = block
31
+ end
32
+
33
+ # Runs all the validators. Returns an error message string from
34
+ # the first failed validation or nil when everything is OK.
35
+ #
36
+ # Alternatively runs just one validator by name. Used in testing.
37
+ def validate!(name=nil)
38
+ validators = name ? [@validators[name]] : @validators.values
39
+
40
+ validators.each do |block|
41
+ if err = block.call()
42
+ return err
43
+ end
44
+ end
45
+ return nil
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -11,18 +11,18 @@ module JsDuck
11
11
  def self.clean(opts)
12
12
  if opts.cache && cache_dir_needs_preserving(opts)
13
13
  # Remove all files inside <output-dir> except .cache/
14
- Dir[opts.output_dir + "/*"].each do |file|
14
+ Dir[opts.output + "/*"].each do |file|
15
15
  FileUtils.rm_rf(file) unless file =~ /\/.cache\z/
16
16
  end
17
17
  else
18
18
  # Remove and recreate the entire <output-dir>
19
- FileUtils.rm_rf(opts.output_dir)
20
- FileUtils.mkdir(opts.output_dir)
19
+ FileUtils.rm_rf(opts.output)
20
+ FileUtils.mkdir(opts.output)
21
21
  end
22
22
  end
23
23
 
24
24
  def self.cache_dir_needs_preserving(opts)
25
- opts.cache_dir == opts.output_dir + "/.cache" && File.exists?(opts.cache_dir)
25
+ opts.cache_dir == opts.output + "/.cache" && File.exists?(opts.cache_dir)
26
26
  end
27
27
 
28
28
  end
@@ -9,7 +9,7 @@ require 'jsduck/base_type'
9
9
  require 'jsduck/class_doc_expander'
10
10
 
11
11
  module JsDuck
12
- # Performs the actual parsing of CSS or JS source.
12
+ # Performs the actual parsing of SCSS or JS source.
13
13
  #
14
14
  # This is the class that brings together all the different steps of
15
15
  # parsing the source.
@@ -27,7 +27,7 @@ module JsDuck
27
27
  def parse(contents, filename="", options={})
28
28
  @doc_processor.filename = @filename = filename
29
29
 
30
- parse_js_or_css(contents, filename, options).map do |docset|
30
+ parse_js_or_scss(contents, filename, options).map do |docset|
31
31
  expand(docset)
32
32
  end.flatten.map do |docset|
33
33
  merge(docset)
@@ -36,9 +36,9 @@ module JsDuck
36
36
 
37
37
  private
38
38
 
39
- # Parses the file depending on filename as JS or CSS
40
- def parse_js_or_css(contents, filename, options)
41
- if filename =~ /\.s?css$/
39
+ # Parses the file depending on filename as JS or SCSS
40
+ def parse_js_or_scss(contents, filename, options)
41
+ if filename =~ /\.scss$/
42
42
  docs = Css::Parser.new(contents, options).parse
43
43
  else
44
44
  docs = Js::Parser.new(contents, options).parse
@@ -0,0 +1,19 @@
1
+ module JsDuck
2
+ module Process
3
+
4
+ # Auto-detects classes inheriting from Ext.Component, and marks
5
+ # them as :component.
6
+ class Components
7
+ def initialize(relations)
8
+ @relations = relations
9
+ end
10
+
11
+ def process_all!
12
+ @relations.each do |cls|
13
+ cls[:component] = true if cls.inherits_from?("Ext.Component")
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -1,3 +1,5 @@
1
+ require 'ostruct'
2
+
1
3
  module JsDuck
2
4
  module Process
3
5
 
@@ -7,13 +9,13 @@ module JsDuck
7
9
  # But only does so when :ext4_events option is set to true or the
8
10
  # code itself is detected as being writted in Ext4 style.
9
11
  class Ext4Events
10
- def initialize(classes, opts={})
12
+ def initialize(classes, opts=OpenStruct.new)
11
13
  @classes = classes
12
14
  @opts = opts
13
15
  end
14
16
 
15
17
  def process_all!
16
- if @opts[:ext4_events] == true || (@opts[:ext4_events] == nil && ext4_style_code?)
18
+ if @opts.ext4_events == true || (@opts.ext4_events == nil && ext4_style_code?)
17
19
  @classes.each_value {|cls| process(cls) }
18
20
  end
19
21
  end
@@ -23,7 +23,10 @@ module JsDuck
23
23
  private
24
24
 
25
25
  def current_version
26
- Util::NullObject.new(:[] => Util::NullObject.new(:[] => true))
26
+ JsDuck::Util::NullObject.new(
27
+ :[] => JsDuck::Util::NullObject.new( # class
28
+ :[] => JsDuck::Util::NullObject.new( # member
29
+ :length => 1.0 / 0))) # params count == Infinity
27
30
  end
28
31
 
29
32
  # Reads in data from all .json files in directory
@@ -61,7 +64,7 @@ module JsDuck
61
64
  def members_id_index(json)
62
65
  index = {}
63
66
  json["members"].each do |m|
64
- index[m["id"]] = true
67
+ index[m["id"]] = m["params"] ? m["params"].map {|p| p["name"] } : true
65
68
  end
66
69
  index
67
70
  end
@@ -19,6 +19,7 @@ module JsDuck
19
19
  # - :params
20
20
  # - :return
21
21
  # - :throws
22
+ # - :properties
22
23
  #
23
24
  # In case of auto-detected members that inherit from a public
24
25
  # member in parent class, we inherit all fields that aren't
@@ -82,6 +83,7 @@ module JsDuck
82
83
  m[:params] = parent[:params] if inherit_params?(m, parent)
83
84
  m[:return] = parent[:return] unless m[:return]
84
85
  m[:throws] = parent[:throws] unless m[:throws] && m[:throws].length > 0
86
+ m[:properties] = parent[:properties] unless m[:properties] && m[:properties].length > 0
85
87
 
86
88
  # Don't inherit type from parent when:
87
89
  # - member itself has type and it's not auto-detected
@@ -27,7 +27,7 @@ module JsDuck
27
27
  if !member[:name] || member[:name] == ""
28
28
  warn(:name_missing, "Unnamed #{member[:tagname]}", member)
29
29
  end
30
- (member[:params] || []).each do |p|
30
+ Array(member[:params]).each do |p|
31
31
  if !p[:name] || p[:name] == ""
32
32
  warn(:name_missing, "Unnamed parameter", member)
33
33
  end
@@ -40,7 +40,7 @@ module JsDuck
40
40
  each_member do |member|
41
41
  if member[:tagname] == :method
42
42
  optional_found = false
43
- member[:params].each do |p|
43
+ Array(member[:params]).each do |p|
44
44
  if optional_found && !p[:optional]
45
45
  warn(:req_after_opt, "Optional param followed by regular param #{p[:name]}", member)
46
46
  end
@@ -54,7 +54,7 @@ module JsDuck
54
54
  def warn_duplicate_params
55
55
  each_member do |member|
56
56
  params = {}
57
- (member[:params] || []).each do |p|
57
+ Array(member[:params]).each do |p|
58
58
  if params[p[:name]]
59
59
  warn(:dup_param, "Duplicate parameter name #{p[:name]}", member)
60
60
  end
@@ -41,7 +41,7 @@ module JsDuck
41
41
  def warn(type, msg, owner)
42
42
  visibility = owner[:private] ? :private : (owner[:protected] ? :protected : :public)
43
43
 
44
- Logger.warn_nodoc(type, visibility, msg, owner[:files][0])
44
+ Logger.warn(:nodoc, msg, owner[:files][0], [type, visibility])
45
45
  end
46
46
 
47
47
  end
@@ -1,17 +1,18 @@
1
1
  require 'jsduck/logger'
2
+ require 'ostruct'
2
3
 
3
4
  module JsDuck
4
5
  module Process
5
6
 
6
7
  class Overrides
7
- def initialize(classes_hash, opts = {:external_classes => []})
8
+ def initialize(classes_hash, opts = OpenStruct.new(:external => []))
8
9
  @classes_hash = classes_hash
9
10
  @opts = opts
10
11
  end
11
12
 
12
13
  # Applies all override classes to target classes, then deletes
13
14
  # the overrides themselves from classes hash and adds the names
14
- # of all the processed overrides to external_classes list in
15
+ # of all the processed overrides to external classes list in
15
16
  # options object.
16
17
  def process_all!
17
18
  overrides = []
@@ -28,7 +29,7 @@ module JsDuck
28
29
  @classes_hash.delete(cls[:name])
29
30
  end
30
31
 
31
- @opts[:external_classes] += overrides.map {|c| c[:name] }
32
+ @opts.external += overrides.map {|c| c[:name] }
32
33
  end
33
34
 
34
35
  private
@@ -1,5 +1,5 @@
1
1
  require 'jsduck/process/importer'
2
- require 'jsduck/tag_registry'
2
+ require 'ostruct'
3
3
 
4
4
  module JsDuck
5
5
  module Process
@@ -7,76 +7,65 @@ module JsDuck
7
7
  # Generates @since and @new tags by importing JSDuck exports of
8
8
  # older versions of the same project and looking in which version
9
9
  # a class or method first appeared.
10
- #
11
- # Additionally here the tooltip text for @new tag gets injected.
12
10
  class Versions
13
- def initialize(relations, opts={}, importer=nil)
11
+ def initialize(relations, opts=OpenStruct.new, importer=Process::Importer.new)
14
12
  @relations = relations
15
13
  @opts = opts
16
- # Allow different importer to be injected for testing
17
- @importer = importer || Process::Importer.new
14
+ @importer = importer
18
15
  end
19
16
 
20
17
  # Loads in exported docs and generates @since and @new tags.
21
18
  def process_all!
22
- init_new_tag_tooltip!
23
-
24
- if @opts[:imports].length > 0
25
- generate_since_tags(@importer.import(@opts[:imports]))
19
+ if @opts.import.length > 0
20
+ @versions = @importer.import(@opts.import)
21
+ add_since_tags
26
22
  end
27
23
  end
28
24
 
29
25
  private
30
26
 
31
- # Initializes the tooltip text for the signature of @new tag.
32
- def init_new_tag_tooltip!
33
- signature = TagRegistry.get_by_name(:new).signature
34
- if @opts[:new_since]
35
- signature[:tooltip] = "New since #{@opts[:new_since]}"
36
- elsif @opts[:imports].length > 0
37
- signature[:tooltip] = "New since #{@opts[:imports].last[:version]}"
38
- end
39
- end
27
+ # classes...
40
28
 
41
29
  # Using the imported versions data, adds @since tags to all
42
- # classes/members.
43
- def generate_since_tags(versions)
44
- new_versions = build_new_versions_map(versions)
45
-
30
+ # classes/members/params.
31
+ def add_since_tags
46
32
  @relations.each do |cls|
47
- v = cls[:since] || class_since(versions, cls)
33
+ v = cls[:since] || class_since(cls)
48
34
  cls[:since] = v
49
- cls[:new] = true if new_versions[v]
35
+ cls[:new] = true if is_new?(v)
50
36
 
51
- cls.all_local_members.each do |m|
52
- v = m[:since] || member_since(versions, cls, m)
53
- m[:since] = v
54
- m[:new] = true if new_versions[v]
55
- end
37
+ add_members_since_tags(cls)
56
38
  end
57
39
  end
58
40
 
59
- # Generates a lookup table of versions that we are going to label
60
- # with @new tags. By default we use the latest version, otherwise
61
- # use all versions since the latest.
62
- def build_new_versions_map(versions)
63
- new_versions = {}
64
-
65
- if @opts[:new_since]
66
- versions.map {|v| v[:version] }.each do |v|
67
- if v == @opts[:new_since] || !new_versions.empty?
68
- new_versions[v] = true
69
- end
41
+ # Returns name of the version since which the class is available
42
+ def class_since(cls)
43
+ @versions.each do |ver|
44
+ return ver[:version] if ver[:classes][cls[:name]]
45
+ cls[:alternateClassNames].each do |name|
46
+ return ver[:version] if ver[:classes][name]
70
47
  end
71
- else
72
- new_versions[versions.last[:version]] = true
73
48
  end
49
+ end
74
50
 
75
- new_versions
51
+ # members...
52
+
53
+ def add_members_since_tags(cls)
54
+ cls.all_local_members.each do |m|
55
+ # Remember the initial explicit @since tag value
56
+ # to disable params processing when it's present.
57
+ explicit_since = m[:since]
58
+
59
+ v = m[:since] || member_since(cls, m)
60
+ m[:since] = v
61
+ m[:new] = true if is_new?(v)
62
+
63
+ add_params_since_tags(cls, m, v) unless explicit_since
64
+ end
76
65
  end
77
66
 
78
- def member_since(versions, cls, m)
79
- versions.each do |ver|
67
+ def member_since(cls, m)
68
+ @versions.each do |ver|
80
69
  c = ver[:classes][cls[:name]]
81
70
  return ver[:version] if c && c[m[:id]]
82
71
  cls[:alternateClassNames].each do |name|
@@ -86,14 +75,60 @@ module JsDuck
86
75
  end
87
76
  end
88
77
 
89
- # Returns name of the version since which the class is available
90
- def class_since(versions, cls)
91
- versions.each do |ver|
92
- return ver[:version] if ver[:classes][cls[:name]]
78
+ # params...
79
+
80
+ def add_params_since_tags(cls, member, member_version)
81
+ Array(member[:params]).each_with_index do |p, i|
82
+ v = param_since(cls, member, i)
83
+ if v != member_version
84
+ p[:since] = v
85
+ p[:new] = true if is_new?(v)
86
+ end
87
+ end
88
+ end
89
+
90
+ def param_since(cls, m, i)
91
+ @versions.each do |ver|
92
+ c = ver[:classes][cls[:name]]
93
+ return ver[:version] if c && has_param?(c[m[:id]], i)
93
94
  cls[:alternateClassNames].each do |name|
94
- return ver[:version] if ver[:classes][name]
95
+ c = ver[:classes][name]
96
+ return ver[:version] if c && has_param?(c[m[:id]], i)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Because parameters can be renamed between versions, only
102
+ # consider parameter count.
103
+ def has_param?(member, param_index)
104
+ member && member.respond_to?(:length) && member.length > param_index
105
+ end
106
+
107
+ # helpers...
108
+
109
+ # Should items introduced in given version be marked as new?
110
+ def is_new?(version_nr)
111
+ @new_versions = new_versions_map unless @new_versions
112
+ @new_versions[version_nr]
113
+ end
114
+
115
+ # Generates a lookup table of versions that we are going to label
116
+ # with @new tags. By default we use the latest version, otherwise
117
+ # use all versions since the latest.
118
+ def new_versions_map
119
+ new_versions = {}
120
+
121
+ if @opts.new_since
122
+ @versions.map {|v| v[:version] }.each do |v|
123
+ if v == @opts.new_since || !new_versions.empty?
124
+ new_versions[v] = true
125
+ end
95
126
  end
127
+ else
128
+ new_versions[@versions.last[:version]] = true
96
129
  end
130
+
131
+ new_versions
97
132
  end
98
133
 
99
134
  end