facter 4.0.52 → 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +202 -0
  3. data/lib/facter.rb +21 -21
  4. data/lib/facter/config.rb +2 -0
  5. data/lib/facter/custom_facts/core/execution/base.rb +7 -3
  6. data/lib/facter/custom_facts/core/execution/popen3.rb +13 -1
  7. data/lib/facter/custom_facts/core/execution/posix.rb +2 -2
  8. data/lib/facter/custom_facts/core/execution/windows.rb +1 -1
  9. data/lib/facter/custom_facts/util/collection.rb +5 -0
  10. data/lib/facter/custom_facts/util/directory_loader.rb +1 -1
  11. data/lib/facter/custom_facts/util/normalization.rb +7 -2
  12. data/lib/facter/custom_facts/util/windows_root.rb +2 -1
  13. data/lib/facter/facts/aix/processors/cores.rb +16 -0
  14. data/lib/facter/facts/aix/processors/threads.rb +16 -0
  15. data/lib/facter/facts/freebsd/is_virtual.rb +1 -5
  16. data/lib/facter/facts/freebsd/virtual.rb +1 -2
  17. data/lib/facter/facts/linux/az_metadata.rb +1 -5
  18. data/lib/facter/facts/linux/cloud/provider.rb +5 -2
  19. data/lib/facter/facts/linux/ec2_metadata.rb +1 -5
  20. data/lib/facter/facts/linux/ec2_userdata.rb +1 -5
  21. data/lib/facter/facts/linux/hypervisors/xen.rb +1 -4
  22. data/lib/facter/facts/linux/is_virtual.rb +1 -5
  23. data/lib/facter/facts/linux/processors/cores.rb +16 -0
  24. data/lib/facter/facts/linux/processors/threads.rb +16 -0
  25. data/lib/facter/facts/linux/virtual.rb +1 -2
  26. data/lib/facter/facts/macosx/os/macosx/version.rb +15 -4
  27. data/lib/facter/facts/macosx/processors/cores.rb +16 -0
  28. data/lib/facter/facts/macosx/processors/threads.rb +16 -0
  29. data/lib/facter/facts/solaris/hypervisors/ldom.rb +1 -1
  30. data/lib/facter/facts/solaris/hypervisors/zone.rb +1 -1
  31. data/lib/facter/facts/solaris/mountpoints.rb +1 -1
  32. data/lib/facter/facts/solaris/processors/cores.rb +16 -0
  33. data/lib/facter/facts/solaris/processors/threads.rb +16 -0
  34. data/lib/facter/facts/windows/az_metadata.rb +1 -5
  35. data/lib/facter/facts/windows/cloud/provider.rb +6 -2
  36. data/lib/facter/facts/windows/ec2_metadata.rb +1 -1
  37. data/lib/facter/facts/windows/ec2_userdata.rb +1 -1
  38. data/lib/facter/facts/windows/gce.rb +1 -1
  39. data/lib/facter/facts/windows/hypervisors/hyperv.rb +1 -1
  40. data/lib/facter/facts/windows/hypervisors/kvm.rb +2 -1
  41. data/lib/facter/facts/windows/hypervisors/virtualbox.rb +2 -2
  42. data/lib/facter/facts/windows/hypervisors/vmware.rb +1 -1
  43. data/lib/facter/facts/windows/hypervisors/xen.rb +3 -1
  44. data/lib/facter/facts/windows/is_virtual.rb +15 -0
  45. data/lib/facter/facts/windows/{virtualization/is_virtual.rb → processors/cores.rb} +4 -4
  46. data/lib/facter/facts/windows/{virtualization/virtual.rb → processors/threads.rb} +4 -4
  47. data/lib/facter/facts/windows/virtual.rb +15 -0
  48. data/lib/facter/framework/cli/cli.rb +13 -15
  49. data/lib/facter/framework/core/cache_manager.rb +2 -2
  50. data/lib/facter/framework/core/fact/external/external_fact_manager.rb +0 -1
  51. data/lib/facter/framework/core/fact/internal/internal_fact_manager.rb +41 -39
  52. data/lib/facter/framework/core/fact_filter.rb +4 -14
  53. data/lib/facter/framework/core/fact_loaders/external_fact_loader.rb +9 -6
  54. data/lib/facter/framework/core/fact_loaders/fact_loader.rb +39 -36
  55. data/lib/facter/framework/core/fact_manager.rb +82 -14
  56. data/lib/facter/framework/core/file_loader.rb +1 -1
  57. data/lib/facter/framework/core/options/config_file_options.rb +7 -0
  58. data/lib/facter/framework/core/options/option_store.rb +3 -1
  59. data/lib/facter/framework/formatters/formatter_helper.rb +3 -5
  60. data/lib/facter/framework/parsers/query_parser.rb +10 -24
  61. data/lib/facter/models/fact_collection.rb +48 -5
  62. data/lib/facter/models/resolved_fact.rb +2 -3
  63. data/lib/facter/models/searched_fact.rb +2 -3
  64. data/lib/facter/resolvers/aix/ffi/ffi_helper.rb +1 -1
  65. data/lib/facter/resolvers/aix/processors.rb +4 -0
  66. data/lib/facter/resolvers/base_resolver.rb +2 -2
  67. data/lib/facter/resolvers/dmi_decode.rb +0 -1
  68. data/lib/facter/resolvers/ec2.rb +8 -1
  69. data/lib/facter/resolvers/linux/hostname.rb +16 -5
  70. data/lib/facter/resolvers/linux/networking.rb +18 -1
  71. data/lib/facter/resolvers/lsb_release.rb +1 -2
  72. data/lib/facter/resolvers/macosx/mountpoints.rb +14 -1
  73. data/lib/facter/resolvers/macosx/processor.rb +16 -1
  74. data/lib/facter/resolvers/mountpoints.rb +16 -8
  75. data/lib/facter/resolvers/networking.rb +6 -3
  76. data/lib/facter/resolvers/partitions.rb +1 -3
  77. data/lib/facter/resolvers/processors_lscpu.rb +44 -0
  78. data/lib/facter/resolvers/ruby.rb +1 -1
  79. data/lib/facter/resolvers/selinux.rb +5 -7
  80. data/lib/facter/resolvers/solaris/ffi/structs.rb +12 -0
  81. data/lib/facter/resolvers/solaris/mountpoints.rb +22 -16
  82. data/lib/facter/resolvers/solaris/networking.rb +20 -5
  83. data/lib/facter/resolvers/solaris/processors.rb +7 -0
  84. data/lib/facter/resolvers/solaris/zone.rb +0 -1
  85. data/lib/facter/resolvers/windows/ffi/identity_ffi.rb +5 -0
  86. data/lib/facter/resolvers/windows/ffi/kernel_ffi.rb +1 -1
  87. data/lib/facter/resolvers/windows/identity.rb +1 -6
  88. data/lib/facter/resolvers/windows/processors.rb +41 -4
  89. data/lib/facter/resolvers/windows/uptime.rb +3 -22
  90. data/lib/facter/resolvers/windows/virtualization.rb +46 -44
  91. data/lib/facter/resolvers/xen.rb +6 -1
  92. data/lib/facter/templates/man.erb +6 -6
  93. data/lib/facter/util/facts/posix/virtual_detector.rb +74 -0
  94. data/lib/facter/util/facts/unit_converter.rb +2 -2
  95. data/lib/facter/util/linux/dhcp.rb +4 -1
  96. data/lib/facter/util/linux/if_inet6.rb +73 -0
  97. data/lib/facter/util/linux/socket_parser.rb +18 -3
  98. data/lib/facter/util/resolvers/http.rb +7 -1
  99. data/lib/facter/util/resolvers/networking/primary_interface.rb +11 -5
  100. data/lib/facter/util/utils.rb +18 -1
  101. data/lib/facter/version.rb +1 -1
  102. metadata +60 -11
  103. data/lib/facter/framework/core/fact_augmenter.rb +0 -37
  104. data/lib/facter/util/facts/virtual_detector.rb +0 -90
