mcbean 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
@@ -1,5 +1,10 @@
1
1
  = Changelog
2
2
 
3
+ == HEAD
4
+
5
+ * <br> elements are converted into newlines (markdown). GH #5
6
+ * <a> elements without an 'href' attribute are not rendered as hyperlinks (markdown). GH #4
7
+
3
8
  == 0.1.0 (2010-03-09)
4
9
 
5
10
  * Happy Birthday!
@@ -3,53 +3,67 @@
3
3
  * http://github.com/flavorjones/mcbean
4
4
  * http://mcbean.heroku.com/
5
5
 
6
- == DESCRIPTION:
6
+ == Description
7
7
 
8
- McBean transforms HTML into Markdown with the help of Loofah and Nokogiri.
8
+ McBean converts HTML into Markdown, and Markdown into HTML (with the
9
+ help of Loofah, Nokogiri and RDiscount).
9
10
 
10
- Its goal is to eventually be able to transform (with the help of other
11
- relevant gems) documents from HTML to Markdown to Textile, and
12
- anything in between. It will be the Sylvester McMonkey McBean of
13
- markup, placing stars onto the bellies of all kinds of document
14
- formats.
11
+ Its goal is to eventually be able to transform documents from HTML to
12
+ Markdown to Textile, and anything in between. It will be the Sylvester
13
+ McMonkey McBean of markup, placing stars onto the bellies of all kinds
14
+ of Sneetchy document formats.
15
15
 
16
16
  "You can't teach a Sneetch."
17
17
 
18
- == FEATURES/PROBLEMS:
18
+ == Features / Problems
19
19
 
20
- * Transforms HTML into Markdown.
20
+ * Transforms HTML into Markdown, and Markdown into HTML.
21
21
  * Doesn't do anything else yet.
22
22
 
23
- == SYNOPSIS:
23
+ == Synopsis
24
24
 
25
- If you have an HTML fragment:
25
+ If you have an HTML fragment, you can convert it into Markdown:
26
26
 
27
- McBean.fragment(your_html_string).to_markdown
27
+ McBean.fragment(your_html).to_markdown
28
28
 
29
- Or if you have an HTML document:
29
+ Or if you have an HTML document, you can convert it into Markdown:
30
30
 
31
- McBean.document(your_html_string).to_markdown
31
+ McBean.document(your_html).to_markdown
32
+
33
+ You can also convert Markdown into HTML (via RDiscount):
34
+
35
+ McBean.markdown(your_markdown).to_html
36
+
37
+ Note that the parameter passed to +fragment+, +document+ and
38
+ +markdown+ can be either a String or an IO.
32
39
 
33
40
  Also, +mcbean+ provides a command-line utility installed into your gem path:
34
41
 
35
42
  $ mcbean /usr/lib/openoffice/licenses/LICENSE_en-GB.html
36
43
  $ mcbean http://daringfireball.net/projects/markdown/syntax
37
44
 
45
+ You can try out McBean at the live demo site: http://mcbean.heroku.com
46
+
38
47
  === Side Note: Fragments vs Documents
39
48
 
40
49
  Generally speaking, if you expect to have a DOCTYPE and a single root
41
50
  \&lt;html\&gt; node, you have a *document*. If you don't expect to
42
51
  have a single root node, you have a *fragment*.
43
52
 
44
- == REQUIREMENTS:
53
+ == Requirements
45
54
 
46
55
  * Loofah 0.4.7 (and thusly Nokogiri)
56
+ * RDiscount 1.3.4
47
57
 
48
- == INSTALL:
58
+ == Install
49
59
 
50
60
  * sudo gem install mcbean
51
61
 
52
- == LICENSE:
62
+ == Shout Outs
63
+
64
+ Thanks to David Loren Parsons and Ryan Tomayko for RDiscount.
65
+
66
+ == License
53
67
 
54
68
  (The MIT License)
55
69
 
