punchblock 0.7.2 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # develop
2
2
 
3
+ # v0.8.0 - 2012-01-06
4
+ * Feature: Expose Blather's connection timeout config when creating a Connection::XMPP
5
+ * Bugfix: Remove some deprecated Tropo extension components
6
+ * Bugfix: Remove reconnection logic since it really belongs in the consumer
7
+ * Feature: Raise a DisconnectedError when a disconnection is detected
8
+
3
9
  # v0.7.2 - 2011-12-28
4
10
  * Feature: Allow sending commands to mixers easily
5
11
  * Feature: Allow configuration of Rayo XMPP domains (root, call and mixer)
data/lib/punchblock.rb CHANGED
@@ -16,6 +16,7 @@ module Punchblock
16
16
  autoload :CommandNode
17
17
  autoload :Component
18
18
  autoload :Connection
19
+ autoload :DisconnectedError
19
20
  autoload :HasHeaders
20
21
  autoload :Header
21
22
  autoload :MediaContainer
@@ -53,7 +54,7 @@ module Punchblock
53
54
  RAYO_NAMESPACES[:"#{ns}_complete"] = [BASE_RAYO_NAMESPACE, ns.to_s, 'complete', RAYO_VERSION].compact.join(':')
54
55
  end
55
56
 
56
- [:ask, :conference, :say, :transfer].each do |ns|
57
+ [:conference].each do |ns|
57
58
  RAYO_NAMESPACES[ns] = [BASE_TROPO_NAMESPACE, ns.to_s, RAYO_VERSION].compact.join(':')
58
59
  RAYO_NAMESPACES[:"#{ns}_complete"] = [BASE_TROPO_NAMESPACE, ns.to_s, 'complete', RAYO_VERSION].compact.join(':')
59
60
  end
@@ -3,10 +3,7 @@ module Punchblock
3
3
  module Tropo
4
4
  extend ActiveSupport::Autoload
5
5
 
6
- autoload :Ask
7
6
  autoload :Conference
8
- autoload :Say
9
- autoload :Transfer
10
7
  end
11
8
  end # Command
12
9
  end # Punchblock
@@ -18,14 +18,14 @@ module Punchblock
18
18
  # @option options [String] :username client JID
19
19
  # @option options [String] :password XMPP password
20
20
  # @option options [String] :rayo_domain the domain on which Rayo is running
21
- # @option options [Boolean, Optional] :auto_reconnect whether or not to auto reconnect
22
21
  # @option options [Numeric, Optional] :write_timeout for which to wait on a command response
22
+ # @option options [Numeric, Optional] :connection_timeout for which to wait on a connection being established
23
23
  # @option options [Numeric, nil, Optional] :ping_period interval in seconds on which to ping the server. Nil or false to disable
24
24
  #
25
25
  def initialize(options = {})
26
26
  raise ArgumentError unless (@username = options[:username]) && options[:password]
27
27
 
28
- setup *[:username, :password, :host, :port, :certs].map { |key| options.delete key }
28
+ setup *[:username, :password, :host, :port, :certs, :connection_timeout].map { |key| options.delete key }
29
29
 
30
30
  @root_domain = Blather::JID.new(options[:root_domain] || options[:rayo_domain] || @username).domain
31
31
  @calls_domain = options[:calls_domain] || "calls.#{@root_domain}"
@@ -33,9 +33,6 @@ module Punchblock
33
33
 
34
34
  @callmap = {} # This hash maps call IDs to their XMPP domain.
35
35
 
36
- @auto_reconnect = !!options[:auto_reconnect]
37
- @reconnect_attempts = 0
38
-
39
36
  @ping_period = options.has_key?(:ping_period) ? options[:ping_period] : 60
40
37
 
41
38
  Blather.logger = pb_logger
@@ -59,7 +56,7 @@ module Punchblock
59
56
  def prep_command_for_execution(command, options = {})
60
57
  command.connection = self
61
58
  command.call_id ||= options[:call_id]
62
- command.mixer_name ||= options[:mixer_name]
59
+ command.mixer_name ||= options[:mixer_name]
63
60
  command.component_id ||= options[:component_id]
64
61
  create_iq(jid_for_command(command)).tap do |iq|
65
62
  pb_logger.debug "Sending IQ ID #{iq.id} #{command.inspect} to #{jid}"
@@ -78,13 +75,17 @@ module Punchblock
78
75
  def connect
79
76
  begin
80
77
  EM.run { client.run }