@@ -15,7 +15,7 @@ module Facts
15
15
  private
16
16
 
17
17
  def vmware?
18
- Facter::Resolvers::Virtualization.resolve(:virtual) == 'vmware' ||
18
+ Facter::Resolvers::Windows::Virtualization.resolve(:virtual) == 'vmware' ||
19
19
  Facter::Resolvers::DMIBios.resolve(:manufacturer) == 'VMware, Inc.'
20
20
  end
21
21
  end
@@ -7,7 +7,9 @@ module Facts
7
7
  FACT_NAME = 'hypervisors.xen'
8
8
 
9
9
  def call_the_resolver
10
- fact_value = { context: hvm? ? 'hvm' : 'pv' } if Facter::Resolvers::Virtualization.resolve(:virtual) == 'xen'
10
+ if Facter::Resolvers::Windows::Virtualization.resolve(:virtual) == 'xen'
11
+ fact_value = { context: hvm? ? 'hvm' : 'pv' }
12
+ end
11
13
 
12
14
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
13
15
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Windows
5
+ class IsVirtual
6
+ FACT_NAME = 'is_virtual'
7
+
8
+ def call_the_resolver
9
+ fact_value = Facter::Resolvers::Windows::Virtualization.resolve(:is_virtual)
10
+
11
+ Facter::ResolvedFact.new(FACT_NAME, fact_value)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Facts
4
4
  module Windows