data/Rakefile CHANGED
@@ -14,7 +14,9 @@ Hoe.spec 'mcbean' do
14
14
  self.readme_file = "README.rdoc"
15
15
 
16
16
  extra_deps << ["loofah", ">= 0.4.7"]
17
+ extra_deps << ["rdiscount", ">= 1.3.4"]
17
18
  extra_dev_deps << ["shoulda", ">= 2.10"]
19
+ extra_dev_deps << ["rr", ">= 0.10.4"]
18
20
  end
19
21
 
20
22
  task :redocs => :fix_css
@@ -1,7 +1,7 @@
1
1
  require "loofah"
2
2
 
3
3
  class McBean
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  REQUIRED_LOOFAH_VERSION = "0.4.7"
6
6
 
7
7
  attr_accessor :html
@@ -17,6 +17,14 @@ class McBean
17
17
  mcbean.html = Loofah.document(string_or_io)
18
18
  mcbean
19
19
  end
20
+
21
+ def McBean.markdown(string_or_io)
22
+ if string_or_io.respond_to?(:read)
23
+ McBean::Markdownify::Antidote.new(string_or_io.read)
24
+ else
25
+ McBean::Markdownify::Antidote.new(string_or_io)
26
+ end
27
+ end
20
28
  end
21
29
  Mcbean = McBean
22
30
 
@@ -1,6 +1,9 @@
1
- class McBean
1
+ require 'rdiscount'
2
2
 
3
+ class McBean
3
4
  class Markdownify < Loofah::Scrubber
5
+ Antidote = ::RDiscount # could conceivably be BlueCloth
6
+
4
7
  def initialize
5
8
  @direction = :bottom_up
6
9
  @link_references = nil
@@ -43,8 +46,12 @@ class McBean
43
46
  else
44
47
  nil
45
48
  end
49
+ when "br"
50
+ new_text node, "\n"
46
51
  when "a"
47
- if node['title']
52
+ if node['href'].nil?
53
+ new_text node, node.content
54
+ elsif node['title']
48
55
  unless @link_references
49
56
  @link_references = node.document.fragment("<div>\n</div>").children.first
50
57
  end_of_doc(node).add_next_sibling @link_references
@@ -1,6 +1,8 @@
1
1
  require "test/unit"
2
2
  require "mcbean"
3
3
  require "shoulda"
4
+ require "rr"
4
5
 
5
- gem "bluecloth", ">= 2.0"
6
- require "bluecloth"
6
+ class Test::Unit::TestCase
7
+ include RR::Adapters::TestUnit
8
+ end
@@ -1,92 +1,125 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
3
  class TestMcBeanMarkdown < Test::Unit::TestCase
4
- context "markdown" do
5
- should "add whitespace around block elements" do
6
- assert_markdown "before<div>inner</div>after", "before\ninner\nafter", false
7
- end
4
+ context McBean::Markdownify do
5
+ context "#to_markdown" do
6
+ should "add whitespace around block elements" do
7
+ assert_markdown "before<div>inner</div>after", "before\ninner\nafter", false
8
+ end
8
9
 
9
- should "convert h1 tag" do
10
- assert_markdown "<h1>Foo</h1>", "\nFoo\n==========\n"
11
- end
10
+ should "convert h1 tag" do
11
+ assert_markdown "<h1>Foo</h1>", "\nFoo\n==========\n"
12
+ end
12
13
 
13
- should "convert h2 tag" do
14
- assert_markdown "<h2>Foo</h2>", "\nFoo\n----------\n"
15
- end
14
+ should "convert h2 tag" do
15
+ assert_markdown "<h2>Foo</h2>", "\nFoo\n----------\n"
16
+ end
16
17
 
17
- should "convert h3 tag" do
18
- assert_markdown "<h3>Foo</h3>", "\n### Foo ###\n"
19
- end
18
+ should "convert h3 tag" do
19
+ assert_markdown "<h3>Foo</h3>", "\n### Foo ###\n"
20
+ end
20
21
 