78
+ rescue Blather::Stream::ConnectionFailed, Blather::Stream::ConnectionTimeout => e
79
+ raise DisconnectedError.new(e.class.to_s, e.message)
81
80
  rescue => e
81
+ # Preserve Punchblock native exceptions
82
+ raise e if e.class.to_s =~ /^Punchblock/
83
+ # Wrap everything else
82
84
  raise ProtocolError.new(e.class.to_s, e.message)
83
85
  end
84
86
  end
85
87
 
86
88
  def stop
87
- @reconnect_attempts = nil
88
89
  client.close
89
90
  end
90
91
 
@@ -155,20 +156,12 @@ module Punchblock
155
156
  when_ready do
156
157
  event_handler.call Connected.new
157
158
  pb_logger.info "Connected to XMPP as #{@username}"
158
- @reconnect_attempts = 0
159
159
  @rayo_ping = EM::PeriodicTimer.new(@ping_period) { ping_rayo } if @ping_period
160
160
  end
161
161
 
162
162
  disconnected do
163
163
  @rayo_ping.cancel if @rayo_ping
164
- if @auto_reconnect && @reconnect_attempts
165
- timer = 30 * 2 ** @reconnect_attempts
166
- pb_logger.warn "XMPP disconnected. Tried to reconnect #{@reconnect_attempts} times. Reconnecting in #{timer}s."
167
- sleep timer
168
- pb_logger.info "Trying to reconnect..."
169
- @reconnect_attempts += 1
170
- connect
171
- end
164
+ raise DisconnectedError
172
165
  end
173
166
 
174
167
  # Read/handle presence requests. This is how we get events.
@@ -0,0 +1,16 @@
1
+ module Punchblock
2
+ ##
3
+ # This exception may be raised if the connection to the server is interrupted.
4
+ class DisconnectedError < StandardError
5
+ attr_accessor :cause, :message
6
+
7
+ def initialize(cause = nil, message = nil)
8
+ @cause, @message = cause, message
9
+ end
10
+
11
+ def to_s
12
+ "#<#{self.class}: cause=#{cause.inspect} message=#{message.inspect}"
13
+ end
14
+ alias :inspect :to_s
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Punchblock
2
- VERSION = "0.7.2"
2
+ VERSION = "0.8.0"
3
3
  end
data/punchblock.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.required_rubygems_version = Gem::Requirement.new(">= 1.3.7") if s.respond_to? :required_rubygems_version=
24
24
 
25
25
  s.add_runtime_dependency %q<niceogiri>, [">= 0.0.4"]
26
- s.add_runtime_dependency %q<blather>, [">= 0.5.9"]
26
+ s.add_runtime_dependency %q<blather>, [">= 0.5.12"]
27
27
  s.add_runtime_dependency %q<activesupport>, [">= 2.1.0"]
28
28
  s.add_runtime_dependency %q<state_machine>, [">= 1.0.1"]
29
29
  s.add_runtime_dependency %q<future-resource>, [">= 0.0.2"]
@@ -73,8 +73,8 @@ module Punchblock
73
73
  offer = Event::Offer.new
74
74
  offer.call_id = '9f00061'
75
75
  offer.to = 'sip:whatever@127.0.0.1'
76
- say = <<-MSG
77
- <say xmlns='urn:xmpp:tropo:say:1' voice='allison'>
76
+ output = <<-MSG
77
+ <output xmlns='urn:xmpp:tropo:say:1'>
78
78
  <audio url='http://acme.com/greeting.mp3'>
79
79
  Thanks for calling ACME company
80
80
  </audio>
@@ -82,16 +82,16 @@ module Punchblock
82
82
  Your package was shipped on
83
83
  </audio>
84
84
  <say-as interpret-as='date'>12/01/2011</say-as>
85
- </say>
85
+ </output>
86
86
  MSG
87
- Component::Tropo::Say
88
- say = RayoNode.import parse_stanza(say).root
87
+ Component::Output
88
+ output = RayoNode.import parse_stanza(output).root
89
89
  connection.expects(:write_to_stream).once.returns true
90
90
  iq = Blather::Stanza::Iq.new :set, '9f00061@call.rayo.net'
91
91
  connection.expects(:create_iq).returns iq
92
92
 
93
93
  write_thread = Thread.new do
94
- connection.write offer.call_id, say
94
+ connection.write offer.call_id, output
95
95
  end
96
96
 
97
97
  result = import_stanza <<-MSG
@@ -106,22 +106,22 @@ module Punchblock
106
106
 
107
107
  write_thread.join
108
108
 
109
- say.state_name.should == :executing
109
+ output.state_name.should == :executing
110
110
 