5
- module Virtualization
6
- class IsVirtual
7
- FACT_NAME = 'is_virtual'
5
+ module Processors
6
+ class Cores
7
+ FACT_NAME = 'processors.cores'
8
8
 
9
9
  def call_the_resolver
10
- fact_value = Facter::Resolvers::Virtualization.resolve(:is_virtual)
10
+ fact_value = Facter::Resolvers::Processors.resolve(:cores_per_socket)
11
11
 
12
12
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
13
13
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Facts
4
4
  module Windows
5
- module Virtualization
6
- class Virtual
7
- FACT_NAME = 'virtual'
5
+ module Processors
6
+ class Threads
7
+ FACT_NAME = 'processors.threads'
8
8
 
9
9
  def call_the_resolver
10
- fact_value = Facter::Resolvers::Virtualization.resolve(:virtual)
10
+ fact_value = Facter::Resolvers::Processors.resolve(:threads_per_core)
11
11
 
12
12
  Facter::ResolvedFact.new(FACT_NAME, fact_value)
13
13
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facts
4
+ module Windows
5
+ class Virtual
6
+ FACT_NAME = 'virtual'
7
+
8
+ def call_the_resolver
9
+ fact_value = Facter::Resolvers::Windows::Virtualization.resolve(:virtual)
10
+
11
+ Facter::ResolvedFact.new(FACT_NAME, fact_value)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -97,6 +97,11 @@ module Facter
97
97
  type: :boolean,
98
98
  desc: 'Resolve facts sequentially'
99
99
 
100
+ class_option :puppet,
101
+ type: :boolean,
102
+ aliases: '-p',
103
+ desc: 'Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts.'
104
+
100
105
  desc '--man', 'Display manual.', hide: true
101
106
  map ['--man'] => :man
102
107
  def man(*args)
@@ -111,6 +116,7 @@ module Facter
111
116
 
112
117
  desc 'query', 'Default method', hide: true
113
118
  def query(*args)
119
+ Facter.puppet_facts if options[:puppet]
114
120
  output, status = Facter.to_user_output(@options, *args)
115
121
  puts output
116
122
 
@@ -126,7 +132,7 @@ module Facter
126
132
  Facter.values(@options, args)
127
133
  end
128
134
 
129
- desc '--version, -v', 'Print the version', hide: true
135
+ desc '--version, -v', 'Print the version'
130
136
  map ['--version', '-v'] => :version
131
137
  def version(*_args)
132
138
  puts Facter::VERSION
@@ -156,19 +162,7 @@ module Facter
156
162
  puts cache_groups
157
163
  end
158
164
 
159
- desc '--puppet, -p', 'Load the Puppet libraries, thus allowing Facter to load Puppet-specific facts.'
160
- map ['--puppet', '-p'] => :puppet
161
- def puppet(*args)
162
- Facter.puppet_facts
163
-
164
- output, status = Facter.to_user_output(@options, *args)
165
- puts output
166
-
167
- status = 1 if Facter::Log.errors?
168
- exit status
169
- end
170
-
171
- desc 'help', 'Help for all arguments'
165
+ desc '--help, -h', 'Help for all arguments'
172
166
  def help(*args)