21
- should "convert h4 tag" do
22
- assert_markdown "<h4>Foo</h4>", "\n#### Foo ####\n"
23
- end
22
+ should "convert h4 tag" do
23
+ assert_markdown "<h4>Foo</h4>", "\n#### Foo ####\n"
24
+ end
24
25
 
25
- should "convert blockquote tag" do
26
- assert_markdown "<blockquote><p>Hello\nGoodbye</p></blockquote>",
27
- "> Hello\n> Goodbye\n"
28
- end
26
+ should "convert blockquote tag" do
27
+ assert_markdown "<blockquote><p>Hello\nGoodbye</p></blockquote>",
28
+ "> Hello\n> Goodbye\n"
29
+ end
29
30
 
30
- # should "convert nested blockquote tag" do
31
- # assert_markdown(
32
- # "<blockquote><p>Hello</p>\n\n<blockquote><p>Nested</p></blockquote>\n\n<p>Goodbye</p></blockquote>",
33
- # <<-EOM
34
- # > Hello
35
- # >
36
- # > > Nested
37
- # >
38
- # > Goodbye
39
- # EOM
40
- # )
41
- # end
42
-
43
- should "convert unordered list" do
44
- assert_markdown "<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n",
45
- "\n* one\n* two\n* three\n"
46
- end
31
+ # should "convert nested blockquote tag" do
32
+ # assert_markdown(
33
+ # "<blockquote><p>Hello</p>\n\n<blockquote><p>Nested</p></blockquote>\n\n<p>Goodbye</p></blockquote>",
34
+ # <<-EOM
35
+ # > Hello
36
+ # >
37
+ # > > Nested
38
+ # >
39
+ # > Goodbye
40
+ # EOM
41
+ # )
42
+ # end
43
+
44
+ should "convert unordered list" do
45
+ assert_markdown "<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n",
46
+ "\n* one\n* two\n* three\n"
47
+ end
47
48
 
48
- should "convert ordered list" do
49
- assert_markdown "<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n",
50
- "\n1. one\n2. two\n3. three\n"
51
- end
49
+ should "convert ordered list" do
50
+ assert_markdown "<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n",
51
+ "\n1. one\n2. two\n3. three\n"
52
+ end
52
53
 
53
- should "ignore empty unordered list items" do
54
- assert_markdown "<ul>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ul>\n",
55
- "\n* one\n* three\n",
56
- false
57
- end
54
+ should "ignore empty unordered list items" do
55
+ assert_markdown "<ul>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ul>\n",
56
+ "\n* one\n* three\n",
57
+ false
58
+ end
58
59
 
59
- should "ignore empty ordered list items" do
60
- assert_markdown "<ol>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ol>\n",
61
- "\n1. one\n3. three\n",
62
- false
63
- end
60
+ should "ignore empty ordered list items" do
61
+ assert_markdown "<ol>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ol>\n",
62
+ "\n1. one\n3. three\n",
63
+ false
64
+ end
64
65
 
65
- should "convert code blocks" do
66
- assert_markdown "<pre><code>This is a code block\ncontinued\n</code></pre>",
67
- "\n This is a code block\n continued\n\n"
68
- end
66
+ should "convert code blocks" do
67
+ assert_markdown "<pre><code>This is a code block\ncontinued\n</code></pre>",
68
+ "\n This is a code block\n continued\n\n"
69
+ end
69
70
 
70
- context "anchors" do
71
- should "convert <a> tags" do
72
- assert_markdown "<p>Yes, magic helmet. And <a href=\"http://sample.com/\">I'll give you a sample</a>.</p>",
73
- "\nYes, magic helmet. And [I'll give you a sample](http://sample.com/).\n"
71
+ should "convert <br> tags to newlines" do
72
+ assert_markdown "<div>hello<br>there</div>",
73
+ "\nhello\nthere\n",
74
+ false
75
+ assert_markdown "<div>hello<br />there</div>",
76
+ "\nhello\nthere\n",
77
+ false
74
78
  end
