infinity_test 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.infinity_test +8 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Rakefile +49 -0
- data/Readme.markdown +92 -0
- data/Tasks +5 -0
- data/VERSION.yml +5 -0
- data/bin/infinity_test +7 -0
- data/buzz_images/buzz_lightyear.jpg +0 -0
- data/buzz_images/buzz_lightyear_continencia.gif +0 -0
- data/buzz_images/to_infinity_and_beyond.png +0 -0
- data/features/infinity_test.feature +36 -0
- data/features/support/env.rb +1 -0
- data/images/faces/failure.png +0 -0
- data/images/faces/pending.png +0 -0
- data/images/faces/sucess.png +0 -0
- data/images/hands/failure.png +0 -0
- data/images/hands/pending.png +0 -0
- data/images/hands/sucess.png +0 -0
- data/images/mario_bros/failure.jpg +0 -0
- data/images/mario_bros/pending.jpg +0 -0
- data/images/mario_bros/sucess.jpg +0 -0
- data/images/rails/failure.png +0 -0
- data/images/rails/pending.png +0 -0
- data/images/rails/sucess.png +0 -0
- data/images/rubies/failure.png +0 -0
- data/images/rubies/pending.png +0 -0
- data/images/rubies/sucess.png +0 -0
- data/images/simpson/failure.gif +0 -0
- data/images/simpson/pending.jpg +0 -0
- data/images/simpson/sucess.jpg +0 -0
- data/images/street_fighter/failure.gif +0 -0
- data/images/street_fighter/pending.gif +0 -0
- data/images/street_fighter/sucess.jpg +0 -0
- data/images/toy_story/failure.gif +0 -0
- data/images/toy_story/pending.png +0 -0
- data/images/toy_story/sucess.png +0 -0
- data/infinity_test.gemspec +168 -0
- data/lib/infinity_test.rb +31 -0
- data/lib/infinity_test/application.rb +168 -0
- data/lib/infinity_test/binary_path.rb +21 -0
- data/lib/infinity_test/command.rb +57 -0
- data/lib/infinity_test/configuration.rb +157 -0
- data/lib/infinity_test/continuous_testing.rb +62 -0
- data/lib/infinity_test/dependencies.rb +45 -0
- data/lib/infinity_test/notifications/growl.rb +15 -0
- data/lib/infinity_test/notifications/lib_notify.rb +11 -0
- data/lib/infinity_test/options.rb +52 -0
- data/lib/infinity_test/rspec.rb +87 -0
- data/lib/infinity_test/runner.rb +30 -0
- data/lib/infinity_test/test_unit.rb +74 -0
- data/lib/infinity_test/test_unit_loader.rb +5 -0
- data/spec/factories/buzz/lib/buzz.rb +0 -0
- data/spec/factories/buzz/spec/buzz_spec.rb +0 -0
- data/spec/factories/company/lib/company.rb +0 -0
- data/spec/factories/company/test/company_test.rb +0 -0
- data/spec/factories/images/failure.png +0 -0
- data/spec/factories/images/pending.png +0 -0
- data/spec/factories/images/sucess.png +0 -0
- data/spec/factories/infinity_test +5 -0
- data/spec/factories/infinity_test_example +7 -0
- data/spec/factories/slinky/spec/slinky/slinky_spec.rb +0 -0
- data/spec/factories/travel/lib/travel.rb +0 -0
- data/spec/factories/travel/test/partner_test.rb +0 -0
- data/spec/factories/travel/test/travel_test.rb +0 -0
- data/spec/factories/wood/lib/wood.rb +0 -0
- data/spec/factories/wood/spec/wood_spec.rb +0 -0
- data/spec/infinity_test/application_spec.rb +149 -0
- data/spec/infinity_test/command_spec.rb +47 -0
- data/spec/infinity_test/configuration_spec.rb +196 -0
- data/spec/infinity_test/continuous_testing_spec.rb +7 -0
- data/spec/infinity_test/notifications/growl_spec.rb +9 -0
- data/spec/infinity_test/notifications/lib_notify_spec.rb +9 -0
- data/spec/infinity_test/options_spec.rb +69 -0
- data/spec/infinity_test/rspec_spec.rb +189 -0
- data/spec/infinity_test/runner_spec.rb +34 -0
- data/spec/infinity_test/test_unit_spec.rb +182 -0
- data/spec/infinity_test_spec.rb +29 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +67 -0
- metadata +226 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
RVM_LIBRARY_DIRECTORY = File.expand_path("~/.rvm/lib")
|
3
|
+
|
4
|
+
#
|
5
|
+
# Try to require the rvm in home folder
|
6
|
+
# If not suceed raise a LoadError
|
7
|
+
# Try to see if the user has the RVM 1.0 or higher for the RVM Ruby API
|
8
|
+
# If not raise a NameError
|
9
|
+
#
|
10
|
+
def require_home_rvm
|
11
|
+
$LOAD_PATH.unshift(RVM_LIBRARY_DIRECTORY) unless $LOAD_PATH.include?(RVM_LIBRARY_DIRECTORY)
|
12
|
+
require 'rvm'
|
13
|
+
RVM::Environment
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: Make require with System Wide Install too
|
17
|
+
#
|
18
|
+
begin
|
19
|
+
require_home_rvm
|
20
|
+
rescue LoadError, NameError
|
21
|
+
puts
|
22
|
+
puts "It appears that you have not installed the RVM in #{RVM_LIBRARY_DIRECTORY} or RVM is very old.\n"
|
23
|
+
puts "The RVM is installed?"
|
24
|
+
puts "If not, please see http://rvm.beginrescueend.com/rvm/install/"
|
25
|
+
puts "If so, try to run:"
|
26
|
+
puts "\t rvm update --head"
|
27
|
+
puts "If the error continues, please create an issue in http://github.com/tomas-stefano/infinity_test"
|
28
|
+
puts 'Thanks :)'
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
def require_without_rubygems(options)
|
33
|
+
gem_name = options[:gem]
|
34
|
+
begin
|
35
|
+
require gem_name
|
36
|
+
rescue LoadError
|
37
|
+
require 'rubygems'
|
38
|
+
require gem_name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
require_without_rubygems :gem => 'watchr'
|
43
|
+
|
44
|
+
require 'ostruct'
|
45
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module InfinityTest
|
2
|
+
module Notifications
|
3
|
+
class Growl
|
4
|
+
|
5
|
+
# Notification via Growl
|
6
|
+
#
|
7
|
+
# Growl.new.notify(:ruby_version => "Ruby 1.9.2", :message => "0 examples, 0 failures", :image => 'image.png')
|
8
|
+
#
|
9
|
+
def notify(options)
|
10
|
+
system "growlnotify -n infinity_test -m '#{options[:message]}' -t 'Ruby #{options[:title]}' --image #{options[:image]} -n infinity_test"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module InfinityTest
|
4
|
+
class Options < Hash
|
5
|
+
|
6
|
+
def initialize(arguments)
|
7
|
+
super()
|
8
|
+
@options = OptionParser.new do |options|
|
9
|
+
parse_rspec(options)
|
10
|
+
parse_test_unit(options)
|
11
|
+
parse_rubies(options)
|
12
|
+
parse_verbose(options)
|
13
|
+
options.banner = [ "Usage: infinity_test [options]", "Starts a continuous test server."].join("\n")
|
14
|
+
options.on_tail("--help", "You're looking at it.") do
|
15
|
+
print options.help
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
@options.parse!(arguments.clone)
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_rspec(options)
|
23
|
+
options.on('--rspec', 'Rspec Framework') do
|
24
|
+
self[:test_framework] = :rspec
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_test_unit(options)
|
29
|
+
options.on('--test-unit', 'Test Unit') do
|
30
|
+
self[:test_framework] = :test_unit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_rubies(options)
|
35
|
+
options.on('--rubies=rubies', 'Specify the Ruby Versions for Testing with several Rubies') do |versions|
|
36
|
+
self[:rubies] = versions
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_verbose(options)
|
41
|
+
options.on('--verbose', 'The Infinity Test dont print the commands. To print the command set this options!') do
|
42
|
+
self[:verbose] = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def rspec?
|
47
|
+
return true if self[:test_framework].equal?(:rspec)
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module InfinityTest
|
2
|
+
class Rspec
|
3
|
+
include BinaryPath
|
4
|
+
attr_accessor :rubies, :test_directory_pattern, :message, :test_pattern,
|
5
|
+
:failure, :sucess, :pending
|
6
|
+
|
7
|
+
#
|
8
|
+
# rspec = InfinityTest::Rspec.new(:rubies => '1.9.1,1.9.2')
|
9
|
+
# rspec.rubies # => '1.9.1,1.9.2'
|
10
|
+
#
|
11
|
+
def initialize(options={})
|
12
|
+
@rubies = options[:rubies] || []
|
13
|
+
@test_directory_pattern = "^spec/*/(.*)_spec.rb"
|
14
|
+
@test_pattern = options[:test_pattern] || 'spec/**/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
def construct_commands(file=nil)
|
18
|
+
@rubies << RVM::Environment.current.environment_name if @rubies.empty?
|
19
|
+
construct_rubies_commands(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def all_files
|
23
|
+
Dir[@test_pattern]
|
24
|
+
end
|
25
|
+
|
26
|
+
def spec_files
|
27
|
+
all_files.collect { |file| file }.join(' ')
|
28
|
+
end
|
29
|
+
|
30
|
+
def construct_rubies_commands(file=nil)
|
31
|
+
results = Hash.new
|
32
|
+
RVM.environments(@rubies) do |environment|
|
33
|
+
ruby_version = environment.environment_name
|
34
|
+
rspec_binary = search_rspec_two(environment)
|
35
|
+
rspec_binary = search_rspec_one(environment) unless File.exist?(rspec_binary)
|
36
|
+
unless have_binary?(rspec_binary)
|
37
|
+
print_message('rspec', ruby_version)
|
38
|
+
else
|
39
|
+
results[ruby_version] = "rvm #{ruby_version} ruby #{rspec_binary} #{decide_files(file)}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
results
|
43
|
+
end
|
44
|
+
|
45
|
+
# TODO: I'm not satisfied yet
|
46
|
+
#
|
47
|
+
def decide_files(file)
|
48
|
+
return file if file
|
49
|
+
spec_files
|
50
|
+
end
|
51
|
+
|
52
|
+
def search_rspec_two(environment)
|
53
|
+
search_binary('rspec', :environment => environment)
|
54
|
+
end
|
55
|
+
|
56
|
+
def search_rspec_one(environment)
|
57
|
+
search_binary('spec', :environment => environment)
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_results(results)
|
61
|
+
shell_result = results.split("\n").last
|
62
|
+
if shell_result =~ /example/
|
63
|
+
@example = shell_result[/(\d+) example/, 1].to_i
|
64
|
+
@failure = shell_result[/(\d+) failure/, 1].to_i
|
65
|
+
@pending = shell_result[/(\d+) pending/, 1].to_i
|
66
|
+
@message = "#{@example} examples, #{@failure} failures, #{@pending} pending"
|
67
|
+
else
|
68
|
+
@example, @pending, @failure = 0, 0, 1
|
69
|
+
@message = "An exception occurred"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def sucess?
|
74
|
+
return false if failure? or pending?
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def failure?
|
79
|
+
@failure > 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def pending?
|
83
|
+
@pending > 0 and not failure?
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module InfinityTest
|
2
|
+
class Runner
|
3
|
+
attr_reader :commands, :options, :application
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
@commands = []
|
8
|
+
@application = InfinityTest.application
|
9
|
+
end
|
10
|
+
|
11
|
+
def run!
|
12
|
+
load_configuration_file_or_read_the_options!
|
13
|
+
start_continuous_testing!
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_configuration_file_or_read_the_options!
|
17
|
+
@application.load_configuration_file
|
18
|
+
@application.config.use(
|
19
|
+
:rubies => (options[:rubies] || @application.rubies),
|
20
|
+
:test_framework => (options[:test_framework] || @application.config.test_framework),
|
21
|
+
:verbose => options[:verbose] || @application.config.verbose
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_continuous_testing!
|
26
|
+
InfinityTest::ContinuousTesting.new(:application => @application).start!
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module InfinityTest
|
2
|
+
class TestUnit
|
3
|
+
attr_reader :rubies, :message, :test_directory_pattern, :tests,
|
4
|
+
:assertions, :failures, :errors
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@rubies = options[:rubies] || []
|
8
|
+
@test_directory_pattern = "^test/*/(.*)_test.rb"
|
9
|
+
@test_pattern = 'test/**/*_test.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
def construct_commands(file=nil)
|
13
|
+
@rubies << RVM::Environment.current.environment_name if @rubies.empty?
|
14
|
+
construct_rubies_commands(file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def construct_rubies_commands(file=nil)
|
18
|
+
results = Hash.new
|
19
|
+
RVM.environments(@rubies) do |environment|
|
20
|
+
ruby_version = environment.environment_name
|
21
|
+
results[ruby_version] = "rvm #{ruby_version} ruby -I'lib:test' #{decide_files(file)}"
|
22
|
+
end
|
23
|
+
results
|
24
|
+
end
|
25
|
+
|
26
|
+
def decide_files(file)
|
27
|
+
return file if file
|
28
|
+
test_files
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_files
|
32
|
+
collect_test_files.unshift(test_loader).join(' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def collect_test_files
|
36
|
+
all_files.collect { |file| file }
|
37
|
+
end
|
38
|
+
|
39
|
+
def all_files
|
40
|
+
Dir[@test_pattern]
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_loader
|
44
|
+
$LOAD_PATH.each do |path|
|
45
|
+
file_path = File.join(path, "infinity_test/test_unit_loader.rb")
|
46
|
+
return file_path if File.exist?(file_path)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_results(results)
|
51
|
+
shell_result = results.split("\n")
|
52
|
+
shell_result = shell_result.select { |line| line =~ /(\d+) tests/}.first
|
53
|
+
if shell_result
|
54
|
+
@tests = shell_result[/(\d+) tests/, 1].to_i
|
55
|
+
@assertions = shell_result[/(\d+) assertions/, 1].to_i
|
56
|
+
@failures = shell_result[/(\d+) failures/, 1].to_i
|
57
|
+
@errors = shell_result[/(\d+) errors/, 1].to_i
|
58
|
+
@message = shell_result
|
59
|
+
else
|
60
|
+
@tests, @assertions, @failures, @errors = 0, 0, 1, 1
|
61
|
+
@message = "An exception ocurred"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def failure?
|
66
|
+
@failures > 0 or @errors > 0
|
67
|
+
end
|
68
|
+
|
69
|
+
def pending?
|
70
|
+
false # Don't have pending in Test::Unit right?? #doubt
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module InfinityTest
|
4
|
+
describe Application do
|
5
|
+
let(:application) { Application.new }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@application = Application.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return test_unit pattern for test unit" do
|
12
|
+
@application.library_directory_pattern.should eql "^lib/*/(.*)\.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return the rubies in the config" do
|
16
|
+
application_with(:rubies => ['1.8.7']).rubies.should == '1.8.7'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return the rubies in the config" do
|
20
|
+
application_with(:rubies => ['1.9.2']).rubies.should == '1.9.2'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return the before callback" do
|
24
|
+
app = application_with(:test_framework => :rspec)
|
25
|
+
proc = Proc.new { 'To Infinity and beyond!' }
|
26
|
+
app.config.before_run(&proc)
|
27
|
+
app.before_callback.should equal proc
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return the block when set after callback" do
|
31
|
+
app = application_with(:test_framework => :rspec)
|
32
|
+
proc = Proc.new { 'To Infinity and beyond!' }
|
33
|
+
app.config.after_run(&proc)
|
34
|
+
app.after_callback.should equal proc
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#image_to_show' do
|
38
|
+
|
39
|
+
before do
|
40
|
+
@application_with_rspec = application_with(:test_framework => :rspec)
|
41
|
+
@application_with_test_unit = application_with(:test_framework => :test_unit)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return sucess when pass all the tests" do
|
45
|
+
test_should_not_fail!(@application_with_rspec)
|
46
|
+
test_should_not_pending!(@application_with_rspec)
|
47
|
+
@application_with_rspec.image_to_show.should match /sucess/
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return failure when not pass all the tests" do
|
51
|
+
test_should_fail!(@application_with_rspec)
|
52
|
+
@application_with_rspec.image_to_show.should match /failure/
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return pending when have pending tests" do
|
56
|
+
test_should_not_fail!(@application_with_rspec)
|
57
|
+
test_should_pending!(@application_with_rspec)
|
58
|
+
@application_with_rspec.image_to_show.should match /pending/
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_should_not_fail!(object)
|
62
|
+
object.test_framework.should_receive(:failure?).and_return(false)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_fail!(object)
|
66
|
+
object.test_framework.should_receive(:failure?).and_return(true)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_should_pending!(object)
|
70
|
+
object.test_framework.should_receive(:pending?).and_return(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_should_not_pending!(object)
|
74
|
+
object.test_framework.should_receive(:pending?).and_return(false)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#notification_framework' do
|
80
|
+
|
81
|
+
it "should return the Growl notification framework if has :growl" do
|
82
|
+
application.config.notifications :growl
|
83
|
+
application.notification_framework.should be_instance_of InfinityTest::Notifications::Growl
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return the Lib Notify if has :lib_notify" do
|
87
|
+
application.config.notifications :lib_notify
|
88
|
+
application.notification_framework.should be_instance_of InfinityTest::Notifications::LibNotify
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should cache notification" do
|
92
|
+
application.config.notifications :lib_notify
|
93
|
+
notification = application.notification_framework
|
94
|
+
application.notification_framework.should equal notification
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#test_framework' do
|
100
|
+
|
101
|
+
before do
|
102
|
+
@application = Application.new
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return the instance of Rspec when test framework is Rspec" do
|
106
|
+
@application.config.use :test_framework => :rspec
|
107
|
+
@application.test_framework.should be_instance_of(InfinityTest::Rspec)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return the instance of Rspec when test framework is Rspec" do
|
111
|
+
@application.config.use :test_framework => :test_unit
|
112
|
+
@application.test_framework.should be_instance_of(InfinityTest::TestUnit)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should pass all the rubies for the test_framework TestUnit" do
|
116
|
+
@application.config.use :test_framework => :test_unit, :rubies => ['1.9.1', '1.9.2']
|
117
|
+
TestUnit.should_receive(:new).with(:rubies => '1.9.1,1.9.2')
|
118
|
+
@application.test_framework
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should pass all the rubies for the test_framework Rspec" do
|
122
|
+
@application.config.use :test_framework => :rspec, :rubies => ['1.9.1', '1.9.2']
|
123
|
+
Rspec.should_receive(:new).with(:rubies => '1.9.1,1.9.2')
|
124
|
+
@application.test_framework
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should cache the test framework instance" do
|
128
|
+
@application.config.use :test_framework => :rspec
|
129
|
+
test_framework = @application.test_framework
|
130
|
+
@application.test_framework.should equal test_framework
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#verbose?' do
|
136
|
+
|
137
|
+
it "should return to false when not set verbose" do
|
138
|
+
@application.verbose?.should equal false
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should return true when set verbose to true" do
|
142
|
+
@application.config.verbose = true
|
143
|
+
@application.verbose?.should be_true
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|