173
167
  help_string = +''
174
168
  help_string << help_header(args)
@@ -205,7 +199,11 @@ module Facter
205
199
  Cli.commands
206
200
  .select { |_k, command_class| command_class.instance_of?(Thor::Command) }
207
201
  .each do |_k, command|
208
- help_command_options << build_option(command['name'], [], command['description'])
202
+ help_command_options << build_option(
203
+ command['name'],
204
+ [command['usage'].split(',')[1]],
205
+ command['description']
206
+ )
209
207
  end
210
208
 
211
209
  help_command_options
@@ -123,7 +123,7 @@ cache_format_version is incorrect!")
123
123
  return unless data[searched_fact.name]
124
124
 
125
125
  [Facter::ResolvedFact.new(searched_fact.name, data[searched_fact.name], searched_fact.type,
126
- searched_fact.user_query, searched_fact.filter_tokens)]
126
+ searched_fact.user_query)]
127
127
  end
128
128
  end
129
129
 
@@ -133,7 +133,7 @@ cache_format_version is incorrect!")
133
133
  next if fact_name == 'cache_format_version'
134
134
 
135
135
  fact = Facter::ResolvedFact.new(fact_name, fact_value, searched_fact.type,
136
- searched_fact.user_query, searched_fact.filter_tokens)
136
+ searched_fact.user_query)
137
137
  fact.file = searched_fact.file
138
138
  facts << fact
139
139
  end
@@ -19,7 +19,6 @@ module Facter
19
19
  custom_facts.each do |custom_fact|
20
20
  fact = LegacyFacter[custom_fact.name]
21
21
  resolved_fact = ResolvedFact.new(custom_fact.name, fact.value, :custom)
22
- resolved_fact.filter_tokens = []
23
22
  resolved_fact.user_query = custom_fact.user_query
24
23
  resolved_fact.file = fact.options[:file]
25
24
 
@@ -2,20 +2,25 @@
2
2
 
3
3
  module Facter
4
4
  class InternalFactManager
5
- @@log = Facter::Log.new(self)
6
-
5
+ # resolves each SearchFact and filter out facts that do not match the given user query
6
+ # @param searched_facts [Array<Facter::SearchedFact>] array of searched facts
7
+ #
8
+ # @return [Array<Facter::ResolvedFact>]
9
+ #
10
+ # @api private
7
11
  def resolve_facts(searched_facts)
8
12
  internal_searched_facts = filter_internal_facts(searched_facts)
9
-
10
13
  resolved_facts = if Options[:sequential]
11
- @@log.debug('Resolving facts sequentially')
14
+ log.debug('Resolving facts sequentially')
12
15
  resolve_sequentially(internal_searched_facts)
13
16
  else
14
- @@log.debug('Resolving fact in parallel')
15
- threads = start_threads(internal_searched_facts)
16
- join_threads(threads, internal_searched_facts)
17
+ log.debug('Resolving fact in parallel')
18
+ resolve_in_parallel(internal_searched_facts)
17
19
  end
18
20
 
21
+ resolved_facts.flatten!
22
+ resolved_facts.compact!
23
+
19
24
  nil_resolved_facts = resolve_nil_facts(searched_facts)
20
25
 
21
26
  resolved_facts.concat(nil_resolved_facts)
@@ -27,6 +32,17 @@ module Facter
27
32
  searched_facts.select { |searched_fact| %i[core legacy].include? searched_fact.type }
28
33
  end
29
34
 
35
+ def valid_fact?(searched_fact, resolved_fact)
36
+ return if resolved_fact.value.nil?
37
+
38
+ searched_fact_name = searched_fact.name
39
+ if searched_fact_name.include?('.*')
40
+ resolved_fact.name.match(searched_fact_name)
41
+ else
42
+ resolved_fact.name == searched_fact_name
43
+ end
44
+ end
45
+
30
46
  def resolve_nil_facts(searched_facts)
31
47
  resolved_facts = []
32
48
  searched_facts.select { |fact| fact.type == :nil }.each do |fact|