75
79
 
76
- context "<a> tags with titles" do
77
- should "convert fq urls to reference-style" do
78
- assert_markdown2 "<p>Yes, magic helmet. And <a href=\"http://sample.com/\" title=\"Fudd\">I'll give you a sample</a>.</p>",
79
- "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: http://sample.com/ \"Fudd\"\n"
80
+ context "anchors" do
81
+ should "convert <a> tags" do
82
+ assert_markdown "<p>Yes, magic helmet. And <a href=\"http://sample.com/\">I'll give you a sample</a>.</p>",
83
+ "\nYes, magic helmet. And [I'll give you a sample](http://sample.com/).\n"
84
+ end
85
+
86
+ context "<a> tags without hrefs" do
87
+ should "be ignored" do
88
+ assert_markdown "<div><a name='link-target'>target title</a></div>",
89
+ "\ntarget title\n",
90
+ false
91
+
92
+ assert_markdown "<div><a id='link-target'>target title</a></div>",
93
+ "\ntarget title\n",
94
+ false
95
+ end
80
96
  end
81
97
 
82
- should "convert relative urls to reference-style" do
83
- assert_markdown2 "<p>Yes, magic helmet. And <a href=\"/home\" title=\"Fudd\">I'll give you a sample</a>.</p>",
84
- "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: /home \"Fudd\"\n"
98
+ context "<a> tags with titles" do
99
+ should "convert fq urls to reference-style" do
100
+ assert_markdown2 "<p>Yes, magic helmet. And <a href=\"http://sample.com/\" title=\"Fudd\">I'll give you a sample</a>.</p>",
101
+ "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: http://sample.com/ \"Fudd\"\n"
102
+ end
103
+
104
+ should "convert relative urls to reference-style" do
105
+ assert_markdown2 "<p>Yes, magic helmet. And <a href=\"/home\" title=\"Fudd\">I'll give you a sample</a>.</p>",
106
+ "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: /home \"Fudd\"\n"
107
+ end
108
+
109
+ should "convert multiple to appear in order at the end of the document" do
110
+ assert_markdown2 "<p>See <a href=\"/prefs\" title=\"Prefs\">Prefs</a> and <a href=\"/home\" title=\"Home\">Home</a>.</p>",
111
+ "\nSee [Prefs][1] and [Home][2].\n\n[1]: /prefs \"Prefs\"\n[2]: /home \"Home\"\n"
112
+ end
85
113
  end
114
+ end
115
+ end
116
+ end
86
117
 
87
- should "convert multiple to appear in order at the end of the document" do
88
- assert_markdown2 "<p>See <a href=\"/prefs\" title=\"Prefs\">Prefs</a> and <a href=\"/home\" title=\"Home\">Home</a>.</p>",
89
- "\nSee [Prefs][1] and [Home][2].\n\n[1]: /prefs \"Prefs\"\n[2]: /home \"Home\"\n"
118
+ context McBean::Markdownify::Antidote do
119
+ context "given that RDiscount is already pretty well tested" do
120
+ context "let's limit ourselves to a token test case" do
121
+ should "convert markdown into html" do
122
+ assert_equal "<h1>hello</h1>\n", McBean.markdown("hello\n=====\n").to_html
90
123
  end
91
124
  end
92
125
  end
@@ -95,7 +128,7 @@ class TestMcBeanMarkdown < Test::Unit::TestCase
95
128
  private
96
129
 
97
130
  def assert_markdown html, markdown, roundtrip=true
98
- assert_equal(html, BlueCloth.new(markdown).to_html, "markdown roundtrip failed") if roundtrip
131
+ assert_equal(html, McBean::Markdownify::Antidote.new(markdown).to_html.chomp, "markdown roundtrip failed") if roundtrip
99
132
  assert_equal(markdown, McBean.fragment(html).to_markdown, "fragment transformation failed")
