tinder 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +21 -0
- data/README.markdown +39 -0
- data/Rakefile +12 -26
- data/VERSION +1 -1
- data/lib/tinder.rb +3 -5
- data/lib/tinder/campfire.rb +9 -49
- data/lib/tinder/connection.rb +56 -2
- data/lib/tinder/room.rb +70 -55
- data/spec/fixtures/rooms.json +18 -0
- data/spec/fixtures/rooms/room80749.json +21 -0
- data/spec/fixtures/rooms/room80751.json +21 -0
- data/spec/fixtures/rooms/show.json +21 -0
- data/spec/fixtures/users/me.json +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/tinder/campfire_spec.rb +53 -0
- data/spec/tinder/connection_spec.rb +29 -0
- data/spec/tinder/room_spec.rb +99 -0
- data/tinder.gemspec +28 -19
- metadata +85 -34
- data/Manifest.txt +0 -10
- data/README.txt +0 -54
- data/spec/campfire_spec.rb +0 -225
- data/spec/html/full_lobby.html +0 -198
- data/spec/html/normal_lobby.html +0 -192
- data/spec/html/transcript.html +0 -133
- data/test/remote/credentials.rb.example +0 -4
- data/test/remote/remote_campfire_test.rb +0 -59
- data/test/test_helper.rb +0 -2
data/Manifest.txt
DELETED
data/README.txt
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
= Tinder - get the Campfire started
|
2
|
-
|
3
|
-
|
4
|
-
This branch is a rewrite of Tinder to use the official Campfire API. The API is intended to be backwards compatible so consumers can easily migrate off the HTML API.
|
5
|
-
|
6
|
-
-- Joshua Peek (Programmer, 37signals)
|
7
|
-
|
8
|
-
|
9
|
-
Tinder is a library for interfacing with Campfire, the chat application from 37Signals. Unlike Marshmallow, it is designed to be a full-featured API (since 37Signals doesn't provide a real one), allowing you to programatically manage and speak/listen in chat rooms.
|
10
|
-
|
11
|
-
== Usage
|
12
|
-
|
13
|
-
campfire = Tinder::Campfire.new 'mysubdomain'
|
14
|
-
campfire.login 'myemail@example.com', 'mypassword'
|
15
|
-
|
16
|
-
room = campfire.create_room 'New Room', 'My new campfire room to test tinder'
|
17
|
-
room.rename 'New Room Name'
|
18
|
-
room.speak 'Hello world!'
|
19
|
-
room.paste "my pasted\ncode"
|
20
|
-
room.destroy
|
21
|
-
|
22
|
-
room = campfire.find_room_by_guest_hash 'abc123', 'John Doe'
|
23
|
-
room.speak 'Hello world!'
|
24
|
-
|
25
|
-
See the RDoc for more details.
|
26
|
-
|
27
|
-
== Installation
|
28
|
-
|
29
|
-
Tinder can be installed as a gem or a Rails plugin:
|
30
|
-
|
31
|
-
gem install tinder
|
32
|
-
|
33
|
-
script/plugin install git://github.com/collectiveidea/tinder.git
|
34
|
-
|
35
|
-
== How to contribute
|
36
|
-
|
37
|
-
If you find what looks like a bug:
|
38
|
-
|
39
|
-
1. Check the GitHub issue tracker to see if anyone else has had the same issue.
|
40
|
-
http://github.com/collectiveidea/tinder/issues/
|
41
|
-
2. If you don't see anything, create an issue with information on how to reproduce it.
|
42
|
-
|
43
|
-
If you want to contribute an enhancement or a fix:
|
44
|
-
|
45
|
-
1. Fork the project on github.
|
46
|
-
http://github.com/collectiveidea/tinder
|
47
|
-
2. Make your changes with tests.
|
48
|
-
3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
|
49
|
-
4. Send a pull request.
|
50
|
-
|
51
|
-
== ToDo
|
52
|
-
|
53
|
-
* Tests! (unit and remote)
|
54
|
-
* Marshmallow-style integration scripts for exception notification and continuous integration
|
data/spec/campfire_spec.rb
DELETED
@@ -1,225 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Preparing a campfire request" do
|
4
|
-
before do
|
5
|
-
@campfire = Tinder::Campfire.new("foobar")
|
6
|
-
@request = Net::HTTP::Get.new("does_not_matter")
|
7
|
-
end
|
8
|
-
|
9
|
-
def prepare_request
|
10
|
-
@campfire.send(:prepare_request, @request)
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should return the request" do
|
14
|
-
prepare_request.should equal(@request)
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should set the cookie" do
|
18
|
-
@campfire.instance_variable_set("@cookie", "foobar")
|
19
|
-
prepare_request['Cookie'].should == 'foobar'
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should set the user agent" do
|
23
|
-
prepare_request['User-Agent'].should =~ /^Tinder/
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# describe "Performing a campfire request" do
|
28
|
-
#
|
29
|
-
# before do
|
30
|
-
# @response = mock("response")
|
31
|
-
# Net::HTTP.any_instance.stubs(:request).returns(response)
|
32
|
-
# request = Net::HTTP::Get.new("does_not_matter")
|
33
|
-
# response.expects(:[]).with('set-cookie').and_return('foobar')
|
34
|
-
# @campfire.send(:perform_request) { request }
|
35
|
-
# end
|
36
|
-
#
|
37
|
-
# it "should set cookie" do
|
38
|
-
# @campfire.instance_variable_get("@cookie").should == 'foobar'
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# end
|
42
|
-
|
43
|
-
describe "Verifying a 200 response" do
|
44
|
-
|
45
|
-
before do
|
46
|
-
@campfire = Tinder::Campfire.new("foobar")
|
47
|
-
@response = mock("response")
|
48
|
-
@response.should_receive(:code).and_return(200)
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should return true when expecting success" do
|
52
|
-
@campfire.send(:verify_response, @response, :success).should equal(true)
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should return false when expecting a redirect" do
|
56
|
-
@campfire.send(:verify_response, @response, :redirect).should equal(false)
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should return false when expecting a redirect to a specific path" do
|
60
|
-
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(false)
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "Verifying a 302 response" do
|
66
|
-
|
67
|
-
before do
|
68
|
-
@campfire = Tinder::Campfire.new("foobar")
|
69
|
-
@response = mock("response")
|
70
|
-
@response.should_receive(:code).and_return(302)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should return true when expecting redirect" do
|
74
|
-
@campfire.send(:verify_response, @response, :redirect).should equal(true)
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should return false when expecting success" do
|
78
|
-
@campfire.send(:verify_response, @response, :success).should equal(false)
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should return true when expecting a redirect to a specific path" do
|
82
|
-
@response.should_receive(:[]).with('location').and_return("/foobar")
|
83
|
-
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(true)
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should return false when redirecting to a different path than expected" do
|
87
|
-
@response.should_receive(:[]).with('location').and_return("/baz")
|
88
|
-
@campfire.send(:verify_response, @response, :redirect_to => '/foobar').should equal(false)
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "A failed login" do
|
94
|
-
|
95
|
-
before do
|
96
|
-
@campfire = Tinder::Campfire.new 'foobar'
|
97
|
-
@response = mock("response")
|
98
|
-
@campfire.should_receive(:post).and_return(@response)
|
99
|
-
@response.should_receive(:code).and_return("302")
|
100
|
-
@response.should_receive(:[]).with("location").and_return("/login")
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should raise an error" do
|
104
|
-
lambda do
|
105
|
-
@campfire.login "doesn't", "matter"
|
106
|
-
end.should raise_error(Tinder::Error)
|
107
|
-
end
|
108
|
-
|
109
|
-
it "should not set logged in status" do
|
110
|
-
@campfire.login 'foo', 'bar' rescue
|
111
|
-
@campfire.logged_in?.should equal(false)
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
describe "Accessing a room with guest access" do
|
117
|
-
|
118
|
-
before do
|
119
|
-
@room_id = 123
|
120
|
-
@campfire = Tinder::Campfire.new 'foobar'
|
121
|
-
@response = mock("response")
|
122
|
-
@campfire.stub!(:post).and_return(@response)
|
123
|
-
end
|
124
|
-
|
125
|
-
it "should return a room for the public room" do
|
126
|
-
@response.should_receive(:code).and_return(302)
|
127
|
-
@response.should_receive(:[]).with("location").and_return("/rooms/#{@room_id}")
|
128
|
-
|
129
|
-
room = @campfire.find_room_by_guest_hash "valid_hash", "John Doe"
|
130
|
-
room.should be_kind_of(Tinder::Room)
|
131
|
-
end
|
132
|
-
|
133
|
-
it "should raise an error if given an invalid room hash" do
|
134
|
-
@response.should_receive(:code).and_return(500)
|
135
|
-
|
136
|
-
room = @campfire.find_room_by_guest_hash "invalid_hash", "John Doe"
|
137
|
-
room.should be_nil
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
describe "Accessing a room" do
|
143
|
-
|
144
|
-
before do
|
145
|
-
@request = mock("request")
|
146
|
-
@response = mock("response")
|
147
|
-
Net::HTTP.stub!(:new).and_return(@request)
|
148
|
-
@request.stub!(:use_ssl=)
|
149
|
-
@request.stub!(:request).and_return(@response)
|
150
|
-
@response.stub!(:[]).and_return(true)
|
151
|
-
end
|
152
|
-
|
153
|
-
describe "when the room is full" do
|
154
|
-
|
155
|
-
before do
|
156
|
-
@html = File.read(File.dirname(__FILE__) + '/html/full_lobby.html')
|
157
|
-
@response.stub!(:body).and_return(@html)
|
158
|
-
@campfire = Tinder::Campfire.new 'foobar'
|
159
|
-
end
|
160
|
-
|
161
|
-
it "should return a room" do
|
162
|
-
@campfire.rooms.should_not be_empty
|
163
|
-
end
|
164
|
-
|
165
|
-
it "should find a room by name" do
|
166
|
-
@campfire.find_room_by_name("Just Fishin").class.should == Tinder::Room
|
167
|
-
end
|
168
|
-
|
169
|
-
end
|
170
|
-
|
171
|
-
describe "when the room is not full" do
|
172
|
-
|
173
|
-
before do
|
174
|
-
@html = File.read(File.dirname(__FILE__) + '/html/normal_lobby.html')
|
175
|
-
@response.stub!(:body).and_return(@html)
|
176
|
-
@campfire = Tinder::Campfire.new 'foobar'
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should return a room" do
|
180
|
-
@campfire.rooms.should_not be_empty
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should find a room by name" do
|
184
|
-
@campfire.find_room_by_name("Just Fishin").class.should == Tinder::Room
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
describe "Accessing a room's transcript" do
|
191
|
-
|
192
|
-
before do
|
193
|
-
@room = Tinder::Room.new nil, 42
|
194
|
-
@html = File.read(File.dirname(__FILE__) + '/html/transcript.html')
|
195
|
-
@response = mock("response")
|
196
|
-
@response.stub!(:body).and_return(@html)
|
197
|
-
@room.stub!(:get).with("room/42/transcript/2009/05/05").
|
198
|
-
and_return(@response)
|
199
|
-
require 'time'
|
200
|
-
@transcript = @room.transcript(Time.parse("2009-05-05"))
|
201
|
-
end
|
202
|
-
|
203
|
-
it "should return some messages" do
|
204
|
-
@transcript.should_not be_empty
|
205
|
-
end
|
206
|
-
|
207
|
-
describe "the first message" do
|
208
|
-
# This is a timestamp message
|
209
|
-
it "should include a timestamp" do
|
210
|
-
@transcript.first[:timestamp].should == Time.parse("2009-05-05 09:35")
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
describe "the second message" do
|
215
|
-
it "should include a timestamp" do
|
216
|
-
@transcript.second[:timestamp].should == Time.parse("2009-05-05 09:35")
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
describe "when entering the room" do
|
221
|
-
it "a transcript message should include the person who entered" do
|
222
|
-
@transcript.second[:person].should == "Marcel"
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
data/spec/html/full_lobby.html
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
3
|
-
|
4
|
-
<head>
|
5
|
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
-
<title>Chat rooms</title>
|
7
|
-
<link href="/stylesheets/screen.css?1224558404" media="all" rel="stylesheet" type="text/css" />
|
8
|
-
<!--[if lte IE 6]>
|
9
|
-
<style type="text/css">
|
10
|
-
@import url("/stylesheets/screen-ie.css?1224558404");
|
11
|
-
</style>
|
12
|
-
<![endif]-->
|
13
|
-
<!--[if IE 7]>
|
14
|
-
<style type="text/css">
|
15
|
-
@import url("/stylesheets/screen-ie-7.css?1224558404");
|
16
|
-
</style>
|
17
|
-
<![endif]-->
|
18
|
-
|
19
|
-
<link href="/stylesheets/print.css?1224558404" media="print" rel="stylesheet" type="text/css" />
|
20
|
-
<link href="/stylesheets/blue.css?1224558404" media="screen" rel="stylesheet" title="Theme" type="text/css" />
|
21
|
-
<script src="/javascripts/prototype.js?1224558404" type="text/javascript"></script>
|
22
|
-
<script src="/javascripts/effects.js?1224558404" type="text/javascript"></script>
|
23
|
-
<script src="/javascripts/application.js?1224558404" type="text/javascript"></script>
|
24
|
-
<script src="/javascripts/nubbins.js?1224558404" type="text/javascript"></script>
|
25
|
-
<script src="/javascripts/campfire.js?1224558404" type="text/javascript"></script>
|
26
|
-
<script src="/javascripts/javascript_flash_gateway.js?1224558404" type="text/javascript"></script>
|
27
|
-
</head>
|
28
|
-
|
29
|
-
<body class="lobby">
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
<div id="Header">
|
35
|
-
<div id="Tabs">
|
36
|
-
<ul id="MainTabs">
|
37
|
-
<li><a href="http://fish.campfirenow.com/" class="current">Lobby</a></li>
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
<li><a href="http://fish.campfirenow.com/room/17715" class="chat" id="room_tab-17715">Just Fishin</a></li>
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
<li><a href="http://fish.campfirenow.com/files+transcripts" class="" style="margin-left: 8px">Files, Transcripts & Search</a></li>
|
47
|
-
|
48
|
-
<li style="float: right;" class="logout"><a href="http://fish.campfirenow.com/logout">Logout</a></li>
|
49
|
-
<li style="float: right" class="logout"><a href="/member/edit">My account</a></li>
|
50
|
-
|
51
|
-
|
52
|
-
</ul>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
|
56
|
-
|
57
|
-
<div id="Wrapper">
|
58
|
-
<div id="Container">
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
<div class="Full">
|
64
|
-
<div class="col">
|
65
|
-
|
66
|
-
<div id="lobby">
|
67
|
-
<h1>
|
68
|
-
<span><a class="admin toggle show_hide_toggler_new_room" href="#" id="create_room_link" onclick="$('new_room').showHide.toggle(); return false;">Create a new room</a></span>
|
69
|
-
Chat rooms
|
70
|
-
</h1>
|
71
|
-
|
72
|
-
<div class="currentChatters">
|
73
|
-
4 people currently chatting
|
74
|
-
<span>
|
75
|
-
<br />You're near your simultaneous chatter limit of 4.
|
76
|
-
Ask <a href="mailto:bob@billy.com">Billy Bob</a> to upgrade the account.
|
77
|
-
</span>
|
78
|
-
|
79
|
-
</div>
|
80
|
-
<div class="show_hide_wrapper"><div class=" showhide" id="new_room" style="display: none"><div class="basic_form_wrapper">
|
81
|
-
<div class="basic_form">
|
82
|
-
<div class="explanation">
|
83
|
-
<h3>Create a new room</h3>
|
84
|
-
<p>All chats take place in rooms. You can create as many rooms as you'd like.</p>
|
85
|
-
<p>Consider making rooms for client projects, general discussions, specific meetings/events, and more.</p>
|
86
|
-
<div class="spinner" id="new_room_spinner" style="display: none"> </div>
|
87
|
-
</div>
|
88
|
-
<div id="new_room_form_errors"></div>
|
89
|
-
<div class="body">
|
90
|
-
<form action="http://fish.campfirenow.com/account/create/room?from=lobby" id="new_room_form" method="post" onsubmit="$(this).down('input[type=submit]').disable(); Element.hide('new_room_cancel_link'); new Ajax.Request('http://fish.campfirenow.com/account/create/room?from=lobby', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;"> <h3>Name the room</h3>
|
91
|
-
<p><input class="big expanded" id="room_name" name="room[name]" size="30" type="text" /></p>
|
92
|
-
<h3 style="font-weight: normal;">Optional: Give the room a topic or description</h3>
|
93
|
-
<p><textarea class="expanded" cols="40" id="room_topic" name="room[topic]" rows="20"></textarea></p>
|
94
|
-
<p class="submit"><input class="primary" name="commit" type="submit" value="Create the room" />
|
95
|
-
<span id="new_room_cancel_link"> or
|
96
|
-
<a class="admin show_hide_toggler_new_room" href="#" onclick="$('new_room').showHide.toggle(); return false;">Cancel</a></span></p>
|
97
|
-
</form> </div>
|
98
|
-
</div>
|
99
|
-
</div>
|
100
|
-
</div><script type="text/javascript">
|
101
|
-
//<![CDATA[
|
102
|
-
new ShowHide('new_room', {"beforeToggle": function(showHide) {Form.reset('new_room_form'); Element.update('new_room_form_errors', '')}, "afterToggle": function(showHide) {if (/MSIE/.test(navigator.userAgent)) {Element.hide(document.body);Element.show(document.body);};Field.activate('room_name')}})
|
103
|
-
//]]>
|
104
|
-
</script></div>
|
105
|
-
|
106
|
-
<div id="rooms">
|
107
|
-
<table class="lobby">
|
108
|
-
<tr>
|
109
|
-
<td class="lobby_room" style="vertical-align: top; width: 33%;"><div id="room_17715" class="room full shaded">
|
110
|
-
<h2>
|
111
|
-
Just Fishin
|
112
|
-
</h2>
|
113
|
-
|
114
|
-
<div class="updated">
|
115
|
-
|
116
|
-
Full
|
117
|
-
<span class="active"> Active 7 minutes ago</span>
|
118
|
-
</div>
|
119
|
-
<p>Sargasm: Deriving far too much satisfaction from glibly berating another with sarcasm.
|
120
|
-
|
121
|
-
Ex: "Oh, thanks a lot for drinking my last beer! No, it's my fault... if I wanted it for myself, I shouldn't have put it in the fridge!"
|
122
|
-
"Dude, don't have a sargasm</p>
|
123
|
-
|
124
|
-
|
125
|
-
<ul class="participant-list" id="participant_list-17715">
|
126
|
-
<li class="user nubbin_region" id="user_38447">
|
127
|
-
|
128
|
-
<span class="name">Caribou Barbie</span>
|
129
|
-
|
130
|
-
</li>
|
131
|
-
<li class="user nubbin_region idle" id="user_39723">
|
132
|
-
|
133
|
-
<span class="name">git</span>
|
134
|
-
|
135
|
-
</li>
|
136
|
-
<li class="user nubbin_region" id="user_38449">
|
137
|
-
|
138
|
-
<span class="name">Joe Sixpack</span>
|
139
|
-
|
140
|
-
</li>
|
141
|
-
<li class="user nubbin_region idle" id="user_38445">
|
142
|
-
|
143
|
-
<span class="name">Billy Bob</span>
|
144
|
-
|
145
|
-
</li>
|
146
|
-
</ul>
|
147
|
-
|
148
|
-
</div>
|
149
|
-
</td>
|
150
|
-
<td class="lobby_room" style="vertical-align: top; width: 33%;"> </td>
|
151
|
-
<td class="lobby_room" style="vertical-align: top; width: 33%;"> </td>
|
152
|
-
</tr>
|
153
|
-
</table>
|
154
|
-
|
155
|
-
</div>
|
156
|
-
</div>
|
157
|
-
|
158
|
-
<script type="text/javascript">
|
159
|
-
//<![CDATA[
|
160
|
-
Ajax.Responders.register({
|
161
|
-
onCreate: function() {
|
162
|
-
if (Ajax.activeRequestCount > 0)
|
163
|
-
Element.show('new_room_spinner');
|
164
|
-
},
|
165
|
-
onComplete: function() {
|
166
|
-
if (Ajax.activeRequestCount == 0)
|
167
|
-
Element.hide('new_room_spinner');
|
168
|
-
}
|
169
|
-
});
|
170
|
-
|
171
|
-
//]]>
|
172
|
-
</script>
|
173
|
-
<script type="text/javascript">
|
174
|
-
//<![CDATA[
|
175
|
-
new PeriodicalExecuter(function() {new Ajax.Request('http://fish.campfirenow.com/rooms', {asynchronous:true, evalScripts:true})}, 60)
|
176
|
-
//]]>
|
177
|
-
</script>
|
178
|
-
|
179
|
-
<p style="clear: both;"> </p>
|
180
|
-
|
181
|
-
</div>
|
182
|
-
|
183
|
-
<div class="bottom"> </div>
|
184
|
-
<div id="Footer">
|
185
|
-
<strong><a href="http://www.campfirenow.com/help" target=_blank>FAQs and Help</a></strong> |
|
186
|
-
<a href="http://www.campfirenow.com/privacy.html" target=_blank>Privacy Policy</a> |
|
187
|
-
<a href="http://www.campfirenow.com/terms.html" target=_blank>Terms of Service</a>
|
188
|
-
</div>
|
189
|
-
|
190
|
-
</div>
|
191
|
-
|
192
|
-
|
193
|
-
</div>
|
194
|
-
</div>
|
195
|
-
|
196
|
-
|
197
|
-
</body>
|
198
|
-
</html>
|