@@ -37,49 +53,35 @@ module Facter
37
53
  end
38
54
 
39
55
  def resolve_sequentially(searched_facts)
40
- resolved_facts = []
41
-
42
- searched_facts
43
- .uniq { |searched_fact| searched_fact.fact_class.name }
44
- .each do |searched_fact|
45
- begin
46
- fact = CoreFact.new(searched_fact)
47
- fact_value = fact.create
48
- resolved_facts << fact_value unless fact_value.nil?
49
- rescue StandardError => e
50
- @@log.log_exception(e)
51
- end
52
- end
56
+ searched_facts.map! { |searched_fact| resolve_fact(searched_fact) }
57
+ end
53
58
 
54
- resolved_facts.flatten!
55
- FactAugmenter.augment_resolved_facts(searched_facts, resolved_facts)
59
+ def resolve_in_parallel(searched_facts)
60
+ searched_facts.map! do |searched_fact|
61
+ Thread.new { resolve_fact(searched_fact) }
62
+ end.map!(&:value)
56
63
  end
57
64
 
58
- def start_threads(searched_facts)
59
- # only resolve a fact once, even if multiple search facts depend on that fact
60
- searched_facts
61
- .uniq { |searched_fact| searched_fact.fact_class.name }
62
- .map do |searched_fact|
63
- Thread.new do
64
- resolve_fact(searched_fact)
65
+ def resolve_fact(searched_fact)
66
+ fact_value = core_fact(searched_fact)
67
+ Array(fact_value).map! do |resolved_fact|
68
+ if valid_fact?(searched_fact, resolved_fact)
69
+ resolved_fact.user_query = searched_fact.user_query
70
+ resolved_fact
65
71
  end
66
72
  end
67
73
  end
68
74
 
69
- def join_threads(threads, searched_facts)
70
- resolved_facts = threads.map(&:value)
71
- resolved_facts.compact!
72
- resolved_facts.flatten!
73
-
74
- FactAugmenter.augment_resolved_facts(searched_facts, resolved_facts)
75
- end
76
-
77
- def resolve_fact(searched_fact)
75
+ def core_fact(searched_fact)
78
76
  fact = CoreFact.new(searched_fact)
79
77
  fact.create
80
78
  rescue StandardError => e
81
- @@log.log_exception(e)
79
+ log.log_exception(e)
82
80
  nil
83
81
  end
82
+
83
+ def log
84
+ @log ||= Facter::Log.new(self)
85
+ end
84
86
  end
85
87
  end
@@ -1,21 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Facter
4
- # Filter inside value of a fact.
5
- # e.g. os.release.major is the user query, os.release is the fact
6
- # and major is the filter criteria inside tha fact
7
4
  class FactFilter
8
- def filter_facts!(searched_facts, user_query)
9
- filter_legacy_facts!(searched_facts) if user_query.empty?
10
- filter_blocked_legacy_facts!(searched_facts)
11
-
12
- searched_facts.each do |fact|
13
- fact.value = if fact.filter_tokens.any? && fact.value.respond_to?(:dig)
14
- fact.value.dig(*fact.filter_tokens)
15
- else
16
- fact.value
17
- end
18
- end
5
+ def filter_facts!(resolved_facts, user_query)
6
+ filter_legacy_facts!(resolved_facts) if user_query.empty?
7
+ filter_blocked_legacy_facts!(resolved_facts)
8
+ resolved_facts
19
9
  end
20
10
 
21
11
  private
@@ -10,20 +10,23 @@ module Facter
10
10
  @external_facts = load_external_facts
11
11
  end
12
12
 
13
+ def load_fact(fact_name)
14
+ build_custom_facts(LegacyFacter.collection.custom_fact(fact_name)) || []
15
+ end
16
+
13
17
  private
14
18
 
15
19
  def load_custom_facts
16
- custom_facts = []
17
-
18
20
  custom_facts_to_load = LegacyFacter.collection.custom_facts
21
+ build_custom_facts(custom_facts_to_load) || []
22
+ end
19
23
 