111
- connection.original_component_from_id('fgh4590').should == say
111
+ connection.original_component_from_id('fgh4590').should == output
112
112
 
113
113
  example_complete = import_stanza <<-MSG
114
114
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
115
115
  <complete xmlns='urn:xmpp:rayo:ext:1'>
116
- <success xmlns='urn:xmpp:tropo:say:complete:1' />
116
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
117
117
  </complete>
118
118
  </presence>
119
119
  MSG
120
120
 
121
121
  connection.__send__ :handle_presence, example_complete
122
- say.complete_event(0.5).source.should == say
122
+ output.complete_event(0.5).source.should == output
123
123
 
124
- say.component_id.should == 'fgh4590'
124
+ output.component_id.should == 'fgh4590'
125
125
  end
126
126
 
127
127
  it 'should send a "Chat" presence when ready' do
@@ -164,7 +164,7 @@ module Punchblock
164
164
  <<-MSG
165
165
  <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
166
166
  <complete xmlns='urn:xmpp:rayo:ext:1'>
167
- <success xmlns='urn:xmpp:tropo:say:complete:1' />
167
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
168
168
  </complete>
169
169
  </presence>
170
170
  MSG
@@ -11,7 +11,7 @@ module Punchblock
11
11
  let :stanza do
12
12
  <<-MESSAGE
13
13
  <complete xmlns='urn:xmpp:rayo:ext:1'>
14
- <success xmlns='urn:xmpp:tropo:say:complete:1' />
14
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
15
15
  </complete>
16
16
  MESSAGE
17
17
  end
@@ -22,7 +22,7 @@ module Punchblock
22
22
 
23
23
  it_should_behave_like 'event'
24
24
 
25
- its(:reason) { should be_instance_of Component::Tropo::Say::Complete::Success }
25
+ its(:reason) { should be_instance_of Component::Output::Complete::Success }
26
26
  end
27
27
  end
28
28
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: punchblock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2011-12-28 00:00:00.000000000 Z
14
+ date: 2012-01-06 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: niceogiri
18
- requirement: &2164396920 !ruby/object:Gem::Requirement
18
+ requirement: &2152641860 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ! '>='
@@ -23,21 +23,21 @@ dependencies:
23
23
  version: 0.0.4
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *2164396920
26
+ version_requirements: *2152641860
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: blather
29
- requirement: &2164396380 !ruby/object:Gem::Requirement
29
+ requirement: &2152641280 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ! '>='
33
33
  - !ruby/object:Gem::Version
34
- version: 0.5.9
34
+ version: 0.5.12
35
35
  type: :runtime
36
36
  prerelease: false
37
- version_requirements: *2164396380
37
+ version_requirements: *2152641280
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: activesupport
40
- requirement: &2164395740 !ruby/object:Gem::Requirement
40
+ requirement: &2152640660 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ! '>='
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: 2.1.0
46
46
  type: :runtime
47
47
  prerelease: false
48
- version_requirements: *2164395740
48
+ version_requirements: *2152640660
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: state_machine
51
- requirement: &2164395120 !ruby/object:Gem::Requirement
51
+ requirement: &2152639980 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ! '>='
@@ -56,10 +56,10 @@ dependencies:
56
56
  version: 1.0.1
57
57
  type: :runtime
58
58
  prerelease: false
59
- version_requirements: *2164395120
59
+ version_requirements: *2152639980
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: future-resource
62
- requirement: &2164394580 !ruby/object:Gem::Requirement
62
+ requirement: &2152639220 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
65
65
  - - ! '>='
@@ -67,10 +67,10 @@ dependencies:
67
67
  version: 0.0.2
68
68
  type: :runtime
69
69
  prerelease: false
70
- version_requirements: *2164394580
70
+ version_requirements: *2152639220
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: has-guarded-handlers
73
- requirement: &2164393880 !ruby/object:Gem::Requirement
73
+ requirement: &2152638480 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
76
  - - ! '>='
@@ -78,10 +78,10 @@ dependencies:
78
78
  version: 0.1.0
79
79
  type: :runtime
80
80
  prerelease: false
81
- version_requirements: *2164393880
81
+ version_requirements: *2152638480
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: celluloid
84
- requirement: &2164392120 !ruby/object:Gem::Requirement
84
+ requirement: &2152637500 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ! '>='
@@ -89,10 +89,10 @@ dependencies:
89
89
  version: 0.6.0
90
90
  type: :runtime
91
91
  prerelease: false
