wallyqs-org-ruby 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.bnsignore +18 -0
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +36 -0
- data/History.txt +112 -0
- data/README.rdoc +67 -0
- data/Rakefile +33 -0
- data/TAGS +167 -0
- data/announcement.txt +24 -0
- data/bin/org-ruby +45 -0
- data/lib/org-ruby.rb +55 -0
- data/lib/org-ruby/headline.rb +110 -0
- data/lib/org-ruby/html_output_buffer.rb +273 -0
- data/lib/org-ruby/html_symbol_replace.rb +345 -0
- data/lib/org-ruby/line.rb +244 -0
- data/lib/org-ruby/output_buffer.rb +237 -0
- data/lib/org-ruby/parser.rb +366 -0
- data/lib/org-ruby/regexp_helper.rb +192 -0
- data/lib/org-ruby/textile_output_buffer.rb +102 -0
- data/lib/org-ruby/textile_symbol_replace.rb +346 -0
- data/lib/org-ruby/tilt.rb +29 -0
- data/org-ruby.gemspec +40 -0
- data/spec/data/freeform-example.org +113 -0
- data/spec/data/freeform.org +111 -0
- data/spec/data/hyp-planning.org +335 -0
- data/spec/data/remember.org +53 -0
- data/spec/headline_spec.rb +65 -0
- data/spec/html_examples/advanced-code.html +81 -0
- data/spec/html_examples/advanced-code.org +106 -0
- data/spec/html_examples/advanced-lists.html +31 -0
- data/spec/html_examples/advanced-lists.org +31 -0
- data/spec/html_examples/block_code.html +28 -0
- data/spec/html_examples/block_code.org +35 -0
- data/spec/html_examples/blockcomment.html +3 -0
- data/spec/html_examples/blockcomment.org +15 -0
- data/spec/html_examples/blockquote.html +7 -0
- data/spec/html_examples/blockquote.org +13 -0
- data/spec/html_examples/center.html +6 -0
- data/spec/html_examples/center.org +7 -0
- data/spec/html_examples/code-comment.html +18 -0
- data/spec/html_examples/code-comment.org +22 -0
- data/spec/html_examples/code-syntax.html +98 -0
- data/spec/html_examples/code-syntax.org +99 -0
- data/spec/html_examples/comment-trees.html +4 -0
- data/spec/html_examples/comment-trees.org +13 -0
- data/spec/html_examples/custom-seq-todo.html +15 -0
- data/spec/html_examples/custom-seq-todo.org +24 -0
- data/spec/html_examples/custom-todo.html +15 -0
- data/spec/html_examples/custom-todo.org +24 -0
- data/spec/html_examples/custom-typ-todo.html +15 -0
- data/spec/html_examples/custom-typ-todo.org +24 -0
- data/spec/html_examples/deflist.html +6 -0
- data/spec/html_examples/deflist.org +6 -0
- data/spec/html_examples/entities.html +4 -0
- data/spec/html_examples/entities.org +11 -0
- data/spec/html_examples/escape-pre.html +6 -0
- data/spec/html_examples/escape-pre.org +6 -0
- data/spec/html_examples/export-exclude-only.html +13 -0
- data/spec/html_examples/export-exclude-only.org +81 -0
- data/spec/html_examples/export-keywords.html +4 -0
- data/spec/html_examples/export-keywords.org +18 -0
- data/spec/html_examples/export-tags.html +8 -0
- data/spec/html_examples/export-tags.org +82 -0
- data/spec/html_examples/export-title.html +2 -0
- data/spec/html_examples/export-title.org +4 -0
- data/spec/html_examples/footnotes.html +10 -0
- data/spec/html_examples/footnotes.org +7 -0
- data/spec/html_examples/html-literal.html +2 -0
- data/spec/html_examples/html-literal.org +6 -0
- data/spec/html_examples/inline-formatting.html +20 -0
- data/spec/html_examples/inline-formatting.org +33 -0
- data/spec/html_examples/inline-images.html +10 -0
- data/spec/html_examples/inline-images.org +15 -0
- data/spec/html_examples/link-features.html +8 -0
- data/spec/html_examples/link-features.org +19 -0
- data/spec/html_examples/lists.html +23 -0
- data/spec/html_examples/lists.org +47 -0
- data/spec/html_examples/metadata-comment.html +27 -0
- data/spec/html_examples/metadata-comment.org +30 -0
- data/spec/html_examples/only-list.html +5 -0
- data/spec/html_examples/only-list.org +3 -0
- data/spec/html_examples/only-table.html +6 -0
- data/spec/html_examples/only-table.org +5 -0
- data/spec/html_examples/skip-header.html +3 -0
- data/spec/html_examples/skip-header.org +28 -0
- data/spec/html_examples/skip-table.html +4 -0
- data/spec/html_examples/skip-table.org +19 -0
- data/spec/html_examples/subsupscript-nil.html +3 -0
- data/spec/html_examples/subsupscript-nil.org +6 -0
- data/spec/html_examples/subsupscript.html +3 -0
- data/spec/html_examples/subsupscript.org +5 -0
- data/spec/html_examples/tables.html +35 -0
- data/spec/html_examples/tables.org +50 -0
- data/spec/html_examples/text.html +2 -0
- data/spec/html_examples/text.org +16 -0
- data/spec/line_spec.rb +155 -0
- data/spec/output_buffer_spec.rb +19 -0
- data/spec/parser_spec.rb +152 -0
- data/spec/regexp_helper_spec.rb +57 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/textile_examples/block_code.org +35 -0
- data/spec/textile_examples/block_code.textile +29 -0
- data/spec/textile_examples/blockquote.org +13 -0
- data/spec/textile_examples/blockquote.textile +11 -0
- data/spec/textile_examples/center.org +7 -0
- data/spec/textile_examples/center.textile +6 -0
- data/spec/textile_examples/footnotes.org +7 -0
- data/spec/textile_examples/footnotes.textile +8 -0
- data/spec/textile_examples/keywords.org +13 -0
- data/spec/textile_examples/keywords.textile +11 -0
- data/spec/textile_examples/links.org +11 -0
- data/spec/textile_examples/links.textile +10 -0
- data/spec/textile_examples/lists.org +36 -0
- data/spec/textile_examples/lists.textile +20 -0
- data/spec/textile_examples/single-space-plain-list.org +13 -0
- data/spec/textile_examples/single-space-plain-list.textile +10 -0
- data/spec/textile_examples/tables.org +50 -0
- data/spec/textile_examples/tables.textile +40 -0
- data/spec/textile_output_buffer_spec.rb +21 -0
- data/tasks/test_case.rake +49 -0
- data/test/test_orgmode_parser.rb +0 -0
- data/util/gen-special-replace.el +37 -0
- metadata +244 -0
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
|
+
|
4
|
+
describe Orgmode::Parser do
|
5
|
+
it "should open ORG files" do
|
6
|
+
parser = Orgmode::Parser.load(RememberFile)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should fail on non-existant files" do
|
10
|
+
lambda { parser = Orgmode::Parser.load("does-not-exist.org") }.should raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should load all of the lines" do
|
14
|
+
parser = Orgmode::Parser.load(RememberFile)
|
15
|
+
parser.lines.length.should eql(53)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should find all headlines" do
|
19
|
+
parser = Orgmode::Parser.load(RememberFile)
|
20
|
+
parser.should have(12).headlines
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can find a headline by index" do
|
24
|
+
parser = Orgmode::Parser.load(RememberFile)
|
25
|
+
parser.headlines[1].line.should eql("** YAML header in Webby\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should determine headline levels" do
|
29
|
+
parser = Orgmode::Parser.load(RememberFile)
|
30
|
+
parser.headlines[0].level.should eql(1)
|
31
|
+
parser.headlines[1].level.should eql(2)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should put body lines in headlines" do
|
35
|
+
parser = Orgmode::Parser.load(RememberFile)
|
36
|
+
parser.headlines[0].should have(1).body_lines
|
37
|
+
parser.headlines[1].should have(7).body_lines
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should understand lines before the first headline" do
|
41
|
+
parser = Orgmode::Parser.load(FreeformFile)
|
42
|
+
parser.should have(19).header_lines
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should load in-buffer settings" do
|
46
|
+
parser = Orgmode::Parser.load(FreeformFile)
|
47
|
+
parser.should have(12).in_buffer_settings
|
48
|
+
parser.in_buffer_settings["TITLE"].should eql("Freeform")
|
49
|
+
parser.in_buffer_settings["EMAIL"].should eql("bdewey@gmail.com")
|
50
|
+
parser.in_buffer_settings["LANGUAGE"].should eql("en")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should understand OPTIONS" do
|
54
|
+
parser = Orgmode::Parser.load(FreeformFile)
|
55
|
+
parser.should have(19).options
|
56
|
+
parser.options["TeX"].should eql("t")
|
57
|
+
parser.options["todo"].should eql("t")
|
58
|
+
parser.options["\\n"].should eql("nil")
|
59
|
+
parser.export_todo?.should be_true
|
60
|
+
parser.options.delete("todo")
|
61
|
+
parser.export_todo?.should be_false
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should skip in-buffer settings inside EXAMPLE blocks" do
|
65
|
+
parser = Orgmode::Parser.load(FreeformExampleFile)
|
66
|
+
parser.should have(0).in_buffer_settings
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should return a textile string" do
|
70
|
+
parser = Orgmode::Parser.load(FreeformFile)
|
71
|
+
parser.to_textile.should be_kind_of(String)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should understand export table option" do
|
75
|
+
fname = File.join(File.dirname(__FILE__), %w[html_examples skip-table.org])
|
76
|
+
data = IO.read(fname)
|
77
|
+
p = Orgmode::Parser.new(data)
|
78
|
+
p.export_tables?.should be_false
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "Custom keyword parser" do
|
82
|
+
fname = File.join(File.dirname(__FILE__), %w[html_examples custom-todo.org])
|
83
|
+
p = Orgmode::Parser.load(fname)
|
84
|
+
valid_keywords = %w[TODO INPROGRESS WAITING DONE CANCELED]
|
85
|
+
invalid_keywords = %w[TODOX todo inprogress Waiting done cANCELED NEXT |]
|
86
|
+
valid_keywords.each do |kw|
|
87
|
+
it "should match custom keyword #{kw}" do
|
88
|
+
(kw =~ p.custom_keyword_regexp).should be_true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
invalid_keywords.each do |kw|
|
92
|
+
it "should not match custom keyword #{kw}" do
|
93
|
+
(kw =~ p.custom_keyword_regexp).should be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
it "should not match blank as a custom keyword" do
|
97
|
+
("" =~ p.custom_keyword_regexp).should be_nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "Custom include/exclude parser" do
|
102
|
+
fname = File.join(File.dirname(__FILE__), %w[html_examples export-tags.org])
|
103
|
+
p = Orgmode::Parser.load(fname)
|
104
|
+
it "should load tags" do
|
105
|
+
p.should have(2).export_exclude_tags
|
106
|
+
p.should have(1).export_select_tags
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "Export to Textile test cases" do
|
111
|
+
data_directory = File.join(File.dirname(__FILE__), "textile_examples")
|
112
|
+
org_files = File.expand_path(File.join(data_directory, "*.org" ))
|
113
|
+
files = Dir.glob(org_files)
|
114
|
+
files.each do |file|
|
115
|
+
basename = File.basename(file, ".org")
|
116
|
+
textile_name = File.join(data_directory, basename + ".textile")
|
117
|
+
textile_name = File.expand_path(textile_name)
|
118
|
+
|
119
|
+
it "should convert #{basename}.org to Textile" do
|
120
|
+
expected = IO.read(textile_name)
|
121
|
+
expected.should be_kind_of(String)
|
122
|
+
parser = Orgmode::Parser.new(IO.read(file))
|
123
|
+
actual = parser.to_textile
|
124
|
+
actual.should be_kind_of(String)
|
125
|
+
actual.should == expected
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "Export to HTML test cases" do
|
131
|
+
# Dynamic generation of examples from each *.org file in html_examples.
|
132
|
+
# Each of these files is convertable to HTML.
|
133
|
+
data_directory = File.join(File.dirname(__FILE__), "html_examples")
|
134
|
+
org_files = File.expand_path(File.join(data_directory, "*.org" ))
|
135
|
+
files = Dir.glob(org_files)
|
136
|
+
files.each do |file|
|
137
|
+
basename = File.basename(file, ".org")
|
138
|
+
textile_name = File.join(data_directory, basename + ".html")
|
139
|
+
textile_name = File.expand_path(textile_name)
|
140
|
+
|
141
|
+
it "should convert #{basename}.org to HTML" do
|
142
|
+
expected = IO.read(textile_name)
|
143
|
+
expected.should be_kind_of(String)
|
144
|
+
parser = Orgmode::Parser.new(IO.read(file))
|
145
|
+
actual = parser.to_html
|
146
|
+
actual.should be_kind_of(String)
|
147
|
+
actual.should == expected
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
|
3
|
+
describe Orgmode::RegexpHelper do
|
4
|
+
it "should recognize simple markup" do
|
5
|
+
e = Orgmode::RegexpHelper.new
|
6
|
+
total = 0
|
7
|
+
e.match_all("/italic/") do |border, string|
|
8
|
+
border.should eql("/")
|
9
|
+
string.should eql("italic")
|
10
|
+
total += 1
|
11
|
+
end
|
12
|
+
total.should eql(1)
|
13
|
+
|
14
|
+
total = 0
|
15
|
+
borders = %w[* / ~]
|
16
|
+
strings = %w[bold italic verbatim]
|
17
|
+
e.match_all("This string contains *bold*, /italic/, and ~verbatim~ text.")\
|
18
|
+
do |border, str|
|
19
|
+
border.should eql(borders[total])
|
20
|
+
str.should eql(strings[total])
|
21
|
+
total += 1
|
22
|
+
end
|
23
|
+
total.should eql(3)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not get confused by links" do
|
27
|
+
e = Orgmode::RegexpHelper.new
|
28
|
+
total = 0
|
29
|
+
# Make sure the slashes in these links aren't treated as italics
|
30
|
+
e.match_all("[[http://www.bing.com/twitter]]") do |border, str|
|
31
|
+
total += 1
|
32
|
+
end
|
33
|
+
total.should eql(0)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should correctly perform substitutions" do
|
37
|
+
e = Orgmode::RegexpHelper.new
|
38
|
+
map = {
|
39
|
+
"*" => "strong",
|
40
|
+
"/" => "i",
|
41
|
+
"~" => "pre"
|
42
|
+
}
|
43
|
+
n = e.rewrite_emphasis("This string contains *bold*, /italic/, and ~verbatim~ text.") do |border, str|
|
44
|
+
"<#{map[border]}>#{str}</#{map[border]}>"
|
45
|
+
end
|
46
|
+
n.should eql("This string contains <strong>bold</strong>, <i>italic</i>, and <pre>verbatim</pre> text.")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should allow link rewriting" do
|
50
|
+
e = Orgmode::RegexpHelper.new
|
51
|
+
str = e.rewrite_links("[[http://www.bing.com]]") do |link,text|
|
52
|
+
text ||= link
|
53
|
+
"\"#{text}\":#{link}"
|
54
|
+
end
|
55
|
+
str.should eql("\"http://www.bing.com\":http://www.bing.com")
|
56
|
+
end
|
57
|
+
end # describe Orgmode::RegexpHelper
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(
|
3
|
+
File.join(File.dirname(__FILE__), %w[.. lib org-ruby]))
|
4
|
+
|
5
|
+
|
6
|
+
RememberFile = File.join(File.dirname(__FILE__), %w[data remember.org])
|
7
|
+
FreeformFile = File.join(File.dirname(__FILE__), %w[data freeform.org])
|
8
|
+
FreeformExampleFile = File.join(File.dirname(__FILE__), %w[data freeform-example.org])
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
# == Mock Framework
|
12
|
+
#
|
13
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
14
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
15
|
+
#
|
16
|
+
# config.mock_with :mocha
|
17
|
+
# config.mock_with :flexmock
|
18
|
+
# config.mock_with :rr
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
* Block Code
|
2
|
+
|
3
|
+
I need to get block code examples working. In =orgmode=, they look
|
4
|
+
like this:
|
5
|
+
|
6
|
+
#+BEGIN_EXAMPLE
|
7
|
+
|
8
|
+
def initialize(output)
|
9
|
+
@output = output
|
10
|
+
@buffer = ""
|
11
|
+
@output_type = :start
|
12
|
+
@list_indent_stack = []
|
13
|
+
@paragraph_modifier = nil
|
14
|
+
|
15
|
+
@logger = Logger.new(STDERR)
|
16
|
+
@logger.level = Logger::WARN
|
17
|
+
end
|
18
|
+
|
19
|
+
#+END_EXAMPLE
|
20
|
+
|
21
|
+
And now I should be back to normal text.
|
22
|
+
|
23
|
+
Putting in another paragraph for good measure.
|
24
|
+
|
25
|
+
|
26
|
+
Code should also get cancelled by a list, thus:
|
27
|
+
|
28
|
+
#+BEGIN_EXAMPLE
|
29
|
+
This is my code!
|
30
|
+
|
31
|
+
Another line!
|
32
|
+
#+END_EXAMPLE
|
33
|
+
|
34
|
+
- My list should cancel this.
|
35
|
+
- Another list line.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
h1. Block Code
|
2
|
+
|
3
|
+
I need to get block code examples working. In @orgmode@, they look like this:
|
4
|
+
|
5
|
+
bc..
|
6
|
+
def initialize(output)
|
7
|
+
@output = output
|
8
|
+
@buffer = ""
|
9
|
+
@output_type = :start
|
10
|
+
@list_indent_stack = []
|
11
|
+
@paragraph_modifier = nil
|
12
|
+
|
13
|
+
@logger = Logger.new(STDERR)
|
14
|
+
@logger.level = Logger::WARN
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
p. And now I should be back to normal text.
|
19
|
+
|
20
|
+
Putting in another paragraph for good measure.
|
21
|
+
|
22
|
+
Code should also get cancelled by a list, thus:
|
23
|
+
|
24
|
+
bc.. This is my code!
|
25
|
+
|
26
|
+
Another line!
|
27
|
+
|
28
|
+
* My list should cancel this.
|
29
|
+
* Another list line.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
KEYWORDS
|
2
|
+
|
3
|
+
By default, I don't want keywords exported to textile.
|
4
|
+
|
5
|
+
* DONE Recognize standard keywords
|
6
|
+
CLOSED: [2009-12-21 Mon 15:23]
|
7
|
+
|
8
|
+
The standard =orgmode= keywords are TODO and DONE. Recognize those.
|
9
|
+
|
10
|
+
* TODO Recongize buffer-specific keywords
|
11
|
+
|
12
|
+
There's a way to define a custom keyword list in a buffer. Research
|
13
|
+
that and handle it.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
KEYWORDS
|
2
|
+
|
3
|
+
By default, I don't want keywords exported to textile.
|
4
|
+
|
5
|
+
h1. Recognize standard keywords
|
6
|
+
|
7
|
+
The standard @orgmode@ keywords are TODO and DONE. Recognize those.
|
8
|
+
|
9
|
+
h1. Recongize buffer-specific keywords
|
10
|
+
|
11
|
+
There's a way to define a custom keyword list in a buffer. Research that and handle it.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
LINKS
|
2
|
+
|
3
|
+
"http://www.bing.com":http://www.bing.com
|
4
|
+
|
5
|
+
h1. Supported Link Styles
|
6
|
+
|
7
|
+
* "http://www.hotmail.com":http://www.hotmail.com => Simple
|
8
|
+
* "Hotmail":http://www.hotmail.com => With link text
|
9
|
+
* "with spaces":http://url/with%20spaces
|
10
|
+
* "http://url/with spaces":http://url/with%20spaces
|
@@ -0,0 +1,36 @@
|
|
1
|
+
* Lists
|
2
|
+
|
3
|
+
I want to make sure I have great support for lists.
|
4
|
+
|
5
|
+
- This is an unordered list
|
6
|
+
- This continues the unordered list
|
7
|
+
|
8
|
+
And this is a paragraph *after* the list.
|
9
|
+
|
10
|
+
** Wrapping within the list
|
11
|
+
|
12
|
+
- This is a single-line list item in the org file.
|
13
|
+
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
|
14
|
+
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
|
15
|
+
erat, sed diam voluptua. At vero eos et accusam et justo duo
|
16
|
+
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
|
17
|
+
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit
|
18
|
+
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
|
19
|
+
invidunt ut labore et dolore magna aliquyam erat, sed diam
|
20
|
+
voluptua. At vero eos et accusam et justo duo dolores et ea
|
21
|
+
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
|
22
|
+
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
|
23
|
+
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
|
24
|
+
invidunt ut labore et dolore magna aliquyam erat, sed diam
|
25
|
+
voluptua. At vero eos et accusam et justo duo dolores et ea
|
26
|
+
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
|
27
|
+
Lorem ipsum dolor sit amet.
|
28
|
+
- And this is the next item. The previous item needs to be on one
|
29
|
+
line to keep =textile= happy.
|
30
|
+
- Ditto the previous line, actually.
|
31
|
+
|
32
|
+
** Edge cases
|
33
|
+
|
34
|
+
- This is a single-line list.
|
35
|
+
And this is a *separate paragraph.* Note the indentation in the org
|
36
|
+
file.
|