kafo 2.1.0 → 3.0.0
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.
- checksums.yaml +5 -5
- data/README.md +56 -98
- data/Rakefile +12 -1
- data/lib/kafo/color_scheme.rb +3 -3
- data/lib/kafo/configuration.rb +5 -7
- data/lib/kafo/data_types/aliases.rb +0 -10
- data/lib/kafo/data_types/not_undef.rb +2 -0
- data/lib/kafo/data_types/optional.rb +2 -0
- data/lib/kafo/hiera_configurer.rb +50 -22
- data/lib/kafo/hook_context.rb +3 -2
- data/lib/kafo/kafo_configure.rb +9 -8
- data/lib/kafo/logger.rb +2 -2
- data/lib/kafo/param.rb +6 -20
- data/lib/kafo/param_builder.rb +1 -8
- data/lib/kafo/progress_bar.rb +1 -1
- data/lib/kafo/puppet_command.rb +4 -21
- data/lib/kafo/puppet_module.rb +2 -13
- data/lib/kafo/scenario_manager.rb +6 -6
- data/lib/kafo/version.rb +1 -1
- data/modules/kafo_configure/Rakefile +1 -0
- data/modules/kafo_configure/lib/puppet/functions/{dump_lookups.rb → kafo_configure/dump_lookups.rb} +2 -1
- data/modules/kafo_configure/lib/puppet/functions/kafo_configure/dump_variables.rb +13 -0
- data/modules/kafo_configure/lib/puppet/functions/kafo_configure/to_yaml.rb +15 -0
- data/modules/kafo_configure/manifests/dump_values.pp +11 -12
- data/modules/kafo_configure/manifests/init.pp +7 -5
- data/modules/kafo_configure/manifests/puppet_version_semver.pp +1 -1
- data/modules/kafo_configure/metadata.json +15 -0
- data/modules/kafo_configure/spec/classes/dump_values_spec.rb +24 -0
- data/modules/kafo_configure/spec/classes/init_spec.rb +17 -0
- data/modules/kafo_configure/spec/fixtures/hiera/hiera.yaml +7 -0
- data/modules/kafo_configure/spec/fixtures/hiera/test.yaml +4 -0
- data/modules/kafo_configure/spec/fixtures/modules/dummy/manifests/init.pp +5 -0
- data/modules/kafo_configure/spec/fixtures/modules/dummy/manifests/params.pp +3 -0
- data/modules/kafo_configure/spec/functions/dump_lookups_spec.rb +7 -0
- data/modules/kafo_configure/spec/functions/dump_variables_spec.rb +10 -0
- data/modules/kafo_configure/spec/functions/to_yaml_spec.rb +5 -0
- data/modules/kafo_configure/spec/spec_helper.rb +5 -0
- metadata +48 -35
- data/lib/kafo/params/password.rb +0 -60
- data/lib/kafo/validator.rb +0 -122
- data/modules/kafo_configure/lib/puppet/parser/functions/decrypt.rb +0 -16
- data/modules/kafo_configure/lib/puppet/parser/functions/dump_values.rb +0 -13
- data/modules/kafo_configure/lib/puppet/parser/functions/foreman_to_yaml.rb +0 -13
- data/modules/kafo_configure/lib/puppet/parser/functions/load_kafo_password.rb +0 -13
- data/modules/kafo_configure/manifests/puppet_version_versioncmp.pp +0 -9
data/lib/kafo/hook_context.rb
CHANGED
@@ -34,7 +34,7 @@ module Kafo
|
|
34
34
|
# app_option '--log-level', 'LEVEL', 'Log level for log file output', :default => config.app[:log_level]:
|
35
35
|
# app_option ['-n', '--noop'], :flag, 'Run puppet in noop mode?', :default => false
|
36
36
|
def app_option(*args)
|
37
|
-
self.kafo.class.app_option
|
37
|
+
self.kafo.class.app_option(*args)
|
38
38
|
end
|
39
39
|
|
40
40
|
# examples:
|
@@ -68,7 +68,8 @@ module Kafo
|
|
68
68
|
# examples:
|
69
69
|
# module_enabled?('example')
|
70
70
|
def module_enabled?(module_name)
|
71
|
-
self.kafo.module(module_name)
|
71
|
+
mod = self.kafo.module(module_name)
|
72
|
+
!mod.nil? && mod.enabled?
|
72
73
|
end
|
73
74
|
|
74
75
|
# You can trigger installer exit by this method. You must specify exit code as a first
|
data/lib/kafo/kafo_configure.rb
CHANGED
@@ -161,7 +161,7 @@ module Kafo
|
|
161
161
|
|
162
162
|
def self.run
|
163
163
|
return super
|
164
|
-
rescue SystemExit
|
164
|
+
rescue SystemExit
|
165
165
|
self.exit_handler.exit(self.exit_code) # fail in initialize
|
166
166
|
end
|
167
167
|
|
@@ -429,12 +429,13 @@ module Kafo
|
|
429
429
|
self.class.exit_handler.register_cleanup_path(hiera.temp_dir)
|
430
430
|
|
431
431
|
puppetconf = PuppetConfigurer.new(
|
432
|
-
'color'
|
433
|
-
'evaltrace'
|
434
|
-
'hiera_config'
|
435
|
-
'noop'
|
436
|
-
'profile'
|
437
|
-
'show_diff'
|
432
|
+
'color' => false,
|
433
|
+
'evaltrace' => !!@progress_bar,
|
434
|
+
'hiera_config' => hiera.config_path,
|
435
|
+
'noop' => !!noop?,
|
436
|
+
'profile' => !!profile?,
|
437
|
+
'show_diff' => true,
|
438
|
+
'environmentpath' => hiera.temp_dir,
|
438
439
|
)
|
439
440
|
self.class.exit_handler.register_cleanup_path(puppetconf.config_path)
|
440
441
|
|
@@ -505,7 +506,7 @@ module Kafo
|
|
505
506
|
end
|
506
507
|
|
507
508
|
def self.preset_color_scheme
|
508
|
-
match = ARGV.join(' ').match
|
509
|
+
match = ARGV.join(' ').match(/--color-of-background[ =](\w+)/)
|
509
510
|
background = match && match[1]
|
510
511
|
ColorScheme.new(:background => background, :colors => use_colors?).setup
|
511
512
|
end
|
data/lib/kafo/logger.rb
CHANGED
@@ -47,7 +47,7 @@ module Kafo
|
|
47
47
|
def self.setup
|
48
48
|
begin
|
49
49
|
FileUtils.mkdir_p(KafoConfigure.config.app[:log_dir], :mode => 0750)
|
50
|
-
rescue Errno::EACCES
|
50
|
+
rescue Errno::EACCES
|
51
51
|
puts "No permissions to create log dir #{KafoConfigure.config.app[:log_dir]}"
|
52
52
|
end
|
53
53
|
|
@@ -61,7 +61,7 @@ module Kafo
|
|
61
61
|
)
|
62
62
|
# set owner and group (it's ignored if attribute is nil)
|
63
63
|
FileUtils.chown KafoConfigure.config.app[:log_owner], KafoConfigure.config.app[:log_group], filename
|
64
|
-
rescue ArgumentError
|
64
|
+
rescue ArgumentError
|
65
65
|
puts "File #{filename} not writeable, won't log anything to file!"
|
66
66
|
end
|
67
67
|
|
data/lib/kafo/param.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
require 'kafo/condition'
|
3
3
|
require 'kafo/data_type'
|
4
|
-
require 'kafo/validator'
|
5
4
|
|
6
5
|
module Kafo
|
7
6
|
class Param
|
@@ -15,6 +14,10 @@ module Kafo
|
|
15
14
|
@name = name
|
16
15
|
@module = builder
|
17
16
|
@type = DataType.new_from_string(type)
|
17
|
+
@default = nil
|
18
|
+
@value_set = false
|
19
|
+
@groups = nil
|
20
|
+
@validation_errors = []
|
18
21
|
end
|
19
22
|
|
20
23
|
def identifier
|
@@ -104,22 +107,7 @@ module Kafo
|
|
104
107
|
end
|
105
108
|
|
106
109
|
def valid?
|
107
|
-
|
108
|
-
# also we want to clone validations so we don't interfere
|
109
|
-
validations = self.module.validations(self).map do |v|
|
110
|
-
# These functions do not take more variables as arguments, instead we need to pass all arguments
|
111
|
-
if v.name == 'validate_re' || v.name == 'validate_integer'
|
112
|
-
args = v.arguments.to_a
|
113
|
-
else
|
114
|
-
args = v.arguments.select { |a| a.to_s == "$#{self.name}" }
|
115
|
-
end
|
116
|
-
{:name => v.name, :arguments => interpret_validation_args(args)}
|
117
|
-
end
|
118
|
-
|
119
|
-
# run old style validation functions
|
120
|
-
@validator = Validator.new
|
121
|
-
validations.each { |v| @validator.send(v[:name], v[:arguments]) }
|
122
|
-
@validation_errors = @validator.errors.dup
|
110
|
+
@validation_errors = []
|
123
111
|
|
124
112
|
# run data type based validations, append errors
|
125
113
|
@type.valid?(value, @validation_errors)
|
@@ -128,7 +116,7 @@ module Kafo
|
|
128
116
|
end
|
129
117
|
|
130
118
|
def validation_errors
|
131
|
-
@validation_errors
|
119
|
+
@validation_errors
|
132
120
|
end
|
133
121
|
|
134
122
|
def multivalued?
|
@@ -189,5 +177,3 @@ module Kafo
|
|
189
177
|
end
|
190
178
|
end
|
191
179
|
end
|
192
|
-
|
193
|
-
require 'kafo/params/password'
|
data/lib/kafo/param_builder.rb
CHANGED
@@ -52,14 +52,7 @@ module Kafo
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def build(name, data)
|
55
|
-
|
56
|
-
if data_type == 'password'
|
57
|
-
type = Params::Password
|
58
|
-
data_type = 'String'
|
59
|
-
else
|
60
|
-
type = Param
|
61
|
-
end
|
62
|
-
param = type.new(@module, name, data_type)
|
55
|
+
param = Param.new(@module, name, data[:types][name] || 'Data')
|
63
56
|
param.manifest_default = data[:values][name]
|
64
57
|
param.doc = data[:docs][name]
|
65
58
|
param.groups = data[:groups][name]
|
data/lib/kafo/progress_bar.rb
CHANGED
@@ -49,7 +49,7 @@ module Kafo
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
if (line_end = EVALTRACE_END.match(line)) && @lines < @total
|
52
|
+
if (line_end = EVALTRACE_END.match(line)) && @total != :unknown && @lines < @total
|
53
53
|
if (known_resource = find_known_resource(line_end[1]))
|
54
54
|
@resources.delete(known_resource) # ensure it's only counted once
|
55
55
|
@lines += 1
|
data/lib/kafo/puppet_command.rb
CHANGED
@@ -10,6 +10,7 @@ module Kafo
|
|
10
10
|
@options.push("--config=#{puppet_config.config_path}") if puppet_config
|
11
11
|
@logger = KafoConfigure.logger
|
12
12
|
@puppet_version_check = !configuration.app[:skip_puppet_version_check]
|
13
|
+
@suffix = nil
|
13
14
|
end
|
14
15
|
|
15
16
|
def command
|
@@ -48,7 +49,7 @@ module Kafo
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def add_progress
|
51
|
-
%{$kafo_add_progress
|
52
|
+
%{$kafo_add_progress=#{!KafoConfigure.verbose}}
|
52
53
|
end
|
53
54
|
|
54
55
|
def generate_version_checks
|
@@ -67,27 +68,9 @@ module Kafo
|
|
67
68
|
end
|
68
69
|
|
69
70
|
def versioncmp(id, version_req)
|
70
|
-
# Parse the common ">= x.y < x.y" version requirement to support pre-Puppet 4.5
|
71
|
-
# checks with versioncmp. Newer versions use SemVerRange for full support.
|
72
|
-
if (version_match = /\A>=\s*([0-9\.]+)(?:\s+<\s*([0-9\.]+))?/.match(version_req))
|
73
|
-
minimum = %{minimum => "#{version_match[1]}",}
|
74
|
-
maximum = version_match[2] ? %{maximum => "#{version_match[2]}",} : ''
|
75
|
-
else
|
76
|
-
minimum = ''
|
77
|
-
maximum = ''
|
78
|
-
end
|
79
|
-
|
80
|
-
# SemVerRange is isolated inside a defined type to prevent parse errors on old versions
|
81
71
|
<<-EOS
|
82
|
-
|
83
|
-
|
84
|
-
requirement => "#{version_req}",
|
85
|
-
}
|
86
|
-
} else {
|
87
|
-
kafo_configure::puppet_version_versioncmp { "#{id}":
|
88
|
-
#{minimum}
|
89
|
-
#{maximum}
|
90
|
-
}
|
72
|
+
kafo_configure::puppet_version_semver { "#{id}":
|
73
|
+
requirement => "#{version_req}",
|
91
74
|
}
|
92
75
|
EOS
|
93
76
|
end
|
data/lib/kafo/puppet_module.rb
CHANGED
@@ -3,7 +3,6 @@ require 'kafo/param'
|
|
3
3
|
require 'kafo/param_builder'
|
4
4
|
require 'kafo/parser_cache_reader'
|
5
5
|
require 'kafo_parsers/parsers'
|
6
|
-
require 'kafo/validator'
|
7
6
|
|
8
7
|
module Kafo
|
9
8
|
class PuppetModule
|
@@ -43,11 +42,12 @@ module Kafo
|
|
43
42
|
@manifest_path = File.join(module_dir, module_manifest_path)
|
44
43
|
@parser = parser
|
45
44
|
@parser_cache = @configuration.parser_cache
|
46
|
-
@validations = []
|
47
45
|
@logger = KafoConfigure.logger
|
48
46
|
@groups = {}
|
49
47
|
@params_path = get_params_path
|
50
48
|
@params_class_name = get_params_class_name
|
49
|
+
@raw_data = nil
|
50
|
+
@enabled = nil
|
51
51
|
end
|
52
52
|
|
53
53
|
def enabled?
|
@@ -73,7 +73,6 @@ module Kafo
|
|
73
73
|
end
|
74
74
|
|
75
75
|
builder = builder_klass.new(self, @raw_data)
|
76
|
-
@validations = @raw_data[:validations]
|
77
76
|
|
78
77
|
builder.validate
|
79
78
|
@params = builder.build_params
|
@@ -93,16 +92,6 @@ module Kafo
|
|
93
92
|
@groups.select { |g| g.formatted_name != PRIMARY_GROUP_NAME }
|
94
93
|
end
|
95
94
|
|
96
|
-
def validations(param = nil)
|
97
|
-
if param.nil?
|
98
|
-
@validations
|
99
|
-
else
|
100
|
-
@validations.select do |validation|
|
101
|
-
validation.arguments.map(&:to_s).include?("$#{param.name}")
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
95
|
def params_hash
|
107
96
|
Hash[params.map { |param| [param.name, param.value] }]
|
108
97
|
end
|
@@ -9,7 +9,7 @@ module Kafo
|
|
9
9
|
def initialize(config, last_scenario_link_name='last_scenario.yaml')
|
10
10
|
@config_dir = File.file?(config) ? File.dirname(config) : config
|
11
11
|
@last_scenario_link = File.join(config_dir, last_scenario_link_name)
|
12
|
-
@previous_scenario = Pathname.new(last_scenario_link).realpath.to_s
|
12
|
+
@previous_scenario = File.exist?(last_scenario_link) ? Pathname.new(last_scenario_link).realpath.to_s : nil
|
13
13
|
end
|
14
14
|
|
15
15
|
def available_scenarios
|
@@ -78,10 +78,10 @@ module Kafo
|
|
78
78
|
|
79
79
|
def scenario_from_args(arg_name='--scenario|-S')
|
80
80
|
# try scenario provided in the args via -S or --scenario
|
81
|
-
parsed = ARGV.join(" ").match
|
81
|
+
parsed = ARGV.join(" ").match(/(#{arg_name})(\s+|[=]?)(\S+)/)
|
82
82
|
if parsed
|
83
83
|
scenario_file = File.join(config_dir, "#{parsed[3]}.yaml")
|
84
|
-
return scenario_file if File.
|
84
|
+
return scenario_file if File.exist?(scenario_file)
|
85
85
|
fail_now("Scenario (#{scenario_file}) was not found, can not continue", :unset_scenario)
|
86
86
|
end
|
87
87
|
end
|
@@ -197,9 +197,9 @@ module Kafo
|
|
197
197
|
|
198
198
|
def link_last_scenario(config_file)
|
199
199
|
link_path = last_scenario_link
|
200
|
-
if
|
201
|
-
File.delete(
|
202
|
-
File.symlink(File.basename(config_file),
|
200
|
+
if link_path
|
201
|
+
File.delete(link_path) if File.symlink?(link_path)
|
202
|
+
File.symlink(File.basename(config_file), link_path)
|
203
203
|
end
|
204
204
|
end
|
205
205
|
|
data/lib/kafo/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
require 'puppetlabs_spec_helper/rake_tasks'
|
data/modules/kafo_configure/lib/puppet/functions/{dump_lookups.rb → kafo_configure/dump_lookups.rb}
RENAMED
@@ -3,9 +3,10 @@
|
|
3
3
|
# Wraps the lookup() function for data lookups of class parameters without
|
4
4
|
# inline defaults.
|
5
5
|
#
|
6
|
-
Puppet::Functions.create_function(:dump_lookups) do
|
6
|
+
Puppet::Functions.create_function(:'kafo_configure::dump_lookups') do
|
7
7
|
dispatch :dump_lookups do
|
8
8
|
param 'Array[String]', :parameters
|
9
|
+
return_type 'Hash[String, Any]'
|
9
10
|
end
|
10
11
|
|
11
12
|
def dump_lookups(parameters)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Find default values for variables specified as args
|
2
|
+
#
|
3
|
+
Puppet::Functions.create_function(:'kafo_configure::dump_variables') do
|
4
|
+
dispatch :dump_variables do
|
5
|
+
param 'Array[String]', :variables
|
6
|
+
return_type 'Hash[String, Any]'
|
7
|
+
end
|
8
|
+
|
9
|
+
def dump_variables(variables)
|
10
|
+
scope = closure_scope
|
11
|
+
Hash[variables.map { |var| [var, scope[var]] }]
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Returns the given argument as a string containing YAML, with an end of
|
2
|
+
# document marker.
|
3
|
+
#
|
4
|
+
Puppet::Functions.create_function(:'kafo_configure::to_yaml') do
|
5
|
+
dispatch :to_yaml do
|
6
|
+
param 'Hash', :variables
|
7
|
+
param 'Hash', :lookups
|
8
|
+
return_type 'String'
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_yaml(variables, lookups)
|
12
|
+
dump = variables.merge(lookups)
|
13
|
+
YAML.dump(dump) + "\n...\n"
|
14
|
+
end
|
15
|
+
end
|
@@ -4,18 +4,17 @@
|
|
4
4
|
# - lookups: a list of variables to find through lookup()
|
5
5
|
#
|
6
6
|
# The result will be merged together into one hash.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}
|
7
|
+
#
|
8
|
+
# @param variables a list of variables from params classes that have
|
9
|
+
# already been included
|
10
|
+
# @param lookups a list of variables to find through lookup()
|
11
|
+
class kafo_configure::dump_values(
|
12
|
+
Array[String] $variables = [],
|
13
|
+
Array[String] $lookups = [],
|
14
|
+
) {
|
15
|
+
$dumped_vars = kafo_configure::dump_variables($variables)
|
16
|
+
$dumped_lookups = kafo_configure::dump_lookups($lookups)
|
17
|
+
$dumped = kafo_configure::to_yaml($dumped_vars, $dumped_lookups)
|
19
18
|
|
20
19
|
notice("\n${dumped}")
|
21
20
|
}
|
@@ -4,12 +4,14 @@
|
|
4
4
|
# $modulepath/config/answers.yaml
|
5
5
|
# /etc/kafo-configure/answers.yaml
|
6
6
|
#
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# @param add_progress
|
8
|
+
# Whether to add a progress bar. Only works on Puppet < 6.
|
9
|
+
class kafo_configure(
|
10
|
+
Boolean $add_progress = $::kafo_add_progress,
|
11
|
+
) {
|
12
|
+
if $add_progress and SemVer($facts['puppetversion']) =~ SemVerRange('< 6.0.0') {
|
10
13
|
add_progress()
|
11
14
|
}
|
12
15
|
|
13
|
-
|
14
|
-
hiera_include('classes')
|
16
|
+
lookup('classes', {merge => unique}).include
|
15
17
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
define kafo_configure::puppet_version_semver($requirement) {
|
2
2
|
unless SemVer($facts['puppetversion']) =~ SemVerRange($requirement) {
|
3
|
-
fail("kafo_configure::puppet_version_failure: Puppet ${facts['puppetversion']} does not meet requirements for ${title} ($requirement)")
|
3
|
+
fail("kafo_configure::puppet_version_failure: Puppet ${facts['puppetversion']} does not meet requirements for ${title} (${requirement})")
|
4
4
|
}
|
5
5
|
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"name": "theforeman-kafo_configure",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"author": "theforeman",
|
5
|
+
"license": "GPL-3.0+",
|
6
|
+
"summary": "An internal module to kafo",
|
7
|
+
"source": "https://github.com/theforeman/kafo",
|
8
|
+
"dependencies": [],
|
9
|
+
"requirements": [
|
10
|
+
{
|
11
|
+
"name": "puppet",
|
12
|
+
"version_requirement": ">= 4.5.0 < 7.0.0"
|
13
|
+
}
|
14
|
+
]
|
15
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'kafo_configure::dump_values' do
|
4
|
+
context 'without parameters' do
|
5
|
+
let(:params) do
|
6
|
+
{
|
7
|
+
variables: [],
|
8
|
+
lookups: [],
|
9
|
+
}
|
10
|
+
end
|
11
|
+
it { is_expected.to compile.with_all_deps }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with values' do
|
15
|
+
let(:hiera_config) { 'spec/fixtures/hiera/hiera.yaml' }
|
16
|
+
let(:params) do
|
17
|
+
{
|
18
|
+
variables: ['dummy:first', 'dummy::second'],
|
19
|
+
lookups: ['my_module::param'],
|
20
|
+
}
|
21
|
+
end
|
22
|
+
it { is_expected.to compile.with_all_deps }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'kafo_configure' do
|
4
|
+
let(:hiera_config) { 'spec/fixtures/hiera/hiera.yaml' }
|
5
|
+
let(:facts) { { puppetversion: Puppet.version } }
|
6
|
+
|
7
|
+
context 'without parameters' do
|
8
|
+
let(:params) { {add_progress: false} }
|
9
|
+
it { is_expected.to compile.with_all_deps }
|
10
|
+
it { is_expected.to contain_class('dummy') }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with progress' do
|
14
|
+
let(:params) { {add_progress: true} }
|
15
|
+
it { is_expected.to compile.with_all_deps }
|
16
|
+
end
|
17
|
+
end
|