92
- version_requirements: *2164392120
92
+ version_requirements: *2152637500
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: ruby_ami
95
- requirement: &2164391380 !ruby/object:Gem::Requirement
95
+ requirement: &2152636520 !ruby/object:Gem::Requirement
96
96
  none: false
97
97
  requirements:
98
98
  - - ! '>='
@@ -100,10 +100,10 @@ dependencies:
100
100
  version: 0.1.3
101
101
  type: :runtime
102
102
  prerelease: false
103
- version_requirements: *2164391380
103
+ version_requirements: *2152636520
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: ruby_speech
106
- requirement: &2164390440 !ruby/object:Gem::Requirement
106
+ requirement: &2152635380 !ruby/object:Gem::Requirement
107
107
  none: false
108
108
  requirements:
109
109
  - - ! '>='
@@ -111,10 +111,10 @@ dependencies:
111
111
  version: 0.3.4
112
112
  type: :runtime
113
113
  prerelease: false
114
- version_requirements: *2164390440
114
+ version_requirements: *2152635380
115
115
  - !ruby/object:Gem::Dependency
116
116
  name: bundler
117
- requirement: &2164389600 !ruby/object:Gem::Requirement
117
+ requirement: &2152634520 !ruby/object:Gem::Requirement
118
118
  none: false
119
119
  requirements:
120
120
  - - ~>
@@ -122,10 +122,10 @@ dependencies:
122
122
  version: 1.0.0
123
123
  type: :development
124
124
  prerelease: false
125
- version_requirements: *2164389600
125
+ version_requirements: *2152634520
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: rspec
128
- requirement: &2164353240 !ruby/object:Gem::Requirement
128
+ requirement: &2152633440 !ruby/object:Gem::Requirement
129
129
  none: false
130
130
  requirements:
131
131
  - - ! '>='
@@ -133,10 +133,10 @@ dependencies:
133
133
  version: 2.5.0
134
134
  type: :development
135
135
  prerelease: false
136
- version_requirements: *2164353240
136
+ version_requirements: *2152633440
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: ci_reporter
139
- requirement: &2164352260 !ruby/object:Gem::Requirement
139
+ requirement: &2152632400 !ruby/object:Gem::Requirement
140
140
  none: false
141
141
  requirements:
142
142
  - - ! '>='
@@ -144,10 +144,10 @@ dependencies:
144
144
  version: 1.6.3
145
145
  type: :development
146
146
  prerelease: false
147
- version_requirements: *2164352260
147
+ version_requirements: *2152632400
148
148
  - !ruby/object:Gem::Dependency
149
149
  name: yard
150
- requirement: &2164351080 !ruby/object:Gem::Requirement
150
+ requirement: &2152631620 !ruby/object:Gem::Requirement
151
151
  none: false
152
152
  requirements:
153
153
  - - ~>
@@ -155,10 +155,10 @@ dependencies:
155
155
  version: 0.6.0
156
156
  type: :development
157
157
  prerelease: false
158
- version_requirements: *2164351080
158
+ version_requirements: *2152631620
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rcov
161
- requirement: &2164350380 !ruby/object:Gem::Requirement
161
+ requirement: &2152630600 !ruby/object:Gem::Requirement
162
162
  none: false
163
163
  requirements:
164
164
  - - ! '>='
@@ -166,10 +166,10 @@ dependencies:
166
166
  version: '0'
167
167
  type: :development
168
168
  prerelease: false
169
- version_requirements: *2164350380
169
+ version_requirements: *2152630600
170
170
  - !ruby/object:Gem::Dependency
171
171
  name: rake
172
- requirement: &2164348740 !ruby/object:Gem::Requirement
172
+ requirement: &2152629520 !ruby/object:Gem::Requirement
173
173
  none: false
174
174
  requirements:
175
175
  - - ! '>='
@@ -177,10 +177,10 @@ dependencies:
177
177
  version: '0'
178
178
  type: :development
179
179
  prerelease: false
180
- version_requirements: *2164348740
180
+ version_requirements: *2152629520
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: mocha
183
- requirement: &2164348020 !ruby/object:Gem::Requirement
183
+ requirement: &2152622020 !ruby/object:Gem::Requirement
184
184
  none: false
185
185
  requirements:
186
186
  - - ! '>='
@@ -188,10 +188,10 @@ dependencies:
188
188
  version: '0'
189
189
  type: :development
190
190
  prerelease: false
191
- version_requirements: *2164348020
191
+ version_requirements: *2152622020
192
192
  - !ruby/object:Gem::Dependency
193
193
  name: i18n