100
133
  assert_equal(Loofah::Helpers.remove_extraneous_whitespace("\n#{markdown}\n"),
101
134
  McBean.document("<div>#{html}</div>").to_markdown, "document transformation failed")
@@ -103,7 +136,7 @@ class TestMcBeanMarkdown < Test::Unit::TestCase
103
136
 
104
137
  def assert_markdown2 html, markdown, roundtrip=true
105
138
  # note peskily absent newline at end of document. sigh.
106
- assert_equal(html, BlueCloth.new(markdown).to_html, "markdown roundtrip failed") if roundtrip
139
+ assert_equal(html, McBean::Markdownify::Antidote.new(markdown).to_html.chomp, "markdown roundtrip failed") if roundtrip
107
140
  assert_equal(markdown, McBean.fragment(html).to_markdown, "fragment transformation failed")
108
141
  assert_equal(Loofah::Helpers.remove_extraneous_whitespace("\n#{markdown}"),
109
142
  McBean.document("<div>#{html}</div>").to_markdown, "document transformation failed")
@@ -10,8 +10,44 @@ class TestMcBean < Test::Unit::TestCase
10
10
  context "cleanup" do
11
11
  should "prune unsafe tags" do
12
12
  result = McBean.fragment("<div>OK</div><script>BAD</script>").to_markdown
13
- assert_match /OK/, result
14
- assert_no_match /BAD/, result
13
+ assert_match( /OK/, result)
14
+ assert_no_match( /BAD/, result)
15
+ end
16
+ end
17
+
18
+ context "parsing" do
19
+ context "McBean.fragment" do
20
+ should "call Loofah.fragment" do
21
+ html = "<h1>hello</h1>\n"
22
+ mock.proxy(Loofah).fragment(html).once
23
+ McBean.fragment html
24
+ end
25
+ end
26
+
27
+ context "McBean.document" do
28
+ should "call Loofah.document" do
29
+ html = "<h1>hello</h1>\n"
30
+ mock.proxy(Loofah).document(html).once
31
+ McBean.document html
32
+ end
33
+ end
34
+
35
+ context "McBean.markdown" do
36
+ context "passed a string" do
37
+ should "create a Markdownify::Antidote" do
38
+ mock.proxy(McBean::Markdownify::Antidote).new(anything).once
39
+ assert_equal "<h1>hello</h1>\n", McBean.markdown("hello\n=====\n").to_html
40
+ end
41
+ end
42
+
43
+ context "passed an IO" do
44
+ should "create a Markdownify::Antidote" do
45
+ io = StringIO.new "hello\n=====\n"
46
+ mock.proxy(McBean::Markdownify::Antidote).new(anything).once
47
+ mock.proxy(io).read.once
48
+ assert_equal "<h1>hello</h1>\n", McBean.markdown(io).to_html
49
+ end
50
+ end
15
51
  end
16
52
  end
17
53
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
7
  - 2
9
- version: 0.1.2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mike Dalessio
@@ -35,7 +35,7 @@ cert_chain:
35
35
  FlqnTjy13J3nD30uxy9a1g==
36
36
  -----END CERTIFICATE-----
37
37
 
38
- date: 2010-03-10 00:00:00 -05:00
38
+ date: 2010-03-24 00:00:00 -04:00
39
39
  default_executable:
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
@@ -53,9 +53,23 @@ dependencies:
53
53
  type: :runtime
54
54
  version_requirements: *id001
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubyforge
56
+ name: rdiscount
57
57
  prerelease: false
58
58
  requirement: &id002 !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 4
66
+ version: 1.3.4
67
+ type: :runtime
68
+ version_requirements: *id002
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubyforge
71
+ prerelease: false
72
+ requirement: &id003 !ruby/object:Gem::Requirement
59
73
  requirements:
60
74
  - - ">="
61
75
  - !ruby/object:Gem::Version
@@ -65,11 +79,11 @@ dependencies:
65
79
  - 3
66
80
  version: 2.0.3
67
81
  type: :development
