electric_slide 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/LICENSE +7 -0
- data/README.markdown +3 -0
- data/Rakefile +16 -0
- data/config/ahn_acd.yml +1 -0
- data/electric_slide.gemspec +32 -0
- data/lib/electric_slide.rb +65 -0
- data/lib/electric_slide/queue_strategy.rb +18 -0
- data/lib/electric_slide/queued_call.rb +24 -0
- data/lib/electric_slide/round_robin.rb +46 -0
- data/lib/electric_slide/round_robin_meetme.rb +34 -0
- data/spec/electric_slide/queue_strategy_spec.rb +16 -0
- data/spec/electric_slide/queued_call_spec.rb +42 -0
- data/spec/electric_slide/round_robin_spec.rb +87 -0
- data/spec/electric_slide_spec.rb +1 -0
- data/spec/spec_helper.rb +25 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6b6b7652ebb0629af9310a93d7c6ac0352fd92c8
|
4
|
+
data.tar.gz: f5fd82735d7d8949b14a4ea8ee318c096820092f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b9bafc665557361a51d504d71d94d2775a8e68924a22600e23a68f8b53acb7a2fcb85a3197e797e0c8af7cccc272f606d63f651c9a654f0aa9e2dc2aa69ac7a
|
7
|
+
data.tar.gz: 85da4abe01db3cd099748cc11ada5c59383c38b8ac1e1994adaa01f98d9d6af05db659e767e6dae6cdef3c4fbae42c414689d9af2d09a670142b1355ec820caa
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2011 The Adhearsion Foundation, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# -*- ruby -*-
|
4
|
+
ENV['RUBY_FLAGS'] = "-I#{%w(lib ext bin spec).join(File::PATH_SEPARATOR)}"
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'bundler/gem_tasks'
|
8
|
+
require 'bundler/setup'
|
9
|
+
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
RSpec::Core::RakeTask.new
|
12
|
+
|
13
|
+
require 'ci/reporter/rake/rspec'
|
14
|
+
task :ci => ['ci:setup:rspec', :spec]
|
15
|
+
task :default => :spec
|
16
|
+
|
data/config/ahn_acd.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# You can use this file for component-specific configuration.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "electric_slide"
|
5
|
+
s.version = "0.0.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ben Klang"]
|
9
|
+
|
10
|
+
s.date = Date.today.to_s
|
11
|
+
s.description = "Automatic Call Distributor (ACD) for Adhearsion. Currently implements only Round Robin distribution strategies."
|
12
|
+
s.email = "dev&adhearsion.com"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.homepage = "http://github.com/adhearsion/electric_slide"
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubygems_version = "1.2.0"
|
20
|
+
s.summary = "Automatic Call Distributor for Adhearsion"
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'adhearsion'
|
23
|
+
s.add_runtime_dependency 'countdownlatch'
|
24
|
+
s.add_runtime_dependency 'activesupport'
|
25
|
+
s.add_development_dependency 'rspec', ['>= 2.5.0']
|
26
|
+
s.add_development_dependency 'flexmock', ['>= 0.9.0']
|
27
|
+
s.add_development_dependency 'ci_reporter'
|
28
|
+
s.add_development_dependency 'simplecov'
|
29
|
+
s.add_development_dependency 'simplecov-rcov'
|
30
|
+
|
31
|
+
s.specification_version = 2
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'active_support/dependencies/autoload'
|
3
|
+
require 'adhearsion/foundation/thread_safety'
|
4
|
+
|
5
|
+
class ElectricSlide < Adhearsion::Plugin
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :QueueStrategy
|
9
|
+
autoload :RoundRobin
|
10
|
+
autoload :RoundRobinMeetme
|
11
|
+
|
12
|
+
include Singleton
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@queues = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(name, queue_type, agent_type = Agent)
|
19
|
+
synchronize do
|
20
|
+
@queues[name] = queue_type.new unless @queues.has_key?(name)
|
21
|
+
@queues[name].extend agent_type
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_queue(name)
|
26
|
+
synchronize do
|
27
|
+
@queues[name]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.method_missing(method, *args, &block)
|
32
|
+
instance.send method, *args, &block
|
33
|
+
end
|
34
|
+
|
35
|
+
module Agent
|
36
|
+
def work(agent_call)
|
37
|
+
loop do
|
38
|
+
agent_call.execute 'Bridge', @queue.next_call
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class CalloutAgent
|
44
|
+
def work(agent_channel)
|
45
|
+
@queue.next_call.each do |next_call|
|
46
|
+
next_call.dial agent_channel
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class MeetMeAgent
|
52
|
+
include Agent
|
53
|
+
|
54
|
+
def work(agent_call)
|
55
|
+
loop do
|
56
|
+
agent_call.join agent_conf, @queue.next_call
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class BridgeAgent
|
62
|
+
include Agent
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class ElectricSlide
|
2
|
+
module QueueStrategy
|
3
|
+
def wrap_call(call)
|
4
|
+
call = QueuedCall.new(call) unless call.respond_to?(:queued_time)
|
5
|
+
call
|
6
|
+
end
|
7
|
+
|
8
|
+
def priority_enqueue(call)
|
9
|
+
# TODO: Add this call to the front of the line
|
10
|
+
enqueue call
|
11
|
+
end
|
12
|
+
|
13
|
+
def enqueue(call)
|
14
|
+
call.hold
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'countdownlatch'
|
2
|
+
|
3
|
+
class ElectricSlide
|
4
|
+
class QueuedCall
|
5
|
+
attr_accessor :call, :queued_time
|
6
|
+
|
7
|
+
def initialize(call)
|
8
|
+
@call = call
|
9
|
+
@queued_time = Time.now
|
10
|
+
end
|
11
|
+
|
12
|
+
def hold
|
13
|
+
call.execute 'StartMusicOnHold'
|
14
|
+
@latch = CountDownLatch.new 1
|
15
|
+
@latch.wait
|
16
|
+
call.execute 'StopMusicOnHold'
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_ready!
|
20
|
+
@latch.countdown!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'electric_slide/queue_strategy'
|
3
|
+
|
4
|
+
class ElectricSlide
|
5
|
+
class RoundRobin
|
6
|
+
include QueueStrategy
|
7
|
+
attr_reader :queue
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@queue = []
|
11
|
+
@agents_waiting = []
|
12
|
+
@conditional = ConditionVariable.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def next_call
|
16
|
+
call = nil
|
17
|
+
synchronize do
|
18
|
+
@agents_waiting << Thread.current
|
19
|
+
@conditional.wait(@mutex) if @queue.length == 0
|
20
|
+
@agents_waiting.delete Thread.current
|
21
|
+
call = @queue.shift
|
22
|
+
end
|
23
|
+
|
24
|
+
call.make_ready!
|
25
|
+
call
|
26
|
+
end
|
27
|
+
|
28
|
+
def agents_waiting
|
29
|
+
synchronize do
|
30
|
+
@agents_waiting.dup
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO: Add mechanism to add calls with higher priority to the front of the queue.
|
35
|
+
|
36
|
+
def enqueue(call)
|
37
|
+
call = wrap_call(call)
|
38
|
+
synchronize do
|
39
|
+
@queue << call
|
40
|
+
@conditional.signal if @queue.length == 1
|
41
|
+
end
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class ElectricSlide
|
2
|
+
class RoundRobinMeetme
|
3
|
+
include QueueStrategy
|
4
|
+
|
5
|
+
def initialize(call)
|
6
|
+
@queue = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def next_call
|
10
|
+
call = synchronize do
|
11
|
+
@queue.pop
|
12
|
+
end
|
13
|
+
|
14
|
+
call.make_ready!
|
15
|
+
call
|
16
|
+
end
|
17
|
+
|
18
|
+
def priority_enqueue(call)
|
19
|
+
call = wrap_call(call)
|
20
|
+
|
21
|
+
synchronize do
|
22
|
+
@queue.unshift call
|
23
|
+
end
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def enqueue(call)
|
28
|
+
synchronize do
|
29
|
+
@queue << call
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElectricSlide::QueueStrategy do
|
4
|
+
include ElectricSlide::QueueStrategy
|
5
|
+
|
6
|
+
describe '#wrap_call' do
|
7
|
+
it 'should pass through a QueuedCall object' do
|
8
|
+
obj = ElectricSlide::QueuedCall.new dummy_call
|
9
|
+
wrap_call(obj).should be obj
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should wrap any object that does not respond to #queued_time' do
|
13
|
+
wrap_call(dummy_call).should be_a ElectricSlide::QueuedCall
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElectricSlide::QueuedCall do
|
4
|
+
it 'should initialize the queued_time to the current time' do
|
5
|
+
now = Time.now
|
6
|
+
flexmock(Time).should_receive(:now).once.and_return now
|
7
|
+
qcall = ElectricSlide::QueuedCall.new dummy_call
|
8
|
+
qcall.instance_variable_get(:@queued_time).should == now
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should start and stop music on hold when put on hold and released' do
|
12
|
+
# Both tests are combined here so we do not leave too many suspended threads lying about
|
13
|
+
queued_caller = dummy_call
|
14
|
+
flexmock(queued_caller).should_receive(:execute).once.with('StartMusicOnHold')
|
15
|
+
flexmock(queued_caller).should_receive(:execute).once.with('StopMusicOnHold')
|
16
|
+
qcall = ElectricSlide::QueuedCall.new queued_caller
|
17
|
+
|
18
|
+
# Place the call on hold and wait for it to enqueue
|
19
|
+
Thread.new { qcall.hold }
|
20
|
+
sleep 0.5
|
21
|
+
|
22
|
+
# Release the call from being on hold and sleep to ensure we get the Stop MOH signal
|
23
|
+
qcall.make_ready!
|
24
|
+
sleep 0.5
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should block the call when put on hold' do
|
28
|
+
queued_caller = dummy_call
|
29
|
+
flexmock(queued_caller).should_receive(:execute).once.with('StartMusicOnHold')
|
30
|
+
flexmock(queued_caller).should_receive(:execute).once.with('StopMusicOnHold')
|
31
|
+
qcall = ElectricSlide::QueuedCall.new queued_caller
|
32
|
+
|
33
|
+
hold_thread = Thread.new { qcall.hold }
|
34
|
+
|
35
|
+
# Give the holding thread a chance to block...
|
36
|
+
sleep 0.5
|
37
|
+
hold_thread.status.should == "sleep"
|
38
|
+
qcall.make_ready!
|
39
|
+
sleep 0.5
|
40
|
+
hold_thread.status.should be false
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElectricSlide::RoundRobin do
|
4
|
+
def dummy_queued_call
|
5
|
+
dqc = ElectricSlide::QueuedCall.new dummy_call
|
6
|
+
flexmock(dqc).should_receive(:hold).once
|
7
|
+
flexmock(dqc).should_receive(:make_ready!).once
|
8
|
+
dqc
|
9
|
+
end
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
@queue = ElectricSlide::RoundRobin.new
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "Queue is empty at start" do
|
16
|
+
subject { ElectricSlide::RoundRobin.new }
|
17
|
+
its(:queue) { should have(0).items }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should properly enqueue a call' do
|
21
|
+
call = ElectricSlide::QueuedCall.new dummy_call
|
22
|
+
flexmock(call).should_receive(:hold).once
|
23
|
+
@queue.enqueue call
|
24
|
+
@queue.instance_variable_get(:@queue).first.should be call
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return the call object that is passed in' do
|
28
|
+
call = dummy_queued_call
|
29
|
+
@queue.enqueue call
|
30
|
+
@queue.next_call.should be call
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should block an agent requesting a call until a call becomes available' do
|
34
|
+
call = dummy_queued_call
|
35
|
+
agent_thread = Thread.new { @queue.next_call }
|
36
|
+
|
37
|
+
# Give the agent thread a chance to block...
|
38
|
+
sleep 0.5
|
39
|
+
|
40
|
+
@queue.agents_waiting.count.should == 1
|
41
|
+
|
42
|
+
@queue.enqueue call
|
43
|
+
|
44
|
+
# Give the agent thread a chance to retrieve the call...
|
45
|
+
sleep 0.5
|
46
|
+
@queue.agents_waiting.count.should == 0
|
47
|
+
agent_thread.kill
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should unblock only one agent per call entering the queue' do
|
51
|
+
call = dummy_queued_call
|
52
|
+
agent1_thread = Thread.new { @queue.next_call }
|
53
|
+
agent2_thread = Thread.new { @queue.next_call }
|
54
|
+
|
55
|
+
# Give the agent threads a chance to block...
|
56
|
+
sleep 0.5
|
57
|
+
|
58
|
+
@queue.agents_waiting.count.should == 2
|
59
|
+
|
60
|
+
@queue.enqueue call
|
61
|
+
|
62
|
+
# Give the agent thread a chance to retrieve the call...
|
63
|
+
sleep 0.5
|
64
|
+
@queue.agents_waiting.count.should == 1
|
65
|
+
agent1_thread.kill
|
66
|
+
agent2_thread.kill
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should properly enqueue calls and return them in the same order' do
|
70
|
+
call1 = dummy_queued_call
|
71
|
+
call2 = dummy_queued_call
|
72
|
+
call3 = dummy_queued_call
|
73
|
+
threads = {}
|
74
|
+
|
75
|
+
threads[:call1] = Thread.new { @queue.enqueue call1 }
|
76
|
+
sleep 0.5
|
77
|
+
threads[:call2] = Thread.new { @queue.enqueue call2 }
|
78
|
+
sleep 0.5
|
79
|
+
threads[:call3] = Thread.new { @queue.enqueue call3 }
|
80
|
+
sleep 0.5
|
81
|
+
|
82
|
+
|
83
|
+
@queue.next_call.should be call1
|
84
|
+
@queue.next_call.should be call2
|
85
|
+
@queue.next_call.should be call3
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'spec_helper'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
Thread.abort_on_exception = true
|
3
|
+
|
4
|
+
%w{
|
5
|
+
adhearsion
|
6
|
+
electric_slide
|
7
|
+
electric_slide/queued_call
|
8
|
+
electric_slide/queue_strategy
|
9
|
+
electric_slide/round_robin
|
10
|
+
rspec/core
|
11
|
+
flexmock
|
12
|
+
flexmock/rspec
|
13
|
+
}.each { |r| require r }
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.mock_framework = :flexmock
|
17
|
+
config.filter_run :focus => true
|
18
|
+
config.run_all_when_everything_filtered = true
|
19
|
+
config.color_enabled = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def dummy_call
|
23
|
+
Object.new
|
24
|
+
end
|
25
|
+
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: electric_slide
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Klang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: adhearsion
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: countdownlatch
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.5.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.5.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: flexmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.9.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.9.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ci_reporter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov-rcov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Automatic Call Distributor (ACD) for Adhearsion. Currently implements
|
126
|
+
only Round Robin distribution strategies.
|
127
|
+
email: dev&adhearsion.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- Gemfile
|
134
|
+
- LICENSE
|
135
|
+
- README.markdown
|
136
|
+
- Rakefile
|
137
|
+
- config/ahn_acd.yml
|
138
|
+
- electric_slide.gemspec
|
139
|
+
- lib/electric_slide.rb
|
140
|
+
- lib/electric_slide/queue_strategy.rb
|
141
|
+
- lib/electric_slide/queued_call.rb
|
142
|
+
- lib/electric_slide/round_robin.rb
|
143
|
+
- lib/electric_slide/round_robin_meetme.rb
|
144
|
+
- spec/electric_slide/queue_strategy_spec.rb
|
145
|
+
- spec/electric_slide/queued_call_spec.rb
|
146
|
+
- spec/electric_slide/round_robin_spec.rb
|
147
|
+
- spec/electric_slide_spec.rb
|
148
|
+
- spec/spec_helper.rb
|
149
|
+
homepage: http://github.com/adhearsion/electric_slide
|
150
|
+
licenses: []
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubyforge_project:
|
168
|
+
rubygems_version: 2.0.3
|
169
|
+
signing_key:
|
170
|
+
specification_version: 2
|
171
|
+
summary: Automatic Call Distributor for Adhearsion
|
172
|
+
test_files: []
|
173
|
+
has_rdoc: true
|