194
- requirement: &2164347400 !ruby/object:Gem::Requirement
194
+ requirement: &2152620880 !ruby/object:Gem::Requirement
195
195
  none: false
196
196
  requirements:
197
197
  - - ! '>='
@@ -199,10 +199,10 @@ dependencies:
199
199
  version: '0'
200
200
  type: :development
201
201
  prerelease: false
202
- version_requirements: *2164347400
202
+ version_requirements: *2152620880
203
203
  - !ruby/object:Gem::Dependency
204
204
  name: countdownlatch
205
- requirement: &2164346700 !ruby/object:Gem::Requirement
205
+ requirement: &2152619940 !ruby/object:Gem::Requirement
206
206
  none: false
207
207
  requirements:
208
208
  - - ! '>='
@@ -210,10 +210,10 @@ dependencies:
210
210
  version: '0'
211
211
  type: :development
212
212
  prerelease: false
213
- version_requirements: *2164346700
213
+ version_requirements: *2152619940
214
214
  - !ruby/object:Gem::Dependency
215
215
  name: guard-rspec
216
- requirement: &2164346200 !ruby/object:Gem::Requirement
216
+ requirement: &2152619460 !ruby/object:Gem::Requirement
217
217
  none: false
218
218
  requirements:
219
219
  - - ! '>='
@@ -221,7 +221,7 @@ dependencies:
221
221
  version: '0'
222
222
  type: :development
223
223
  prerelease: false
224
- version_requirements: *2164346200
224
+ version_requirements: *2152619460
225
225
  description: Like Rack is to Rails and Sinatra, Punchblock provides a consistent API
226
226
  on top of several underlying third-party call control protocols.
227
227
  email: punchblock@adhearsion.com
@@ -265,10 +265,7 @@ files:
265
265
  - lib/punchblock/component/record.rb
266
266
  - lib/punchblock/component/stop.rb
267
267
  - lib/punchblock/component/tropo.rb
268
- - lib/punchblock/component/tropo/ask.rb
269
268
  - lib/punchblock/component/tropo/conference.rb
270
- - lib/punchblock/component/tropo/say.rb
271
- - lib/punchblock/component/tropo/transfer.rb
272
269
  - lib/punchblock/connection.rb
273
270
  - lib/punchblock/connection/asterisk.rb
274
271
  - lib/punchblock/connection/connected.rb
@@ -277,6 +274,7 @@ files:
277
274
  - lib/punchblock/core_ext/blather/stanza.rb
278
275
  - lib/punchblock/core_ext/blather/stanza/presence.rb
279
276
  - lib/punchblock/core_ext/ruby.rb
277
+ - lib/punchblock/disconnected_error.rb
280
278
  - lib/punchblock/event.rb
281
279
  - lib/punchblock/event/answered.rb
282
280
  - lib/punchblock/event/asterisk.rb
@@ -326,10 +324,7 @@ files:
326
324
  - spec/punchblock/component/input_spec.rb
327
325
  - spec/punchblock/component/output_spec.rb
328
326
  - spec/punchblock/component/record_spec.rb
329
- - spec/punchblock/component/tropo/ask_spec.rb
330
327
  - spec/punchblock/component/tropo/conference_spec.rb
331
- - spec/punchblock/component/tropo/say_spec.rb
332
- - spec/punchblock/component/tropo/transfer_spec.rb
333
328
  - spec/punchblock/connection/asterisk_spec.rb
334
329
  - spec/punchblock/connection/xmpp_spec.rb
335
330
  - spec/punchblock/event/answered_spec.rb
@@ -366,7 +361,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
366
361
  version: '0'
367
362
  segments:
368
363
  - 0
369
- hash: 1241799790800462241
364
+ hash: -4143902595723607278
370
365
  required_rubygems_version: !ruby/object:Gem::Requirement
371
366
  none: false
372
367
  requirements:
@@ -399,10 +394,7 @@ test_files:
399
394
  - spec/punchblock/component/input_spec.rb
400
395
  - spec/punchblock/component/output_spec.rb
401
396
  - spec/punchblock/component/record_spec.rb
402
- - spec/punchblock/component/tropo/ask_spec.rb
403
397
  - spec/punchblock/component/tropo/conference_spec.rb
404
- - spec/punchblock/component/tropo/say_spec.rb
405
- - spec/punchblock/component/tropo/transfer_spec.rb
406
398
  - spec/punchblock/connection/asterisk_spec.rb
407
399
  - spec/punchblock/connection/xmpp_spec.rb
408
400
  - spec/punchblock/event/answered_spec.rb