20
- custom_facts_to_load&.each do |k, v|
24
+ def build_custom_facts(custom_facts_to_load)
25
+ custom_facts_to_load&.map do |k, v|
21
26
  loaded_fact = LoadedFact.new(k.to_s, nil, :custom)
22
27
  loaded_fact.is_env = v.options[:is_env] if v.options[:is_env]
23
- custom_facts << loaded_fact
28
+ loaded_fact
24
29
  end
25
-
26
- custom_facts
27
30
  end
28
31
 
29
32
  def load_external_facts
@@ -11,44 +11,27 @@ module Facter
11
11
 
12
12
  @internal_facts = []
13
13
  @external_facts = []
14
+ @custom_facts = []
14
15
  @facts = []
15
- end
16
16
 
17
- def load(options)
18
17
  @internal_loader ||= InternalFactLoader.new
19
18
  @external_fact_loader ||= ExternalFactLoader.new
19
+ end
20
20
 
21
- @facts = []
22
- @external_facts = []
23
-
24
- @internal_facts = load_internal_facts(options)
21
+ def load(user_query, options)
22
+ @internal_facts = load_internal_facts(user_query, options)
23
+ @custom_facts = load_custom_facts(options)
25
24
  @external_facts = load_external_facts(options)
26
25
 
27
26
  filter_env_facts
28
27
 
29
- @facts = @internal_facts + @external_facts
30
- end
31
-
32
- private
33
-
34
- def filter_env_facts
35
- env_fact_names = @external_facts.select { |fact| fact.is_env == true }.map(&:name)
36
- return unless env_fact_names.any?
37
-
38
- @internal_facts.delete_if do |fact|
39
- if env_fact_names.include?(fact.name)
40
- @log.debug("Reading #{fact.name} fact from environment variable")
41
- true
42
- else
43
- false
44
- end
45
- end
28
+ @facts = @internal_facts + @external_facts + @custom_facts
46
29
  end
47
30
 
48
- def load_internal_facts(options)
31
+ def load_internal_facts(user_query, options)
49
32
  @log.debug('Loading internal facts')
50
33
  internal_facts = []
51
- if options[:user_query] || options[:show_legacy]
34
+ if user_query || options[:show_legacy]
52
35
  # if we have a user query, then we must search in core facts and legacy facts
53
36
  @log.debug('Loading all internal facts')
54
37
  internal_facts = @internal_loader.facts
@@ -60,23 +43,43 @@ module Facter
60
43
  block_facts(internal_facts, options)
61
44
  end
62
45
 
46
+ def load_custom_fact(options, fact_name)
47
+ return [] unless options[:custom_facts]
48
+
49
+ custom_facts = @external_fact_loader.load_fact(fact_name)
50
+ block_facts(custom_facts, options)
51
+ end
52
+
53
+ def load_custom_facts(options)
54
+ return [] unless options[:custom_facts]
55
+
56
+ @log.debug('Loading custom facts')
57
+ custom_facts = @external_fact_loader.custom_facts
58
+ block_facts(custom_facts, options)
59
+ end
60
+
63
61
  def load_external_facts(options)
62
+ return [] unless options[:external_facts]
63
+
64
64
  @log.debug('Loading external facts')
65
- external_facts = []
65
+ external_facts = @external_fact_loader.external_facts
66
+ block_facts(external_facts, options)
67
+ end
66
68
 
67
- if options[:custom_facts]
68
- @log.debug('Loading custom facts')
69
- external_facts += @external_fact_loader.custom_facts
70
- end
69
+ private
71
70
 
72
- external_facts = block_facts(external_facts, options)
71
+ def filter_env_facts
72
+ env_fact_names = @external_facts.select { |fact| fact.is_env == true }.map(&:name)
73
+ return unless env_fact_names.any?
73
74
 
74
- if options[:external_facts]
75
- @log.debug('Loading external facts')
76
- external_facts += @external_fact_loader.external_facts
75
+ @internal_facts.delete_if do |fact|
76
+ if env_fact_names.include?(fact.name)
77
+ @log.debug("Reading #{fact.name} fact from environment variable")
78
+ true
79
+ else
80
+ false
81
+ end
77
82
  end
78
-
79
- external_facts
80
83
  end
81
84
 
82
85
  def block_facts(facts, options)