flannel 0.2.1 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/features/fixtures/preformatted.flannel +2 -1
- data/features/fixtures/preformatted.out +2 -1
- data/flannel.gemspec +14 -14
- data/lib/flannel.rb +10 -1
- data/lib/flannel/block_cutter.rb +34 -0
- data/lib/flannel/cutting_board.rb +3 -7
- data/lib/flannel/feed_parser.rb +14 -10
- data/lib/flannel/html_formatter.rb +105 -0
- data/lib/flannel/text_block.rb +41 -0
- data/test/{shears_test.rb → block_cutter_test.rb} +7 -7
- data/test/cutting_board_test.rb +0 -5
- data/test/flannel_test.rb +6 -0
- data/test/html_formatter_test.rb +80 -0
- data/test/text_block_test.rb +64 -0
- metadata +11 -11
- data/lib/flannel/shears.rb +0 -89
- data/lib/flannel/square.rb +0 -92
- data/lib/flannel/stripe.rb +0 -77
- data/test/square_test.rb +0 -102
- data/test/stripe_test.rb +0 -126
data/VERSION.yml
CHANGED
data/flannel.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{flannel}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jamal Hansen"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-25}
|
13
13
|
s.email = %q{jamal.hansen@gmail.com}
|
14
14
|
s.executables = ["quilt-it~", "quilt-it"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -50,22 +50,22 @@ Gem::Specification.new do |s|
|
|
50
50
|
"features/wiki_links.feature",
|
51
51
|
"flannel.gemspec",
|
52
52
|
"lib/flannel.rb",
|
53
|
+
"lib/flannel/block_cutter.rb",
|
53
54
|
"lib/flannel/cache_location_does_not_exist_error.rb",
|
54
55
|
"lib/flannel/cutting_board.rb",
|
55
56
|
"lib/flannel/feed_parser.rb",
|
56
57
|
"lib/flannel/file_cache.rb",
|
57
|
-
"lib/flannel/
|
58
|
-
"lib/flannel/
|
59
|
-
"lib/flannel/stripe.rb",
|
58
|
+
"lib/flannel/html_formatter.rb",
|
59
|
+
"lib/flannel/text_block.rb",
|
60
60
|
"lib/flannel/wrappable.rb",
|
61
|
+
"test/block_cutter_test.rb",
|
61
62
|
"test/cutting_board_test.rb",
|
62
63
|
"test/feed_parser_test.rb",
|
63
64
|
"test/file_cache_test.rb",
|
64
65
|
"test/flannel_test.rb",
|
65
|
-
"test/
|
66
|
-
"test/
|
67
|
-
"test/
|
68
|
-
"test/test_helper.rb"
|
66
|
+
"test/html_formatter_test.rb",
|
67
|
+
"test/test_helper.rb",
|
68
|
+
"test/text_block_test.rb"
|
69
69
|
]
|
70
70
|
s.homepage = %q{http://github.com/rubyyot/flannel}
|
71
71
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -74,14 +74,14 @@ Gem::Specification.new do |s|
|
|
74
74
|
s.rubygems_version = %q{1.3.5}
|
75
75
|
s.summary = %q{A soft comfortable worn in markup language for Ruby}
|
76
76
|
s.test_files = [
|
77
|
-
"test/
|
77
|
+
"test/html_formatter_test.rb",
|
78
|
+
"test/block_cutter_test.rb",
|
79
|
+
"test/test_helper.rb",
|
78
80
|
"test/file_cache_test.rb",
|
79
|
-
"test/stripe_test.rb",
|
80
81
|
"test/cutting_board_test.rb",
|
82
|
+
"test/text_block_test.rb",
|
81
83
|
"test/feed_parser_test.rb",
|
82
|
-
"test/flannel_test.rb"
|
83
|
-
"test/square_test.rb",
|
84
|
-
"test/shears_test.rb"
|
84
|
+
"test/flannel_test.rb"
|
85
85
|
]
|
86
86
|
|
87
87
|
if s.respond_to? :specification_version then
|
data/lib/flannel.rb
CHANGED
@@ -6,10 +6,19 @@ require 'flannel/stripe'
|
|
6
6
|
require 'flannel/feed_parser'
|
7
7
|
require 'flannel/file_cache'
|
8
8
|
|
9
|
+
require 'flannel/block_cutter'
|
10
|
+
require 'flannel/text_block'
|
11
|
+
require 'flannel/html_formatter'
|
12
|
+
|
9
13
|
module Flannel
|
10
14
|
def self.quilt markup, params={}
|
15
|
+
@@cache_params = params
|
11
16
|
return nil unless markup
|
12
|
-
shears = Flannel::CuttingBoard.new
|
17
|
+
shears = Flannel::CuttingBoard.new
|
13
18
|
shears.cut markup
|
14
19
|
end
|
20
|
+
|
21
|
+
def self.cache_params
|
22
|
+
@@cache_params
|
23
|
+
end
|
15
24
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Flannel
|
2
|
+
class BlockCutter
|
3
|
+
def cut markup
|
4
|
+
pieces = split_preformatted_blocks(markup)
|
5
|
+
pieces = pieces.map { |part| split_into_blocks(part) }
|
6
|
+
pieces.flatten!
|
7
|
+
convert_to_text_blocks pieces
|
8
|
+
end
|
9
|
+
|
10
|
+
def split_into_blocks markup
|
11
|
+
if is_preformatted markup
|
12
|
+
markup
|
13
|
+
else
|
14
|
+
markup.split(/\n\s*?\n/).map { |s| s.strip }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def split_preformatted_blocks markup
|
19
|
+
markup.split(/^(_(?=\n\n)|(?=_))/).map { |s| s.strip }.reject { |s| is_invalid_block s}
|
20
|
+
end
|
21
|
+
|
22
|
+
def convert_to_text_blocks pieces
|
23
|
+
pieces.map{ |piece| Flannel::TextBlock.new piece }
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_invalid_block s
|
27
|
+
s == "" || s == "_"
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_preformatted markup
|
31
|
+
markup[0] == '_'[0]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,14 +1,10 @@
|
|
1
1
|
|
2
2
|
module Flannel
|
3
3
|
class CuttingBoard
|
4
|
-
def initialize params={}
|
5
|
-
@params = params
|
6
|
-
end
|
7
|
-
|
8
4
|
def cut markup
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
cutter = Flannel::BlockCutter.new
|
6
|
+
text_blocks = cutter.cut markup
|
7
|
+
text_blocks.map { |text| text.to_h }.join("\n\n")
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
data/lib/flannel/feed_parser.rb
CHANGED
@@ -19,9 +19,7 @@ module Flannel
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def get_document url
|
22
|
-
doc =
|
23
|
-
doc = open(url) unless doc
|
24
|
-
@cache.save url, doc if @cache
|
22
|
+
doc = open(url)
|
25
23
|
doc
|
26
24
|
end
|
27
25
|
|
@@ -30,14 +28,20 @@ module Flannel
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def get_news url
|
33
|
-
item_string =
|
34
|
-
|
35
|
-
|
31
|
+
item_string = nil
|
32
|
+
item_string = @cache.retrieve(url) if @cache
|
33
|
+
|
34
|
+
unless item_string
|
35
|
+
item_string = ""
|
36
|
+
doc = Hpricot.XML(get_document(url))
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
(doc/"item").each do |item|
|
39
|
+
link = (item/"link").inner_html
|
40
|
+
title = (item/"title").inner_html
|
41
|
+
item_string << format_item(link, title)
|
42
|
+
end
|
43
|
+
|
44
|
+
@cache.save url, item_string if @cache
|
41
45
|
end
|
42
46
|
|
43
47
|
item_string
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Flannel
|
2
|
+
class HtmlFormatter
|
3
|
+
include Wrappable
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@tags ={:preformatted => "pre", :feed => "ul", :list => "ul", :header_1 => "h1", :header_2 => "h2", :header_3 => "h3", :header_4 => "h4", :header_5 => "h5", :header_6 => "h6", :paragraph => "p"}
|
7
|
+
end
|
8
|
+
|
9
|
+
def do text, style
|
10
|
+
steps = get_steps_for style
|
11
|
+
inject text, steps
|
12
|
+
end
|
13
|
+
|
14
|
+
def permalink topic
|
15
|
+
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def inject text, steps
|
19
|
+
if steps.empty?
|
20
|
+
text
|
21
|
+
else
|
22
|
+
step = steps.shift
|
23
|
+
text = step.call text
|
24
|
+
inject text, steps
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_steps_for style
|
29
|
+
steps = []
|
30
|
+
|
31
|
+
case style
|
32
|
+
|
33
|
+
when :preformatted
|
34
|
+
steps << lambda { |text| html_escape text}
|
35
|
+
when :feed
|
36
|
+
steps << lambda { |text| parse_feed text }
|
37
|
+
else
|
38
|
+
steps << lambda { |text| build_wiki_links text }
|
39
|
+
steps << lambda { |text| convert_external_links text }
|
40
|
+
end
|
41
|
+
|
42
|
+
if style == :list
|
43
|
+
steps << lambda { |text| format_list text }
|
44
|
+
end
|
45
|
+
|
46
|
+
steps << lambda { |text| wrap text, @tags[style]}
|
47
|
+
|
48
|
+
steps
|
49
|
+
end
|
50
|
+
|
51
|
+
def html_escape text
|
52
|
+
require 'cgi'
|
53
|
+
|
54
|
+
CGI::escapeHTML(text)
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_wiki_links text
|
58
|
+
text.gsub(/-\w(.*?)\w>/) { |match| %{<a href="#{wiki_link match}">#{format_link_display(match)}</a>}}
|
59
|
+
end
|
60
|
+
|
61
|
+
def wiki_link topic
|
62
|
+
permalink topic[1..-2]
|
63
|
+
end
|
64
|
+
|
65
|
+
def permalink topic
|
66
|
+
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def format_link_display text
|
70
|
+
text[1..-2].split("/").last
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_external_links text
|
74
|
+
text.gsub(/\[([^\|]*\|[^\]]*)\]/) { |match| build_external_link match }
|
75
|
+
end
|
76
|
+
|
77
|
+
def build_external_link match
|
78
|
+
text, url, title = match[1..-2].split("|", 3)
|
79
|
+
|
80
|
+
url = format_link url.strip
|
81
|
+
text.strip!
|
82
|
+
title.strip! if title
|
83
|
+
|
84
|
+
if title
|
85
|
+
%{<a href="#{url}" title="#{title}" target="_blank">#{text}</a>}
|
86
|
+
else
|
87
|
+
%{<a href="#{url}" target="_blank">#{text}</a>}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def format_link url
|
92
|
+
return url if /:\/\// =~ url
|
93
|
+
"http://#{url}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def format_list text
|
97
|
+
text.split(/^\*/).reject { |item| item == "" }.map { |item| wrap(item.chomp, "li") }.join("\n")
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_feed text
|
101
|
+
parser = Flannel::FeedParser.new Flannel.cache_params
|
102
|
+
parser.sub_feeds text
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Flannel
|
2
|
+
class TextBlock
|
3
|
+
attr_reader :style
|
4
|
+
|
5
|
+
def initialize text
|
6
|
+
set_style_marker text
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
@text
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
html_formatter = Flannel::HtmlFormatter.new
|
15
|
+
html_formatter.do(@text, @style)
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_style_marker text
|
19
|
+
case text[0]
|
20
|
+
when '_'[0] #preformatted
|
21
|
+
@style = :preformatted
|
22
|
+
@text = text[1..-1]
|
23
|
+
when '&'[0] #feed
|
24
|
+
@style = :feed
|
25
|
+
@text = text[1..-1]
|
26
|
+
when '*'[0] #list
|
27
|
+
@style = :list
|
28
|
+
@text = text
|
29
|
+
when '='[0] #header
|
30
|
+
match = text.match /^(=+)/
|
31
|
+
weight = match.captures[0].length
|
32
|
+
|
33
|
+
@style = "header_#{weight}".to_sym
|
34
|
+
@text = text[weight..-1]
|
35
|
+
else #other
|
36
|
+
@style = :paragraph
|
37
|
+
@text = text
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class BlockCutterTest < Test::Unit::TestCase
|
4
4
|
context "basic behavior" do
|
5
5
|
setup do
|
6
|
-
@
|
6
|
+
@block_cutter = Flannel::BlockCutter.new
|
7
7
|
end
|
8
8
|
|
9
9
|
should "split a flannel document into squares based on blank lines" do
|
10
10
|
markup = "foo\n\nbar"
|
11
11
|
|
12
|
-
squares = @
|
12
|
+
squares = @block_cutter.cut markup
|
13
13
|
assert_equal 2, squares.length
|
14
14
|
assert_equal "foo", squares[0].to_s
|
15
15
|
assert_equal "bar", squares[1].to_s
|
@@ -18,7 +18,7 @@ class ShearsTest < Test::Unit::TestCase
|
|
18
18
|
should "not split preformatted text based on blank lines" do
|
19
19
|
markup = "_foo\n\nbar\n_"
|
20
20
|
|
21
|
-
squares = @
|
21
|
+
squares = @block_cutter.cut markup
|
22
22
|
assert_equal 1, squares.length
|
23
23
|
assert_equal :preformatted, squares[0].style
|
24
24
|
end
|
@@ -27,7 +27,7 @@ class ShearsTest < Test::Unit::TestCase
|
|
27
27
|
should "separate preformatted blocks" do
|
28
28
|
markup = "_foo\n_\n\n_bar\n_"
|
29
29
|
|
30
|
-
squares = @
|
30
|
+
squares = @block_cutter.cut markup
|
31
31
|
assert_equal 2, squares.length
|
32
32
|
assert_equal :preformatted, squares[0].style
|
33
33
|
assert_equal :preformatted, squares[1].style
|
@@ -36,14 +36,14 @@ class ShearsTest < Test::Unit::TestCase
|
|
36
36
|
should "strip preformatted markers when found" do
|
37
37
|
markup = "_foo\n\nbar\n_"
|
38
38
|
|
39
|
-
squares = @
|
39
|
+
squares = @block_cutter.cut markup
|
40
40
|
assert_equal "foo\n\nbar", squares[0].to_s
|
41
41
|
end
|
42
42
|
|
43
43
|
should "set square style to feed based on ampersand " do
|
44
44
|
markup = "& http://www.example.com/rss"
|
45
45
|
|
46
|
-
squares = @
|
46
|
+
squares = @block_cutter.cut markup
|
47
47
|
assert_equal :feed, squares[0].style
|
48
48
|
end
|
49
49
|
end
|
data/test/cutting_board_test.rb
CHANGED
@@ -11,11 +11,6 @@ class CuttingBoardTest < Test::Unit::TestCase
|
|
11
11
|
assert_equal "<pre>foo\n\n bar</pre>", @board.cut(markup)
|
12
12
|
end
|
13
13
|
|
14
|
-
should "preformat text when both start and end line have the markers" do
|
15
|
-
markup = "_foo\n\n_ bar"
|
16
|
-
assert_equal "<pre>foo\n\n bar</pre>", @board.cut(markup)
|
17
|
-
end
|
18
|
-
|
19
14
|
should "not replace in preformatted text" do
|
20
15
|
markup = "_4 - 2 > 2 - 2\n_"
|
21
16
|
assert_equal '<pre>4 - 2 > 2 - 2</pre>', @board.cut(markup)
|
data/test/flannel_test.rb
CHANGED
@@ -9,4 +9,10 @@ class FlannelTest < Test::Unit::TestCase
|
|
9
9
|
should "return nil if text is nil" do
|
10
10
|
assert_nil Flannel.quilt(nil)
|
11
11
|
end
|
12
|
+
|
13
|
+
should "parse paragraphs correctly" do
|
14
|
+
input = "\nThis is paragraph one.\n\nThis is paragraph two.\n\nThis is paragraph three. Watchout for the end of file.\n"
|
15
|
+
output = "<p>This is paragraph one.</p>\n\n<p>This is paragraph two.</p>\n\n<p>This is paragraph three. Watchout for the end of file.</p>"
|
16
|
+
assert_equal output, Flannel.quilt(input)
|
17
|
+
end
|
12
18
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'flannel/stripe'
|
3
|
+
|
4
|
+
class HtmlFormatterTest < Test::Unit::TestCase
|
5
|
+
context "basic operations" do
|
6
|
+
setup do
|
7
|
+
@formatter = Flannel::HtmlFormatter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return html fragment with format" do
|
11
|
+
assert_equal "<p>foo</p>", @formatter.do('foo', :paragraph)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "building wiki links" do
|
15
|
+
should "not be greedy in matching" do
|
16
|
+
result = @formatter.do "a -foo> and a -bar>.", :paragraph
|
17
|
+
assert_equal '<p>a <a href="foo">foo</a> and a <a href="bar">bar</a>.</p>', result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "subdirectories" do
|
22
|
+
should "handle subdirectories and not display directory info" do
|
23
|
+
result = @formatter.do("I think it -cheese/tastes good>.", :paragraph)
|
24
|
+
assert_equal '<p>I think it <a href="cheese/tastes-good">tastes good</a>.</p>', result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "links" do
|
29
|
+
should "output the link" do
|
30
|
+
assert_equal '<p><a href="cheese">cheese</a></p>', @formatter.do("-cheese>", :paragraph)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "hyphenate words" do
|
34
|
+
result = @formatter.do("-cheese is good>", :paragraph)
|
35
|
+
assert_equal '<p><a href="cheese-is-good">cheese is good</a></p>', result
|
36
|
+
end
|
37
|
+
|
38
|
+
should "replace text surrounded by - and > with a wiki link" do
|
39
|
+
result = @formatter.do("red, -green>, refactor", :paragraph)
|
40
|
+
assert_equal '<p>red, <a href="green">green</a>, refactor</p>',result
|
41
|
+
end
|
42
|
+
|
43
|
+
should "not replace text surrounded by - and > with a wiki link if spaced" do
|
44
|
+
result = @formatter.do("red, - green >, refactor", :paragraph)
|
45
|
+
assert_equal '<p>red, - green >, refactor</p>', result
|
46
|
+
end
|
47
|
+
|
48
|
+
should "not replace text surrounded by - and > with a wiki link if spaced on right" do
|
49
|
+
result = @formatter.do("red, -green >, refactor", :paragraph)
|
50
|
+
assert_equal '<p>red, -green >, refactor</p>', result
|
51
|
+
end
|
52
|
+
|
53
|
+
should "not replace surrounded by - and > with a wiki link if spaced on left" do
|
54
|
+
result = @formatter.do("red, - green>, refactor", :paragraph)
|
55
|
+
assert_equal '<p>red, - green>, refactor</p>', result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "preformatted text" do
|
60
|
+
should "html escape preformatted text" do
|
61
|
+
result = @formatter.do("<p>& foo</p>", :preformatted)
|
62
|
+
assert_equal "<pre><p>& foo</p></pre>", result
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "making permalinks" do
|
67
|
+
should "replace spaces with dashes" do
|
68
|
+
assert_equal "get-the-box", @formatter.permalink("get the box")
|
69
|
+
end
|
70
|
+
|
71
|
+
should "replace multiple spaces with single dashes" do
|
72
|
+
assert_equal "get-the-box", @formatter.permalink("get the box")
|
73
|
+
end
|
74
|
+
|
75
|
+
should "replace odd characters with dashes" do
|
76
|
+
assert_equal "get-the-box", @formatter.permalink("get the @#)(* box")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TextBlockTest < Test::Unit::TestCase
|
4
|
+
context "basic behavior" do
|
5
|
+
should "return html" do
|
6
|
+
text_block = Flannel::TextBlock.new "foo"
|
7
|
+
assert_equal "<p>foo</p>", text_block.to_h
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "style" do
|
12
|
+
should "recognize preformatted" do
|
13
|
+
text_block = Flannel::TextBlock.new "_foo"
|
14
|
+
assert_equal :preformatted, text_block.style
|
15
|
+
end
|
16
|
+
|
17
|
+
should "recognize paragraph" do
|
18
|
+
text_block = Flannel::TextBlock.new "foo"
|
19
|
+
assert_equal :paragraph, text_block.style
|
20
|
+
end
|
21
|
+
|
22
|
+
should "recognize list" do
|
23
|
+
text_block = Flannel::TextBlock.new "* foo/n* bar/n* baz"
|
24
|
+
assert_equal :list, text_block.style
|
25
|
+
end
|
26
|
+
|
27
|
+
should "recognize feed" do
|
28
|
+
text_block = Flannel::TextBlock.new "& http://foo.example.com"
|
29
|
+
assert_equal :feed, text_block.style
|
30
|
+
end
|
31
|
+
|
32
|
+
should "recognize header" do
|
33
|
+
text_block = Flannel::TextBlock.new "====My Header"
|
34
|
+
assert_equal :header_4, text_block.style
|
35
|
+
end
|
36
|
+
|
37
|
+
should "wrap in pre tags when preformatted" do
|
38
|
+
text_block = Flannel::TextBlock.new "_foo"
|
39
|
+
assert_equal "<pre>foo</pre>", text_block.to_h
|
40
|
+
end
|
41
|
+
|
42
|
+
should "wrap in ul tags when unordered_list" do
|
43
|
+
text_block = Flannel::TextBlock.new "* foo"
|
44
|
+
assert_equal "<ul><li>foo</li></ul>", text_block.to_h
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "external links" do
|
49
|
+
should "convert [|] pattern to an external link" do
|
50
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|http://example.com] yadda"
|
51
|
+
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
52
|
+
end
|
53
|
+
|
54
|
+
should "add http:// to external links" do
|
55
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|example.com] yadda"
|
56
|
+
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
57
|
+
end
|
58
|
+
|
59
|
+
should "add create title if provided to external links" do
|
60
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|example.com|My title] yadda"
|
61
|
+
assert_equal '<p>yadda <a href="http://example.com" title="My title" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flannel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamal Hansen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-25 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -76,22 +76,22 @@ files:
|
|
76
76
|
- features/wiki_links.feature
|
77
77
|
- flannel.gemspec
|
78
78
|
- lib/flannel.rb
|
79
|
+
- lib/flannel/block_cutter.rb
|
79
80
|
- lib/flannel/cache_location_does_not_exist_error.rb
|
80
81
|
- lib/flannel/cutting_board.rb
|
81
82
|
- lib/flannel/feed_parser.rb
|
82
83
|
- lib/flannel/file_cache.rb
|
83
|
-
- lib/flannel/
|
84
|
-
- lib/flannel/
|
85
|
-
- lib/flannel/stripe.rb
|
84
|
+
- lib/flannel/html_formatter.rb
|
85
|
+
- lib/flannel/text_block.rb
|
86
86
|
- lib/flannel/wrappable.rb
|
87
|
+
- test/block_cutter_test.rb
|
87
88
|
- test/cutting_board_test.rb
|
88
89
|
- test/feed_parser_test.rb
|
89
90
|
- test/file_cache_test.rb
|
90
91
|
- test/flannel_test.rb
|
91
|
-
- test/
|
92
|
-
- test/square_test.rb
|
93
|
-
- test/stripe_test.rb
|
92
|
+
- test/html_formatter_test.rb
|
94
93
|
- test/test_helper.rb
|
94
|
+
- test/text_block_test.rb
|
95
95
|
has_rdoc: true
|
96
96
|
homepage: http://github.com/rubyyot/flannel
|
97
97
|
licenses: []
|
@@ -121,11 +121,11 @@ signing_key:
|
|
121
121
|
specification_version: 3
|
122
122
|
summary: A soft comfortable worn in markup language for Ruby
|
123
123
|
test_files:
|
124
|
+
- test/html_formatter_test.rb
|
125
|
+
- test/block_cutter_test.rb
|
124
126
|
- test/test_helper.rb
|
125
127
|
- test/file_cache_test.rb
|
126
|
-
- test/stripe_test.rb
|
127
128
|
- test/cutting_board_test.rb
|
129
|
+
- test/text_block_test.rb
|
128
130
|
- test/feed_parser_test.rb
|
129
131
|
- test/flannel_test.rb
|
130
|
-
- test/square_test.rb
|
131
|
-
- test/shears_test.rb
|
data/lib/flannel/shears.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
#require 'square'
|
2
|
-
#require 'stripe'
|
3
|
-
|
4
|
-
module Flannel
|
5
|
-
class Shears
|
6
|
-
def initialize params={}
|
7
|
-
@params = params
|
8
|
-
end
|
9
|
-
|
10
|
-
def cut markup
|
11
|
-
@squares = []
|
12
|
-
@square = Flannel::Square.new
|
13
|
-
@end_preformat = false
|
14
|
-
|
15
|
-
markup.split("\n").each { |line| cut_into_squares line }
|
16
|
-
|
17
|
-
@squares << @square
|
18
|
-
end
|
19
|
-
|
20
|
-
def cut_into_squares line
|
21
|
-
if need_new_square? line
|
22
|
-
shift_square
|
23
|
-
else
|
24
|
-
add line
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def shift_square
|
29
|
-
@squares << @square unless @square.blank?
|
30
|
-
@square = Flannel::Square.new @params
|
31
|
-
end
|
32
|
-
|
33
|
-
def need_new_square? line
|
34
|
-
@square.style == :preformatted ? @end_preformat : empty?(line.strip)
|
35
|
-
end
|
36
|
-
|
37
|
-
def add line
|
38
|
-
@preformatted_marker_line = false
|
39
|
-
line = strip_markers line
|
40
|
-
line = remove_hanging_preformatted_lines line
|
41
|
-
|
42
|
-
@square << line unless line.nil?
|
43
|
-
end
|
44
|
-
|
45
|
-
def remove_hanging_preformatted_lines line
|
46
|
-
if @preformatted_marker_line
|
47
|
-
@end_preformat = @square.populated?
|
48
|
-
if line.strip == ""
|
49
|
-
return nil
|
50
|
-
end
|
51
|
-
else
|
52
|
-
@end_preformat = false
|
53
|
-
end
|
54
|
-
line
|
55
|
-
end
|
56
|
-
|
57
|
-
def strip_markers line
|
58
|
-
parts = line.match(/^([=_*&]+)(.*)/)
|
59
|
-
|
60
|
-
if parts
|
61
|
-
set_style parts[1]
|
62
|
-
line = parts[2]
|
63
|
-
end
|
64
|
-
line
|
65
|
-
end
|
66
|
-
|
67
|
-
def set_style marker
|
68
|
-
if marker
|
69
|
-
case marker[0]
|
70
|
-
when 61 # equals (header)
|
71
|
-
style = "header_#{marker.length}"
|
72
|
-
@square.style = style.to_sym
|
73
|
-
when 95 # underscore (preformatted)
|
74
|
-
@square.style = :preformatted
|
75
|
-
@preformatted_marker_line = true
|
76
|
-
when 42 # star (list)
|
77
|
-
@square.style = :list
|
78
|
-
when 38 # ampersand (feed)
|
79
|
-
@square.style = :feed
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def empty? str
|
85
|
-
str.nil? || str == ""
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
data/lib/flannel/square.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
#require 'wrappable'
|
2
|
-
|
3
|
-
module Flannel
|
4
|
-
class Square
|
5
|
-
include Flannel::Wrappable
|
6
|
-
attr_accessor :style
|
7
|
-
|
8
|
-
def initialize params={}
|
9
|
-
@tags ={:preformatted => "pre", :feed => "ul", :list => "ul", :header_1 => "h1", :header_2 => "h2", :header_3 => "h3", :header_4 => "h4", :header_5 => "h5", :header_6 => "h6"}
|
10
|
-
@stripes = []
|
11
|
-
@style = :paragraph
|
12
|
-
@params = params
|
13
|
-
end
|
14
|
-
|
15
|
-
def << text
|
16
|
-
text = text.strip unless @style == :preformatted
|
17
|
-
@params[:style] = @style
|
18
|
-
@stripes << Flannel::Stripe.stitch(text, @params.dup)
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
@stripes.map { |stripe| stripe.weave }.join("\n")
|
23
|
-
end
|
24
|
-
|
25
|
-
def blank?
|
26
|
-
(@stripes.length == 0 || all_stripes_blank)
|
27
|
-
end
|
28
|
-
|
29
|
-
def populated?
|
30
|
-
!blank?
|
31
|
-
end
|
32
|
-
|
33
|
-
def all_stripes_blank
|
34
|
-
@stripes.each do |stripe|
|
35
|
-
return false if !stripe.empty?
|
36
|
-
end
|
37
|
-
|
38
|
-
return true
|
39
|
-
end
|
40
|
-
|
41
|
-
def to_h
|
42
|
-
@post_wrap = nil
|
43
|
-
lines = @stripes.map { |stripe| stripe.to_h }
|
44
|
-
|
45
|
-
quilt lines
|
46
|
-
end
|
47
|
-
|
48
|
-
def quilt lines
|
49
|
-
output = lines.join("\n")
|
50
|
-
output = convert_external_links output
|
51
|
-
return wrap(output, find_tag)
|
52
|
-
end
|
53
|
-
|
54
|
-
def preformatted
|
55
|
-
@style == :preformatted
|
56
|
-
end
|
57
|
-
|
58
|
-
def convert_external_links text
|
59
|
-
return text if preformatted
|
60
|
-
text.gsub(/\[([^\|]*\|[^\]]*)\]/) { |match| build_external_link match }
|
61
|
-
end
|
62
|
-
|
63
|
-
def build_external_link match
|
64
|
-
text, url, title = match[1..-2].split("|", 3)
|
65
|
-
|
66
|
-
url = format_link url.strip
|
67
|
-
text.strip!
|
68
|
-
title.strip! if title
|
69
|
-
|
70
|
-
if title
|
71
|
-
%{<a href="#{url}" title="#{title}" target="_blank">#{text}</a>}
|
72
|
-
else
|
73
|
-
%{<a href="#{url}" target="_blank">#{text}</a>}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def format_link url
|
78
|
-
return url if /:\/\// =~ url
|
79
|
-
"http://#{url}"
|
80
|
-
end
|
81
|
-
|
82
|
-
def find_tag
|
83
|
-
if @style && @tags.has_key?(@style)
|
84
|
-
tag = @tags[@style]
|
85
|
-
else
|
86
|
-
tag = "p"
|
87
|
-
end
|
88
|
-
tag
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
data/lib/flannel/stripe.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
|
2
|
-
module Flannel
|
3
|
-
class Stripe
|
4
|
-
include Wrappable
|
5
|
-
attr_reader :weave
|
6
|
-
|
7
|
-
def self.stitch weave="", params={}
|
8
|
-
Flannel::Stripe.new weave, params
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize weave="", params={}
|
12
|
-
@weave = weave
|
13
|
-
@params = params
|
14
|
-
end
|
15
|
-
|
16
|
-
def wiki_link topic
|
17
|
-
if @params[:wiki_link]
|
18
|
-
@params[:wiki_link].call(permalink topic)
|
19
|
-
else
|
20
|
-
permalink topic[1..-2]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def permalink topic
|
25
|
-
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
26
|
-
end
|
27
|
-
|
28
|
-
def empty?
|
29
|
-
@weave == nil || @weave.strip == ""
|
30
|
-
end
|
31
|
-
|
32
|
-
def build_wiki_links
|
33
|
-
return @weave if preformatted
|
34
|
-
@weave.gsub(/-\w(.*?)\w>/) { |match| %{<a href="#{wiki_link match}">#{format_link_display(match)}</a>}}
|
35
|
-
end
|
36
|
-
|
37
|
-
def format_link_display text
|
38
|
-
text[1..-2].split("/").last
|
39
|
-
end
|
40
|
-
|
41
|
-
def to_h
|
42
|
-
|
43
|
-
if feed
|
44
|
-
parser = Flannel::FeedParser.new @params
|
45
|
-
parser.sub_feeds @weave
|
46
|
-
else
|
47
|
-
text = build_wiki_links
|
48
|
-
markup text
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def preformatted
|
53
|
-
@params[:style] == :preformatted
|
54
|
-
end
|
55
|
-
|
56
|
-
def list
|
57
|
-
@params[:style] == :list
|
58
|
-
end
|
59
|
-
|
60
|
-
def feed
|
61
|
-
@params[:style] == :feed
|
62
|
-
end
|
63
|
-
|
64
|
-
def markup text
|
65
|
-
return html_escape text if preformatted
|
66
|
-
|
67
|
-
tag = "li" if list
|
68
|
-
wrap(text, tag)
|
69
|
-
end
|
70
|
-
|
71
|
-
def html_escape text
|
72
|
-
require 'cgi'
|
73
|
-
|
74
|
-
CGI::escapeHTML(text)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
data/test/square_test.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class SquareTest < Test::Unit::TestCase
|
4
|
-
context "basic behavior" do
|
5
|
-
setup do
|
6
|
-
@square = Flannel::Square.new
|
7
|
-
end
|
8
|
-
|
9
|
-
should "accept strings with <<" do
|
10
|
-
@square << "foo"
|
11
|
-
assert_equal "foo", @square.to_s
|
12
|
-
end
|
13
|
-
|
14
|
-
should "be blank when there are no stripes" do
|
15
|
-
assert @square.blank?
|
16
|
-
@square << "foo"
|
17
|
-
assert !@square.blank?
|
18
|
-
end
|
19
|
-
|
20
|
-
should "be blank when the first stripe is an empty string" do
|
21
|
-
@square << ""
|
22
|
-
assert @square.blank?
|
23
|
-
end
|
24
|
-
|
25
|
-
should "be blank when the first stripe is whitespace" do
|
26
|
-
@square << " "
|
27
|
-
assert @square.blank?
|
28
|
-
end
|
29
|
-
|
30
|
-
should "be blank when the all stripes are empty strings" do
|
31
|
-
@square << ""
|
32
|
-
@square << ""
|
33
|
-
@square << ""
|
34
|
-
assert @square.blank?
|
35
|
-
end
|
36
|
-
|
37
|
-
should "be blank when the all stripes are whitespace" do
|
38
|
-
@square << " "
|
39
|
-
@square << " "
|
40
|
-
@square << ""
|
41
|
-
assert @square.blank?
|
42
|
-
end
|
43
|
-
|
44
|
-
should "not be blank when a stripe is not blank" do
|
45
|
-
@square << " "
|
46
|
-
@square << " "
|
47
|
-
@square << "foo"
|
48
|
-
assert !@square.blank?
|
49
|
-
end
|
50
|
-
|
51
|
-
should "return html" do
|
52
|
-
@square << "foo"
|
53
|
-
assert_equal "<p>foo</p>", @square.to_h
|
54
|
-
end
|
55
|
-
|
56
|
-
should "accept a style" do
|
57
|
-
@square.style = :preformatted
|
58
|
-
assert_equal :preformatted, @square.style
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "style" do
|
63
|
-
should "accept an optional style parameter" do
|
64
|
-
square = Flannel::Square.new
|
65
|
-
square.style = :foo
|
66
|
-
end
|
67
|
-
|
68
|
-
should "wrap in pre tags when preformatted" do
|
69
|
-
square = Flannel::Square.new
|
70
|
-
square.style = :preformatted
|
71
|
-
square << "foo"
|
72
|
-
assert_equal "<pre>foo</pre>", square.to_h
|
73
|
-
end
|
74
|
-
|
75
|
-
should "wrap in ul tags when unordered_list" do
|
76
|
-
square = Flannel::Square.new
|
77
|
-
square.style = :list
|
78
|
-
square << "foo"
|
79
|
-
assert_equal "<ul><li>foo</li></ul>", square.to_h
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "external links" do
|
84
|
-
should "convert [|] pattern to an external link" do
|
85
|
-
square = Flannel::Square.new
|
86
|
-
square << "yadda [yadda|http://example.com] yadda"
|
87
|
-
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', square.to_h
|
88
|
-
end
|
89
|
-
|
90
|
-
should "add http:// to external links" do
|
91
|
-
square = Flannel::Square.new
|
92
|
-
square << "yadda [yadda|example.com] yadda"
|
93
|
-
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', square.to_h
|
94
|
-
end
|
95
|
-
|
96
|
-
should "add create title if provided to external links" do
|
97
|
-
square = Flannel::Square.new
|
98
|
-
square << "yadda [yadda|example.com|My title] yadda"
|
99
|
-
assert_equal '<p>yadda <a href="http://example.com" title="My title" target="_blank">yadda</a> yadda</p>', square.to_h
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/test/stripe_test.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'flannel/stripe'
|
3
|
-
|
4
|
-
class StripeTest < Test::Unit::TestCase
|
5
|
-
context "basic operations" do
|
6
|
-
setup do
|
7
|
-
@stripe = Flannel::Stripe.stitch "foo"
|
8
|
-
end
|
9
|
-
|
10
|
-
should "be of of kind Flannel::Stripe" do
|
11
|
-
assert Flannel::Stripe, @stripe.class
|
12
|
-
end
|
13
|
-
|
14
|
-
should "create instance with stitch" do
|
15
|
-
assert_equal "foo", @stripe.weave
|
16
|
-
end
|
17
|
-
|
18
|
-
should "return html fragment with to_h" do
|
19
|
-
assert_equal "foo", @stripe.to_h
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context "building wiki links" do
|
24
|
-
setup do
|
25
|
-
wiki_link = lambda { |keyword| "http://www.example.com/foo/#{keyword}"}
|
26
|
-
@stripe = Flannel::Stripe.stitch "the -roof is on fire>", :wiki_link => wiki_link
|
27
|
-
end
|
28
|
-
|
29
|
-
should "build wiki links based on a lambda" do
|
30
|
-
assert_equal "http://www.example.com/foo/cheese",
|
31
|
-
@stripe.wiki_link("-cheese>")
|
32
|
-
end
|
33
|
-
|
34
|
-
should "find and replace wiki link markup" do
|
35
|
-
assert_equal 'the <a href="http://www.example.com/foo/roof-is-on-fire">roof is on fire</a>',
|
36
|
-
@stripe.to_h
|
37
|
-
end
|
38
|
-
|
39
|
-
should "permalink topics when making wiki links" do
|
40
|
-
assert_equal "http://www.example.com/foo/cheese-tastes-good",
|
41
|
-
@stripe.wiki_link("-cheese tastes good>")
|
42
|
-
end
|
43
|
-
|
44
|
-
should "not be greedy in matching" do
|
45
|
-
stripe = Flannel::Stripe.stitch("a -foo> and a -bar>.")
|
46
|
-
assert_equal 'a <a href="foo">foo</a> and a <a href="bar">bar</a>.', stripe.build_wiki_links
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "subdirectories" do
|
51
|
-
setup do
|
52
|
-
@stripe = Flannel::Stripe.stitch "I think it -cheese/tastes good>."
|
53
|
-
end
|
54
|
-
|
55
|
-
should "handle subdirectories" do
|
56
|
-
assert_equal "cheese/tastes-good", @stripe.wiki_link("-cheese/tastes good>")
|
57
|
-
end
|
58
|
-
|
59
|
-
should "not display directory info" do
|
60
|
-
assert_equal 'I think it <a href="cheese/tastes-good">tastes good</a>.', @stripe.build_wiki_links
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context "no lambda is provided" do
|
65
|
-
setup do
|
66
|
-
@stripe = Flannel::Stripe.stitch "baz"
|
67
|
-
end
|
68
|
-
|
69
|
-
should "output the wiki text" do
|
70
|
-
assert_equal "cheese", @stripe.wiki_link("-cheese>")
|
71
|
-
end
|
72
|
-
|
73
|
-
should "prermalink the wiki text" do
|
74
|
-
assert_equal "cheese-is-good", @stripe.wiki_link("-cheese is good>")
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "replacing wiki links" do
|
79
|
-
should "replace surrounded by - and > with a wiki link" do
|
80
|
-
stripe = Flannel::Stripe.stitch("red, -green>, refactor")
|
81
|
-
assert_equal 'red, <a href="green">green</a>, refactor', stripe.to_h
|
82
|
-
end
|
83
|
-
|
84
|
-
should "not replace surrounded by - and > with a wiki link if spaced" do
|
85
|
-
stripe = Flannel::Stripe.stitch("red, - green >, refactor")
|
86
|
-
assert_equal 'red, - green >, refactor', stripe.to_h
|
87
|
-
end
|
88
|
-
|
89
|
-
should "not replace surrounded by - and > with a wiki link if spaced on
|
90
|
-
right" do
|
91
|
-
stripe = Flannel::Stripe.stitch("red, -green >, refactor")
|
92
|
-
assert_equal 'red, -green >, refactor', stripe.to_h
|
93
|
-
end
|
94
|
-
|
95
|
-
should "not replace surrounded by - and > with a wiki link if spaced on
|
96
|
-
left" do
|
97
|
-
stripe = Flannel::Stripe.stitch("red, - green>, refactor")
|
98
|
-
assert_equal 'red, - green>, refactor', stripe.to_h
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context "preformatted text" do
|
103
|
-
should "html escape preformatted text" do
|
104
|
-
stripe = Flannel::Stripe.stitch "<p>& foo</p>", :style => :preformatted
|
105
|
-
assert_equal "<p>& foo</p>", stripe.to_h
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context "making permalinks" do
|
110
|
-
setup do
|
111
|
-
@stripe = Flannel::Stripe.stitch ""
|
112
|
-
end
|
113
|
-
|
114
|
-
should "replace spaces with dashes" do
|
115
|
-
assert_equal "get-the-box", @stripe.permalink("get the box")
|
116
|
-
end
|
117
|
-
|
118
|
-
should "replace multiple spaces with single dashes" do
|
119
|
-
assert_equal "get-the-box", @stripe.permalink("get the box")
|
120
|
-
end
|
121
|
-
|
122
|
-
should "replace odd characters with dashes" do
|
123
|
-
assert_equal "get-the-box", @stripe.permalink("get the @#)(* box")
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|