pry 0.6.7-i386-mswin32
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.
- data/.gemtest +0 -0
- data/CHANGELOG +83 -0
- data/LICENSE +25 -0
- data/README.markdown +312 -0
- data/Rakefile +103 -0
- data/bin/pry +82 -0
- data/examples/example_basic.rb +17 -0
- data/examples/example_command_override.rb +35 -0
- data/examples/example_commands.rb +39 -0
- data/examples/example_hooks.rb +12 -0
- data/examples/example_image_edit.rb +71 -0
- data/examples/example_input.rb +10 -0
- data/examples/example_input2.rb +32 -0
- data/examples/example_output.rb +14 -0
- data/examples/example_print.rb +9 -0
- data/examples/example_prompt.rb +12 -0
- data/lib/pry.rb +32 -0
- data/lib/pry/command_base.rb +150 -0
- data/lib/pry/commands.rb +577 -0
- data/lib/pry/completion.rb +202 -0
- data/lib/pry/core_extensions.rb +55 -0
- data/lib/pry/hooks.rb +8 -0
- data/lib/pry/print.rb +19 -0
- data/lib/pry/prompts.rb +26 -0
- data/lib/pry/pry_class.rb +186 -0
- data/lib/pry/pry_instance.rb +316 -0
- data/lib/pry/version.rb +3 -0
- data/test/test.rb +681 -0
- data/test/test_helper.rb +38 -0
- metadata +131 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
# taken from irb
|
2
|
+
|
3
|
+
require "readline"
|
4
|
+
|
5
|
+
class Pry
|
6
|
+
|
7
|
+
# Implements tab completion for Readline in Pry
|
8
|
+
module InputCompleter
|
9
|
+
|
10
|
+
if Readline.respond_to?("basic_word_break_characters=")
|
11
|
+
Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{("
|
12
|
+
end
|
13
|
+
|
14
|
+
Readline.completion_append_character = nil
|
15
|
+
|
16
|
+
ReservedWords = [
|
17
|
+
"BEGIN", "END",
|
18
|
+
"alias", "and",
|
19
|
+
"begin", "break",
|
20
|
+
"case", "class",
|
21
|
+
"def", "defined", "do",
|
22
|
+
"else", "elsif", "end", "ensure",
|
23
|
+
"false", "for",
|
24
|
+
"if", "in",
|
25
|
+
"module",
|
26
|
+
"next", "nil", "not",
|
27
|
+
"or",
|
28
|
+
"redo", "rescue", "retry", "return",
|
29
|
+
"self", "super",
|
30
|
+
"then", "true",
|
31
|
+
"undef", "unless", "until",
|
32
|
+
"when", "while",
|
33
|
+
"yield",
|
34
|
+
]
|
35
|
+
|
36
|
+
Operators = ["%", "&", "*", "**", "+", "-", "/",
|
37
|
+
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
38
|
+
"[]", "[]=", "^", "!", "!=", "!~"]
|
39
|
+
|
40
|
+
# Return a new completion proc for use by Readline.
|
41
|
+
# @param [Binding] target The current binding context.
|
42
|
+
# @param [Array<String>] commands The array of Pry commands.
|
43
|
+
def self.build_completion_proc(target, commands=[""])
|
44
|
+
proc do |input|
|
45
|
+
bind = target
|
46
|
+
|
47
|
+
case input
|
48
|
+
when /^(\/[^\/]*\/)\.([^.]*)$/
|
49
|
+
# Regexp
|
50
|
+
receiver = $1
|
51
|
+
message = Regexp.quote($2)
|
52
|
+
|
53
|
+
candidates = Regexp.instance_methods.collect{|m| m.to_s}
|
54
|
+
select_message(receiver, message, candidates)
|
55
|
+
|
56
|
+
when /^([^\]]*\])\.([^.]*)$/
|
57
|
+
# Array
|
58
|
+
receiver = $1
|
59
|
+
message = Regexp.quote($2)
|
60
|
+
|
61
|
+
candidates = Array.instance_methods.collect{|m| m.to_s}
|
62
|
+
select_message(receiver, message, candidates)
|
63
|
+
|
64
|
+
when /^([^\}]*\})\.([^.]*)$/
|
65
|
+
# Proc or Hash
|
66
|
+
receiver = $1
|
67
|
+
message = Regexp.quote($2)
|
68
|
+
|
69
|
+
candidates = Proc.instance_methods.collect{|m| m.to_s}
|
70
|
+
candidates |= Hash.instance_methods.collect{|m| m.to_s}
|
71
|
+
select_message(receiver, message, candidates)
|
72
|
+
|
73
|
+
when /^(:[^:.]*)$/
|
74
|
+
# Symbol
|
75
|
+
if Symbol.respond_to?(:all_symbols)
|
76
|
+
sym = $1
|
77
|
+
candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
|
78
|
+
candidates.grep(/^#{sym}/)
|
79
|
+
else
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
|
83
|
+
when /^::([A-Z][^:\.\(]*)$/
|
84
|
+
# Absolute Constant or class methods
|
85
|
+
receiver = $1
|
86
|
+
candidates = Object.constants.collect{|m| m.to_s}
|
87
|
+
candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
|
88
|
+
|
89
|
+
when /^([A-Z].*)::([^:.]*)$/
|
90
|
+
# Constant or class methods
|
91
|
+
receiver = $1
|
92
|
+
message = Regexp.quote($2)
|
93
|
+
begin
|
94
|
+
candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
|
95
|
+
candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
|
96
|
+
rescue Exception
|
97
|
+
candidates = []
|
98
|
+
end
|
99
|
+
candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
|
100
|
+
|
101
|
+
when /^(:[^:.]+)\.([^.]*)$/
|
102
|
+
# Symbol
|
103
|
+
receiver = $1
|
104
|
+
message = Regexp.quote($2)
|
105
|
+
|
106
|
+
candidates = Symbol.instance_methods.collect{|m| m.to_s}
|
107
|
+
select_message(receiver, message, candidates)
|
108
|
+
|
109
|
+
when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
|
110
|
+
# Numeric
|
111
|
+
receiver = $1
|
112
|
+
message = Regexp.quote($5)
|
113
|
+
|
114
|
+
begin
|
115
|
+
candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
|
116
|
+
rescue Exception
|
117
|
+
candidates = []
|
118
|
+
end
|
119
|
+
select_message(receiver, message, candidates)
|
120
|
+
|
121
|
+
when /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
|
122
|
+
# Numeric(0xFFFF)
|
123
|
+
receiver = $1
|
124
|
+
message = Regexp.quote($2)
|
125
|
+
|
126
|
+
begin
|
127
|
+
candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
|
128
|
+
rescue Exception
|
129
|
+
candidates = []
|
130
|
+
end
|
131
|
+
select_message(receiver, message, candidates)
|
132
|
+
|
133
|
+
when /^(\$[^.]*)$/
|
134
|
+
regmessage = Regexp.new(Regexp.quote($1))
|
135
|
+
candidates = global_variables.collect{|m| m.to_s}.grep(regmessage)
|
136
|
+
|
137
|
+
when /^([^."].*)\.([^.]*)$/
|
138
|
+
# variable
|
139
|
+
receiver = $1
|
140
|
+
message = Regexp.quote($2)
|
141
|
+
|
142
|
+
gv = eval("global_variables", bind).collect{|m| m.to_s}
|
143
|
+
lv = eval("local_variables", bind).collect{|m| m.to_s}
|
144
|
+
cv = eval("self.class.constants", bind).collect{|m| m.to_s}
|
145
|
+
|
146
|
+
if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
|
147
|
+
# foo.func and foo is local var. OR
|
148
|
+
# Foo::Bar.func
|
149
|
+
begin
|
150
|
+
candidates = eval("#{receiver}.methods", bind).collect{|m| m.to_s}
|
151
|
+
rescue Exception
|
152
|
+
candidates = []
|
153
|
+
end
|
154
|
+
else
|
155
|
+
# func1.func2
|
156
|
+
candidates = []
|
157
|
+
ObjectSpace.each_object(Module){|m|
|
158
|
+
begin
|
159
|
+
name = m.name
|
160
|
+
rescue Exception
|
161
|
+
name = ""
|
162
|
+
end
|
163
|
+
next if name != "IRB::Context" and
|
164
|
+
/^(IRB|SLex|RubyLex|RubyToken)/ =~ name
|
165
|
+
candidates.concat m.instance_methods(false).collect{|x| x.to_s}
|
166
|
+
}
|
167
|
+
candidates.sort!
|
168
|
+
candidates.uniq!
|
169
|
+
end
|
170
|
+
select_message(receiver, message, candidates)
|
171
|
+
|
172
|
+
when /^\.([^.]*)$/
|
173
|
+
# unknown(maybe String)
|
174
|
+
|
175
|
+
receiver = ""
|
176
|
+
message = Regexp.quote($1)
|
177
|
+
|
178
|
+
candidates = String.instance_methods(true).collect{|m| m.to_s}
|
179
|
+
select_message(receiver, message, candidates)
|
180
|
+
|
181
|
+
else
|
182
|
+
candidates = eval("methods | private_methods | local_variables | self.class.constants", bind).collect{|m| m.to_s}
|
183
|
+
|
184
|
+
(candidates|ReservedWords|commands).grep(/^#{Regexp.quote(input)}/)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.select_message(receiver, message, candidates)
|
190
|
+
candidates.grep(/^#{message}/).collect do |e|
|
191
|
+
case e
|
192
|
+
when /^[a-zA-Z_]/
|
193
|
+
receiver + "." + e
|
194
|
+
when /^[0-9]/
|
195
|
+
when *Operators
|
196
|
+
#receiver + " " + e
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Pry
|
2
|
+
module ObjectExtensions
|
3
|
+
|
4
|
+
# Start a Pry REPL.
|
5
|
+
# This method differs from `Pry.start` in that it does not
|
6
|
+
# support an options hash. Also, when no parameter is provided, the Pry
|
7
|
+
# session will start on the implied receiver rather than on
|
8
|
+
# top-level (as in the case of `Pry.start`).
|
9
|
+
# It has two forms of invocation. In the first form no parameter
|
10
|
+
# should be provided and it will start a pry session on the
|
11
|
+
# receiver. In the second form it should be invoked without an
|
12
|
+
# explicit receiver and one parameter; this will start a Pry
|
13
|
+
# session on the parameter.
|
14
|
+
# @param [Object, Binding] target The receiver of the Pry session.
|
15
|
+
# @example First form
|
16
|
+
# "dummy".pry
|
17
|
+
# @example Second form
|
18
|
+
# pry "dummy"
|
19
|
+
# @example Start a Pry session on current self (whatever that is)
|
20
|
+
# pry
|
21
|
+
def pry(target=self)
|
22
|
+
Pry.start(target)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return a binding object for the receiver.
|
26
|
+
def __binding__
|
27
|
+
if is_a?(Module)
|
28
|
+
return class_eval "binding"
|
29
|
+
end
|
30
|
+
|
31
|
+
unless respond_to? :__binding_impl__
|
32
|
+
begin
|
33
|
+
instance_eval %{
|
34
|
+
def __binding_impl__
|
35
|
+
binding
|
36
|
+
end
|
37
|
+
}
|
38
|
+
rescue TypeError
|
39
|
+
self.class.class_eval %{
|
40
|
+
def __binding_impl__
|
41
|
+
binding
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
__binding_impl__
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# bring the extensions into Object
|
53
|
+
class Object
|
54
|
+
include Pry::ObjectExtensions
|
55
|
+
end
|
data/lib/pry/hooks.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# The default hooks - display messages when beginning and ending Pry sessions.
|
4
|
+
DEFAULT_HOOKS = {
|
5
|
+
:before_session => proc { |out, obj| out.puts "Beginning Pry session for #{Pry.view_clip(obj)}" },
|
6
|
+
:after_session => proc { |out, obj| out.puts "Ending Pry session for #{Pry.view_clip(obj)}" }
|
7
|
+
}
|
8
|
+
end
|
data/lib/pry/print.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
# The default print object - only show first line of backtrace and
|
4
|
+
# prepend output with `=>`
|
5
|
+
DEFAULT_PRINT = proc do |output, value|
|
6
|
+
case value
|
7
|
+
when Exception
|
8
|
+
output.puts "#{value.class}: #{value.message}"
|
9
|
+
output.puts "from #{value.backtrace.first}"
|
10
|
+
else
|
11
|
+
if Pry.color
|
12
|
+
output.puts "=> #{CodeRay.scan(Pry.view(value), :ruby).term}"
|
13
|
+
else
|
14
|
+
output.puts "=> #{Pry.view(value)}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/lib/pry/prompts.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Pry
|
2
|
+
|
3
|
+
|
4
|
+
# The default prompt; includes the target and nesting level
|
5
|
+
DEFAULT_PROMPT = [
|
6
|
+
proc do |target_self, nest_level|
|
7
|
+
|
8
|
+
if nest_level == 0
|
9
|
+
"pry(#{Pry.view_clip(target_self)})> "
|
10
|
+
else
|
11
|
+
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}> "
|
12
|
+
end
|
13
|
+
end,
|
14
|
+
|
15
|
+
proc do |target_self, nest_level|
|
16
|
+
if nest_level == 0
|
17
|
+
"pry(#{Pry.view_clip(target_self)})* "
|
18
|
+
else
|
19
|
+
"pry(#{Pry.view_clip(target_self)}):#{Pry.view_clip(nest_level)}* "
|
20
|
+
end
|
21
|
+
end
|
22
|
+
]
|
23
|
+
|
24
|
+
# A simple prompt - doesn't display target or nesting level
|
25
|
+
SIMPLE_PROMPT = [proc { ">> " }, proc { ">* " }]
|
26
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# @author John Mair (banisterfiend)
|
2
|
+
class Pry
|
3
|
+
|
4
|
+
# class accessors
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Get nesting data.
|
8
|
+
# This method should not need to be accessed directly.
|
9
|
+
# @return [Array] The unparsed nesting information.
|
10
|
+
attr_reader :nesting
|
11
|
+
|
12
|
+
# Get last value evaluated by Pry.
|
13
|
+
# This method should not need to be accessed directly.
|
14
|
+
# @return [Object] The last result.
|
15
|
+
attr_accessor :last_result
|
16
|
+
|
17
|
+
# Get the active Pry instance that manages the active Pry session.
|
18
|
+
# This method should not need to be accessed directly.
|
19
|
+
# @return [Pry] The active Pry instance.
|
20
|
+
attr_accessor :active_instance
|
21
|
+
|
22
|
+
# Get/Set the object to use for input by default by all Pry instances.
|
23
|
+
# @return [#readline] The object to use for input by default by all
|
24
|
+
# Pry instances.
|
25
|
+
attr_accessor :input
|
26
|
+
|
27
|
+
# Get/Set the object to use for output by default by all Pry instances.
|
28
|
+
# @return [#puts] The object to use for output by default by all
|
29
|
+
# Pry instances.
|
30
|
+
attr_accessor :output
|
31
|
+
|
32
|
+
# Get/Set the object to use for commands by default by all Pry instances.
|
33
|
+
# @return [Pry::CommandBase] The object to use for commands by default by all
|
34
|
+
# Pry instances.
|
35
|
+
attr_accessor :commands
|
36
|
+
|
37
|
+
# Get/Set the Proc to use for printing by default by all Pry
|
38
|
+
# instances.
|
39
|
+
# This is the 'print' component of the REPL.
|
40
|
+
# @return [Proc] The Proc to use for printing by default by all
|
41
|
+
# Pry instances.
|
42
|
+
attr_accessor :print
|
43
|
+
|
44
|
+
# Get/Set the Hash that defines Pry hooks used by default by all Pry
|
45
|
+
# instances.
|
46
|
+
# @return [Hash] The hooks used by default by all Pry instances.
|
47
|
+
# @example
|
48
|
+
# Pry.hooks :before_session => proc { puts "hello" },
|
49
|
+
# :after_session => proc { puts "goodbye" }
|
50
|
+
attr_accessor :hooks
|
51
|
+
|
52
|
+
# Get the array of Procs to be used for the prompts by default by
|
53
|
+
# all Pry instances.
|
54
|
+
# @return [Array<Proc>] The array of Procs to be used for the
|
55
|
+
# prompts by default by all Pry instances.
|
56
|
+
attr_accessor :prompt
|
57
|
+
|
58
|
+
# Value returned by last executed Pry command.
|
59
|
+
# @return [Object] The command value
|
60
|
+
attr_accessor :cmd_ret_value
|
61
|
+
|
62
|
+
# Determines whether colored output is enabled.
|
63
|
+
# @return [Boolean]
|
64
|
+
attr_accessor :color
|
65
|
+
end
|
66
|
+
|
67
|
+
# Start a Pry REPL.
|
68
|
+
# @param [Object, Binding] target The receiver of the Pry session
|
69
|
+
# @param [Hash] options
|
70
|
+
# @option options (see Pry#initialize)
|
71
|
+
# @example
|
72
|
+
# Pry.start(Object.new, :input => MyInput.new)
|
73
|
+
def self.start(target=TOPLEVEL_BINDING, options={})
|
74
|
+
new(options).repl(target)
|
75
|
+
end
|
76
|
+
|
77
|
+
# A custom version of `Kernel#inspect`.
|
78
|
+
# This method should not need to be accessed directly.
|
79
|
+
# @param obj The object to view.
|
80
|
+
# @return [String] The string representation of `obj`.
|
81
|
+
def self.view(obj)
|
82
|
+
case obj
|
83
|
+
when String, Hash, Array, Symbol, nil
|
84
|
+
obj.inspect
|
85
|
+
else
|
86
|
+
obj.to_s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# A version of `Pry.view` that clips the output to `max_size` chars.
|
91
|
+
# In case of > `max_size` chars the `#<Object...> notation is used.
|
92
|
+
# @param obj The object to view.
|
93
|
+
# @param max_size The maximum number of chars before clipping occurs.
|
94
|
+
# @return [String] The string representation of `obj`.
|
95
|
+
def self.view_clip(obj, max_size=60)
|
96
|
+
if Pry.view(obj).size < max_size
|
97
|
+
Pry.view(obj)
|
98
|
+
else
|
99
|
+
"#<#{obj.class}:%#x>" % (obj.object_id << 1)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Run a Pry command from outside a session. The commands available are
|
104
|
+
# those referenced by `Pry.commands` (the default command set).
|
105
|
+
# Command output is suppresed by default, this is because the return
|
106
|
+
# value (if there is one) is likely to be more useful.
|
107
|
+
# @param [String] arg_string The Pry command (including arguments,
|
108
|
+
# if any).
|
109
|
+
# @param [Hash] options Optional named parameters.
|
110
|
+
# @return [Object] The return value of the Pry command.
|
111
|
+
# @option options [Object, Binding] :context The object context to run the
|
112
|
+
# command under. Defaults to `TOPLEVEL_BINDING` (main).
|
113
|
+
# @option options [Boolean] :show_output Whether to show command
|
114
|
+
# output. Defaults to false.
|
115
|
+
# @example Run at top-level with no output.
|
116
|
+
# Pry.run_command "ls"
|
117
|
+
# @example Run under Pry class, returning only public methods.
|
118
|
+
# Pry.run_command "ls -m", :context => Pry
|
119
|
+
# @example Display command output.
|
120
|
+
# Pry.run_command "ls -av", :show_output => true
|
121
|
+
def self.run_command(arg_string, options={})
|
122
|
+
name, arg_string = arg_string.split(/\s+/, 2)
|
123
|
+
arg_string = "" if !arg_string
|
124
|
+
|
125
|
+
options = {
|
126
|
+
:context => TOPLEVEL_BINDING,
|
127
|
+
:show_output => false
|
128
|
+
}.merge!(options)
|
129
|
+
|
130
|
+
null_output = Object.new.tap { |v| v.instance_eval { def puts(*) end } }
|
131
|
+
|
132
|
+
commands = Pry.commands.dup
|
133
|
+
commands.output = options[:show_output] ? Pry.output : null_output
|
134
|
+
commands.target = Pry.binding_for(options[:context])
|
135
|
+
|
136
|
+
cmd = commands.commands[name]
|
137
|
+
if cmd
|
138
|
+
action = cmd[:action]
|
139
|
+
commands.instance_exec(*Shellwords.shellwords(arg_string), &action)
|
140
|
+
else
|
141
|
+
raise "No such Pry command: #{name}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Set all the configurable options back to their default values
|
146
|
+
def self.reset_defaults
|
147
|
+
@input = Readline
|
148
|
+
@output = $stdout
|
149
|
+
@commands = Pry::Commands
|
150
|
+
@prompt = DEFAULT_PROMPT
|
151
|
+
@print = DEFAULT_PRINT
|
152
|
+
@hooks = DEFAULT_HOOKS
|
153
|
+
@color = false
|
154
|
+
end
|
155
|
+
|
156
|
+
self.reset_defaults
|
157
|
+
|
158
|
+
@nesting = []
|
159
|
+
def @nesting.level
|
160
|
+
last.is_a?(Array) ? last.first : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
# Return all active Pry sessions.
|
164
|
+
# @return [Array<Pry>] Active Pry sessions.
|
165
|
+
def self.sessions
|
166
|
+
# last element in nesting array is the pry instance
|
167
|
+
nesting.map(&:last)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Return a `Binding` object for `target` or return `target` if it is
|
171
|
+
# already a `Binding`.
|
172
|
+
# In the case where `target` is top-level then return `TOPLEVEL_BINDING`
|
173
|
+
# @param [Object] target The object to get a `Binding` object for.
|
174
|
+
# @return [Binding] The `Binding` object.
|
175
|
+
def self.binding_for(target)
|
176
|
+
if target.is_a?(Binding)
|
177
|
+
target
|
178
|
+
else
|
179
|
+
if target == TOPLEVEL_BINDING.eval('self')
|
180
|
+
TOPLEVEL_BINDING
|
181
|
+
else
|
182
|
+
target.__binding__
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|