68
- version_requirements: *id002
82
+ version_requirements: *id003
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: gemcutter
71
85
  prerelease: false
72
- requirement: &id003 !ruby/object:Gem::Requirement
86
+ requirement: &id004 !ruby/object:Gem::Requirement
73
87
  requirements:
74
88
  - - ">="
75
89
  - !ruby/object:Gem::Version
@@ -79,11 +93,11 @@ dependencies:
79
93
  - 0
80
94
  version: 0.3.0
81
95
  type: :development
82
- version_requirements: *id003
96
+ version_requirements: *id004
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: shoulda
85
99
  prerelease: false
86
- requirement: &id004 !ruby/object:Gem::Requirement
100
+ requirement: &id005 !ruby/object:Gem::Requirement
87
101
  requirements:
88
102
  - - ">="
89
103
  - !ruby/object:Gem::Version
@@ -92,11 +106,25 @@ dependencies:
92
106
  - 10
93
107
  version: "2.10"
94
108
  type: :development
95
- version_requirements: *id004
109
+ version_requirements: *id005
110
+ - !ruby/object:Gem::Dependency
111
+ name: rr
112
+ prerelease: false
113
+ requirement: &id006 !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ segments:
118
+ - 0
119
+ - 10
120
+ - 4
121
+ version: 0.10.4
122
+ type: :development
123
+ version_requirements: *id006
96
124
  - !ruby/object:Gem::Dependency
97
125
  name: hoe
98
126
  prerelease: false
99
- requirement: &id005 !ruby/object:Gem::Requirement
127
+ requirement: &id007 !ruby/object:Gem::Requirement
100
128
  requirements:
101
129
  - - ">="
102
130
  - !ruby/object:Gem::Version
@@ -106,15 +134,15 @@ dependencies:
106
134
  - 0
107
135
  version: 2.5.0
108
136
  type: :development
109
- version_requirements: *id005
137
+ version_requirements: *id007
110
138
  description: |-
111
- McBean transforms HTML into Markdown with the help of Loofah and Nokogiri.
139
+ McBean converts HTML into Markdown, and Markdown into HTML (with the
140
+ help of Loofah, Nokogiri and RDiscount).
112
141
 
113
- Its goal is to eventually be able to transform (with the help of other
114
- relevant gems) documents from HTML to Markdown to Textile, and
115
- anything in between. It will be the Sylvester McMonkey McBean of
116
- markup, placing stars onto the bellies of all kinds of document
117
- formats.
142
+ Its goal is to eventually be able to transform documents from HTML to
143
+ Markdown to Textile, and anything in between. It will be the Sylvester
144
+ McMonkey McBean of markup, placing stars onto the bellies of all kinds
145
+ of Sneetchy document formats.
118
146
 
119
147
  "You can't teach a Sneetch."
120
148
  email:
@@ -171,7 +199,7 @@ rubyforge_project: mcbean
171
199
  rubygems_version: 1.3.6
172
200
  signing_key:
173
201
  specification_version: 3
174
- summary: McBean transforms HTML into Markdown with the help of Loofah and Nokogiri
202
+ summary: McBean converts HTML into Markdown, and Markdown into HTML (with the help of Loofah, Nokogiri and RDiscount)
175
203
  test_files:
176
204
  - test/test_mcbean.rb
177
205
  - test/test_markdown.rb
metadata.gz.sig CHANGED
@@ -1,2 +1,3 @@
1
- �}�[���3\��,��b�Cy����$�W�P�M�I�:���b�S�Ż����b�rR̗��p���p����^X�|X�������.m~�1w�Ypf[��\�l�Y%�w�9���T�P�
2
- S
1
+ �Ԕ�
2
+ �m�Z�QH��t��Jkq��$�ڇ
3
+ �B��U�Ӡ�CR�"�x�Q�t�y P� �n~5y9�p`Fg�*��>��/�9�s7d)�������8�|��^Ť�A �^��� ��K��nZ�C���5f��E% �ӄ?}Wa��%���t׉�3X����U