knjrbfw 0.0.7 → 0.0.8
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/Gemfile +3 -1
- data/VERSION +1 -1
- data/knjrbfw.gemspec +14 -4
- data/lib/knj/amixer.rb +148 -0
- data/lib/knj/arrayext.rb +14 -5
- data/lib/knj/autoload.rb +63 -57
- data/lib/knj/autoload/backups/facets_dictionary.rb +2 -2
- data/lib/knj/autoload/erubis.rb +2 -0
- data/lib/knj/cmd_gen.rb +71 -0
- data/lib/knj/compiler.rb +2 -2
- data/lib/knj/datarow.rb +138 -38
- data/lib/knj/datestamp.rb +2 -2
- data/lib/knj/datet.rb +72 -17
- data/lib/knj/erb/include.rb +5 -5
- data/lib/knj/errors.rb +4 -1
- data/lib/knj/eruby.rb +25 -11
- data/lib/knj/event_filemod.rb +27 -26
- data/lib/knj/event_handler.rb +8 -8
- data/lib/knj/exchangerates.rb +1 -1
- data/lib/knj/facebook_connect.rb +37 -0
- data/lib/knj/gettext_threadded.rb +4 -3
- data/lib/knj/google_sitemap.rb +1 -1
- data/lib/knj/hash_methods.rb +1 -1
- data/lib/knj/http.rb +35 -19
- data/lib/knj/http2.rb +249 -0
- data/lib/knj/image.rb +128 -0
- data/lib/knj/jruby-gtk2/gtk2.rb +1 -1
- data/lib/knj/knj.rb +1 -1
- data/lib/knj/knj_controller.rb +0 -2
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql.rb +3 -3
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_columns.rb +11 -11
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_tables.rb +2 -2
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3.rb +71 -14
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_columns.rb +17 -14
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_tables.rb +5 -5
- data/lib/knj/knjdb/libknjdb.rb +33 -16
- data/lib/knj/knjdb/libknjdb_row.rb +8 -8
- data/lib/knj/maemo/fremantle-calendar/fremantle-calendar.rb +1 -1
- data/lib/knj/mount.rb +6 -6
- data/lib/knj/mutexcl.rb +2 -2
- data/lib/knj/objects.rb +286 -73
- data/lib/knj/opts.rb +11 -4
- data/lib/knj/os.rb +16 -3
- data/lib/knj/php.rb +73 -26
- data/lib/knj/php_parser/php_parser.rb +1 -77
- data/lib/knj/retry.rb +4 -4
- data/lib/knj/rhodes/rhodes.rb +106 -0
- data/lib/knj/sshrobot/sshrobot.rb +1 -1
- data/lib/knj/strings.rb +72 -0
- data/lib/knj/sysuser.rb +1 -1
- data/lib/knj/tests/test_http2.rb +18 -0
- data/lib/knj/thread.rb +1 -5
- data/lib/knj/thread2.rb +3 -3
- data/lib/knj/threadhandler.rb +2 -2
- data/lib/knj/threadpool.rb +4 -4
- data/lib/knj/translations.rb +2 -17
- data/lib/knj/unix_proc.rb +3 -3
- data/lib/knj/web.rb +156 -77
- data/lib/knj/webscripts/image.rhtml +22 -3
- data/lib/knj/x11vnc.rb +3 -3
- data/spec/amixer_spec.rb +27 -0
- data/spec/knjrbfw_spec.rb +70 -12
- data/testfiles/image.jpg +0 -0
- metadata +32 -14
- data/Gemfile.lock +0 -32
data/lib/knj/opts.rb
CHANGED
@@ -5,7 +5,7 @@ module Knj::Opts
|
|
5
5
|
|
6
6
|
def self.init(arr_opts)
|
7
7
|
arr_opts.each do |pair|
|
8
|
-
if
|
8
|
+
if pair[0] == "knjdb" or pair[0] == "table"
|
9
9
|
$knjoptions[pair[0]] = pair[1]
|
10
10
|
end
|
11
11
|
end
|
@@ -18,7 +18,9 @@ module Knj::Opts
|
|
18
18
|
if !value
|
19
19
|
return ""
|
20
20
|
else
|
21
|
-
return value["value"]
|
21
|
+
return value["value"] if value.key?("value")
|
22
|
+
return value[:value] if value.key?(:value)
|
23
|
+
raise "Could not figure out of value."
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -26,13 +28,18 @@ module Knj::Opts
|
|
26
28
|
db = $knjoptions["knjdb"]
|
27
29
|
result = db.select($knjoptions["table"], {"title" => title}, {"limit" => 1}).fetch
|
28
30
|
|
29
|
-
if result
|
31
|
+
if !result
|
30
32
|
db.insert($knjoptions["table"], {
|
31
33
|
"title" => title,
|
32
34
|
"value" => value
|
33
35
|
})
|
34
36
|
else
|
35
|
-
|
37
|
+
id = nil
|
38
|
+
id = result["id"] if result.key?("id")
|
39
|
+
id = result[:id] if result.key?(:id)
|
40
|
+
raise "Could not figure out of ID." if !id
|
41
|
+
|
42
|
+
db.update($knjoptions["table"], {"value" => value}, {"id" => id})
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
data/lib/knj/os.rb
CHANGED
@@ -99,9 +99,22 @@ module Knj::Os
|
|
99
99
|
#Returns the xauth file for GDM.
|
100
100
|
def self.xauth_file
|
101
101
|
authfile = ""
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
|
103
|
+
if File.exists?("/var/run/gdm")
|
104
|
+
Dir.foreach("/var/run/gdm") do |file|
|
105
|
+
next if file == "." or file == ".." or !file.match(/^auth-for-gdm-.+$/)
|
106
|
+
authfile = "/var/run/gdm/#{file}/database"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
if File.exists?("/var/run/lightdm")
|
111
|
+
Dir.foreach("/var/run/lightdm") do |file|
|
112
|
+
next if file == "." or file == ".."
|
113
|
+
|
114
|
+
Dir.foreach("/var/run/lightdm/#{file}") do |f2|
|
115
|
+
authfile = "/var/run/lightdm/#{file}/#{f2}" if f2.match(/^:(\d+)$/)
|
116
|
+
end
|
117
|
+
end
|
105
118
|
end
|
106
119
|
|
107
120
|
if authfile.to_s.length <= 0
|
data/lib/knj/php.rb
CHANGED
@@ -13,7 +13,7 @@ module Knj::Php
|
|
13
13
|
send_paras << paras[1] if paras[1]
|
14
14
|
paras[0][0].send(*send_paras)
|
15
15
|
else
|
16
|
-
raise "Unknown user-func."
|
16
|
+
raise "Unknown user-func: '#{paras[0].class.name}'."
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -118,6 +118,42 @@ module Knj::Php
|
|
118
118
|
elsif cstr == "Knj::Unix_proc"
|
119
119
|
retstr += "#{argument.class.to_s}::data - "
|
120
120
|
retstr += print_r(argument.data, true, count).to_s
|
121
|
+
elsif cstr == "Thread"
|
122
|
+
retstr += "#{argument.class.to_s} - "
|
123
|
+
|
124
|
+
hash = {}
|
125
|
+
argument.keys.each do |key|
|
126
|
+
hash[key] = argument[key]
|
127
|
+
end
|
128
|
+
|
129
|
+
retstr += print_r(hash, true, count).to_s
|
130
|
+
elsif cstr == "Class"
|
131
|
+
retstr += "#{argument.class.to_s} - "
|
132
|
+
hash = {"name" => argument.name}
|
133
|
+
retstr += print_r(hash, true, count).to_s
|
134
|
+
elsif cstr == "URI::Generic"
|
135
|
+
retstr += "#{argument.class.to_s}{\n"
|
136
|
+
methods = [:host, :port, :scheme, :path]
|
137
|
+
count += 1
|
138
|
+
methods.each do |method|
|
139
|
+
i_spaces = 0
|
140
|
+
while(i_spaces < count - 1)
|
141
|
+
retstr += " "
|
142
|
+
i_spaces += 1
|
143
|
+
end
|
144
|
+
|
145
|
+
retstr += "#{method}: #{argument.send(method)}\n"
|
146
|
+
end
|
147
|
+
|
148
|
+
count -= 1
|
149
|
+
|
150
|
+
i = 0
|
151
|
+
while(i < count - 1)
|
152
|
+
retstr += " "
|
153
|
+
i += 1
|
154
|
+
end
|
155
|
+
|
156
|
+
retstr += "}\n"
|
121
157
|
else
|
122
158
|
#print argument.to_s, "\n"
|
123
159
|
retstr += "Unknown class: " + cstr + "\n"
|
@@ -195,8 +231,7 @@ module Knj::Php
|
|
195
231
|
end
|
196
232
|
|
197
233
|
def htmlspecialchars(string)
|
198
|
-
|
199
|
-
return CGI.escapeHTML(string)
|
234
|
+
return Knj::Web.html(string)
|
200
235
|
end
|
201
236
|
|
202
237
|
def isset(var)
|
@@ -250,16 +285,16 @@ module Knj::Php
|
|
250
285
|
end
|
251
286
|
|
252
287
|
begin
|
253
|
-
|
288
|
+
_kas.header(key, value) #This is for knjAppServer - knj.
|
254
289
|
sent = true
|
255
290
|
rescue NameError => e
|
256
291
|
if $knj_eruby
|
257
292
|
$knj_eruby.header(key, value)
|
258
293
|
sent = true
|
259
|
-
elsif $cgi.
|
294
|
+
elsif $cgi.class.name == "CGI"
|
260
295
|
sent = true
|
261
296
|
$cgi.header(key => value)
|
262
|
-
elsif $_CGI.
|
297
|
+
elsif $_CGI.class.name == "CGI"
|
263
298
|
sent = true
|
264
299
|
$_CGI.header(key => value)
|
265
300
|
end
|
@@ -273,23 +308,17 @@ module Knj::Php
|
|
273
308
|
end
|
274
309
|
|
275
310
|
def urldecode(string)
|
276
|
-
|
277
|
-
#return CGI.unescape(string)
|
278
|
-
|
279
|
-
#Thanks to CGI framework
|
280
|
-
str = string.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
|
281
|
-
[$1.delete('%')].pack('H*')
|
282
|
-
end
|
311
|
+
return Knj::Web.urldec(string)
|
283
312
|
end
|
284
313
|
|
285
314
|
def urlencode(string)
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
315
|
+
return Knj::Web.urlenc(string)
|
316
|
+
end
|
317
|
+
|
318
|
+
def parse_str(str, hash)
|
319
|
+
CGI.parse(str).each do |key, val|
|
320
|
+
hash[key] = val
|
321
|
+
end
|
293
322
|
end
|
294
323
|
|
295
324
|
def file_put_contents(filepath, content)
|
@@ -421,8 +450,7 @@ module Knj::Php
|
|
421
450
|
end
|
422
451
|
|
423
452
|
def html_entity_decode(string)
|
424
|
-
|
425
|
-
string = CGI.unescapeHTML(string.to_s)
|
453
|
+
string = Knj::Web.html(string)
|
426
454
|
string = string.gsub("ø", "ø").gsub("æ", "æ").gsub("å", "å").gsub("€", "€").gsub("#39;", "'")
|
427
455
|
return string
|
428
456
|
end
|
@@ -527,9 +555,14 @@ module Knj::Php
|
|
527
555
|
args["expires"] = Time.at(expire) if expire
|
528
556
|
args["domain"] = domain if domain
|
529
557
|
|
530
|
-
|
531
|
-
|
532
|
-
|
558
|
+
begin
|
559
|
+
_kas.cookie(args)
|
560
|
+
rescue NameError
|
561
|
+
cookie = CGI::Cookie.new(args)
|
562
|
+
status = Knj::Php.header("Set-Cookie: #{cookie.to_s}")
|
563
|
+
$_COOKIE[cname] = cvalue if $_COOKIE
|
564
|
+
end
|
565
|
+
|
533
566
|
return status
|
534
567
|
end
|
535
568
|
|
@@ -610,7 +643,7 @@ module Knj::Php
|
|
610
643
|
month = cur_time.month if month == nil
|
611
644
|
year = cur_time.year if year == nil
|
612
645
|
|
613
|
-
new_time =
|
646
|
+
new_time = Knj::Datet.in("#{year.to_s}-#{month.to_s}-#{date.to_s} #{hour.to_s}:#{min.to_s}:#{sec.to_s}")
|
614
647
|
return new_time.to_i
|
615
648
|
end
|
616
649
|
|
@@ -713,5 +746,19 @@ module Knj::Php
|
|
713
746
|
return plain_str.to_s
|
714
747
|
end
|
715
748
|
|
749
|
+
#Sort methods.
|
750
|
+
def ksort(hash)
|
751
|
+
nhash = hash.sort do |a, b|
|
752
|
+
a[0] <=> b[0]
|
753
|
+
end
|
754
|
+
|
755
|
+
newhash = {}
|
756
|
+
nhash.each do |val|
|
757
|
+
newhash[val[0]] = val[1][0]
|
758
|
+
end
|
759
|
+
|
760
|
+
return newhash
|
761
|
+
end
|
762
|
+
|
716
763
|
module_function(*instance_methods)
|
717
764
|
end
|
@@ -5,7 +5,7 @@ class Knj::Php_parser
|
|
5
5
|
@args = args
|
6
6
|
@cont = File.read(@args["file"])
|
7
7
|
|
8
|
-
if !args.
|
8
|
+
if !args.key?("require_requirements") or args["require_requirements"]
|
9
9
|
@retcont = "require \"knj/autoload\"\n"
|
10
10
|
@retcont += "require \"knj/php\"\n"
|
11
11
|
@retcont += "require \"knj/php_parser/php_parser\"\n"
|
@@ -13,82 +13,6 @@ class Knj::Php_parser
|
|
13
13
|
else
|
14
14
|
@retcont = ""
|
15
15
|
end
|
16
|
-
|
17
|
-
@regex_funcname = "([A-z][A-z\d_]*)"
|
18
|
-
@regex_varname = "([A-z][A-z\d]*)"
|
19
|
-
|
20
|
-
@tabs = 0
|
21
|
-
@funcs_started = 0
|
22
|
-
end
|
23
|
-
|
24
|
-
def parse
|
25
|
-
self.search_starttag
|
26
|
-
return @retcont
|
27
|
-
end
|
28
|
-
|
29
|
-
def search_starttag
|
30
|
-
match = self.matchclear(/\A([\s\S]*?<\?(php|))/)
|
31
|
-
if !match
|
32
|
-
return nil
|
33
|
-
end
|
34
|
-
|
35
|
-
self.clear_whitespace
|
36
|
-
self.search_newstuff
|
37
|
-
end
|
38
|
-
|
39
|
-
def tabs
|
40
|
-
cont = ""
|
41
|
-
0.upto(@tabs - 1) do |count|
|
42
|
-
cont += "\t"
|
43
|
-
end
|
44
|
-
|
45
|
-
return cont
|
46
|
-
end
|
47
|
-
|
48
|
-
def clear_regex(regex)
|
49
|
-
@cont = @cont.gsub(regex, "")
|
50
|
-
end
|
51
|
-
|
52
|
-
def clear_whitespace
|
53
|
-
@cont = @cont.gsub(/\A\s+/, "")
|
54
|
-
end
|
55
|
-
|
56
|
-
def matchclear(regex, debug = false)
|
57
|
-
if match = @cont.match(regex)
|
58
|
-
print "Before (#{debug}):\n#{@cont}\n\n" if debug
|
59
|
-
@cont = @cont.gsub(regex, "")
|
60
|
-
self.clear_whitespace
|
61
|
-
print "After (#{debug}):\n#{@cont}\n\n\n" if debug
|
62
|
-
|
63
|
-
return match
|
64
|
-
end
|
65
|
-
|
66
|
-
return false
|
67
|
-
end
|
68
|
-
|
69
|
-
def search_newstuff
|
70
|
-
loop do
|
71
|
-
if match = self.matchclear(/\Afunction\s+#{@regex_funcname}\(/)
|
72
|
-
self.func_args(match[1])
|
73
|
-
elsif match = self.matchclear(/\A(print|echo)\s+/)
|
74
|
-
@retcont += "#{self.tabs}Knj::Php.#{match[1]}("
|
75
|
-
self.func_args_single_given
|
76
|
-
elsif match = self.matchclear(/\A\}/)
|
77
|
-
@tabs -= 1
|
78
|
-
@retcont += "#{self.tabs}end\n"
|
79
|
-
@tabs -= 1
|
80
|
-
@retcont += "#{self.tabs}end\n"
|
81
|
-
elsif match = self.matchclear(/\A([A-z][A-z\d_]*)\(/)
|
82
|
-
@retcont += "#{self.tabs}Knj::Php_parser::Functions.#{match[1]}("
|
83
|
-
self.func_args_given
|
84
|
-
elsif match = self.matchclear(/\A\?>/)
|
85
|
-
self.search_starttag
|
86
|
-
elsif cont.length <= 0
|
87
|
-
break
|
88
|
-
else
|
89
|
-
raise "Could not find out whats next."
|
90
|
-
end
|
91
|
-
end
|
92
16
|
end
|
93
17
|
end
|
94
18
|
|
data/lib/knj/retry.rb
CHANGED
@@ -30,12 +30,12 @@ class Knj::Retry
|
|
30
30
|
end
|
31
31
|
rescue Exception => e
|
32
32
|
if e.class == Interrupt
|
33
|
-
raise e if !args.
|
33
|
+
raise e if !args.key?(:interrupt) or args[:interrupt]
|
34
34
|
elsif e.class == SystemExit
|
35
|
-
raise e if !args.
|
36
|
-
elsif count <= 1 or (args.
|
35
|
+
raise e if !args.key?(:exit) or args[:exit]
|
36
|
+
elsif count <= 1 or (args.key?(:errors) and args[:errors].index(e.class) == nil)
|
37
37
|
doraise = e
|
38
|
-
elsif args.
|
38
|
+
elsif args.key?(:errors) and args[:errors].index(e.class) != nil
|
39
39
|
#given error was in the :errors-array - do nothing. Maybe later it should be logged and returned in a stats-hash or something? - knj
|
40
40
|
end
|
41
41
|
|
data/lib/knj/rhodes/rhodes.rb
CHANGED
@@ -1,4 +1,110 @@
|
|
1
|
+
$knjautoload = false
|
2
|
+
|
1
3
|
class Knj::Rhodes
|
4
|
+
attr_reader :db, :ob, :gettext, :args
|
5
|
+
|
6
|
+
def initialize(args = {})
|
7
|
+
require "Knj/arrayext.rb"
|
8
|
+
require "Knj/php.rb"
|
9
|
+
require "Knj/objects.rb"
|
10
|
+
require "Knj/datarow.rb"
|
11
|
+
require "Knj/event_handler.rb"
|
12
|
+
require "Knj/hash_methods.rb"
|
13
|
+
require "Knj/errors.rb"
|
14
|
+
require "Knj/gettext_threadded.rb"
|
15
|
+
require "Knj/locales.rb"
|
16
|
+
require "Knj/web.rb"
|
17
|
+
require "Knj/rhodes/mutex.rb"
|
18
|
+
require "Knj/opts.rb"
|
19
|
+
|
20
|
+
require "Knj/knjdb/libknjdb.rb"
|
21
|
+
require "Knj/knjdb/drivers/sqlite3/knjdb_sqlite3.rb"
|
22
|
+
require "Knj/knjdb/drivers/sqlite3/knjdb_sqlite3_tables.rb"
|
23
|
+
require "Knj/knjdb/drivers/sqlite3/knjdb_sqlite3_columns.rb"
|
24
|
+
require "Knj/knjdb/drivers/sqlite3/knjdb_sqlite3_indexes.rb"
|
25
|
+
|
26
|
+
@args = args
|
27
|
+
|
28
|
+
@db = Knj::Db.new(
|
29
|
+
:type => "sqlite3",
|
30
|
+
:subtype => "rhodes",
|
31
|
+
:path => "#{Rho::RhoApplication.get_base_app_path}app/rhodes_default.sqlite3",
|
32
|
+
:return_keys => "symbols",
|
33
|
+
:require => false
|
34
|
+
)
|
35
|
+
|
36
|
+
if @args[:schema]
|
37
|
+
schema = @args[:schema]
|
38
|
+
else
|
39
|
+
schema = {"tables" => {}}
|
40
|
+
end
|
41
|
+
|
42
|
+
schema["tables"]["Option"] = {
|
43
|
+
"columns" => [
|
44
|
+
{"name" => "id", "type" => "int", "autoincr" => true, "primarykey" => true},
|
45
|
+
{"name" => "title", "type" => "varchar"},
|
46
|
+
{"name" => "value", "type" => "text"}
|
47
|
+
]
|
48
|
+
}
|
49
|
+
|
50
|
+
require "knjdbrevision/knjdbrevision.rb"
|
51
|
+
dbrev = Knjdbrevision.new
|
52
|
+
dbrev.init_db(schema, @db)
|
53
|
+
|
54
|
+
@ob = Knj::Objects.new(
|
55
|
+
:db => @db,
|
56
|
+
:class_path => "#{Rho::RhoApplication.get_base_app_path}app/Multinasser/include",
|
57
|
+
:require => false,
|
58
|
+
:module => @args[:module],
|
59
|
+
:datarow => true
|
60
|
+
)
|
61
|
+
|
62
|
+
Knj::Opts.init(
|
63
|
+
"table" => "Option",
|
64
|
+
"knjdb" => @db
|
65
|
+
)
|
66
|
+
|
67
|
+
@gettext = Knj::Gettext_threadded.new
|
68
|
+
@gettext.load_dir("#{Rho::RhoApplication.get_base_app_path}app/locales")
|
69
|
+
end
|
70
|
+
|
71
|
+
def inputs(*arr)
|
72
|
+
html = ""
|
73
|
+
|
74
|
+
arr.each do |data|
|
75
|
+
value = ""
|
76
|
+
|
77
|
+
data[:type] = :text if !data.key?(:type)
|
78
|
+
|
79
|
+
if data.key?(:value) and data[:value].is_a?(Array) and data[:value][0]
|
80
|
+
value = data[:value][0][data[:value][1]]
|
81
|
+
elsif data.key?(:value)
|
82
|
+
value = data[:value]
|
83
|
+
end
|
84
|
+
|
85
|
+
extra_args = ""
|
86
|
+
extra_args = " autofocus=\"autofocus\"" if data[:autofocus]
|
87
|
+
|
88
|
+
css = {}
|
89
|
+
|
90
|
+
if data[:type] == :textarea
|
91
|
+
css["height"] = data[:height] if data.key?(:height)
|
92
|
+
|
93
|
+
html += "<div data-role=\"fieldcontain\">"
|
94
|
+
html += "<label for=\"#{data[:name]}\">#{data[:title]}</label>"
|
95
|
+
html += "<textarea name=\"#{data[:name]}\" id=\"#{data[:name]}\"#{Knj::Web.style_html(css)}#{extra_args}>#{value}</textarea>"
|
96
|
+
html += "</div>"
|
97
|
+
else
|
98
|
+
html += "<div data-role=\"fieldcontain\">"
|
99
|
+
html += "<label for=\"#{data[:name]}\">#{data[:title]}</label>"
|
100
|
+
html += "<input type=\"#{data[:type]}\" name=\"#{data[:name]}\" id=\"#{data[:name]}\" value=\"#{value}\"#{Knj::Web.style_html(css)}#{extra_args} />"
|
101
|
+
html += "</div>"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
return html
|
106
|
+
end
|
107
|
+
|
2
108
|
def self.html_links(args)
|
3
109
|
html_cont = "#{args[:html]}"
|
4
110
|
|