mcbean 0.1.2 → 0.2.0

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.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