cloudi 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data.tar.gz.sig +1 -0
  2. data/README.markdown +7 -0
  3. data/lib/cloudi.rb +668 -0
  4. metadata +117 -0
  5. metadata.gz.sig +0 -0
data.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ 1LȅsH����?/�"E1�3#������{v������]x=���[��|�N��[��YI�9c���s��`9)O�� kc���5p>����W*�g6����i��1C�1�90-�/����e�1�dk28�"b2�o"��&g9�:�u$�@$��I�U��exW4�����=�F���s��<�=f�=%�����>��Ct�'�@һ4}�:�V_��B�A���ll�B8��_��_��:��c�:�Q
data/README.markdown ADDED
@@ -0,0 +1,7 @@
1
+ `cloudi_api_ruby`
2
+ =================
3
+
4
+ [![Build Status](https://travis-ci.org/CloudI/cloudi_api_ruby.png)](https://travis-ci.org/CloudI/cloudi_api_ruby)
5
+
6
+ Ruby [CloudI API](http://cloudi.org/api.html#1_Intro)
7
+
data/lib/cloudi.rb ADDED
@@ -0,0 +1,668 @@
1
+ #!/usr/bin/env ruby
2
+ #-*-Mode:ruby;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*-
3
+ # ex: set ft=ruby fenc=utf-8 sts=4 ts=4 sw=4 et:
4
+ #
5
+ # BSD LICENSE
6
+ #
7
+ # Copyright (c) 2011-2014, Michael Truog <mjtruog at gmail dot com>
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright
14
+ # notice, this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright
16
+ # notice, this list of conditions and the following disclaimer in
17
+ # the documentation and/or other materials provided with the
18
+ # distribution.
19
+ # * All advertising materials mentioning features or use of this
20
+ # software must display the following acknowledgment:
21
+ # This product includes software developed by Michael Truog
22
+ # * The name of the author may not be used to endorse or promote
23
+ # products derived from this software without specific prior
24
+ # written permission
25
+ #
26
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
27
+ # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39
+ # DAMAGE.
40
+ #
41
+
42
+ $:.unshift File.dirname(__FILE__)
43
+
44
+ $stdout.sync = true
45
+ $stderr.sync = true
46
+
47
+ require 'erlang'
48
+
49
+ module CloudI
50
+ class API
51
+ include Erlang
52
+ # unbuffered output is with $stderr.puts '...'
53
+
54
+ ASYNC = 1
55
+ SYNC = -1
56
+
57
+ def initialize(thread_index)
58
+ protocol = API.getenv('CLOUDI_API_INIT_PROTOCOL')
59
+ buffer_size_str = API.getenv('CLOUDI_API_INIT_BUFFER_SIZE')
60
+ if protocol == 'tcp'
61
+ @s = IO.for_fd(thread_index + 3, File::RDWR, autoclose: false)
62
+ @s.sync = true
63
+ @use_header = true
64
+ elsif protocol == 'udp'
65
+ @s = IO.for_fd(thread_index + 3, File::RDWR, autoclose: false)
66
+ @s.sync = true
67
+ @use_header = false
68
+ elsif protocol == 'local'
69
+ @s = IO.for_fd(thread_index + 3, File::RDWR, autoclose: false)
70
+ @s.sync = true
71
+ @use_header = true
72
+ else
73
+ raise InvalidInputException
74
+ end
75
+ @initialization_complete = false
76
+ @size = buffer_size_str.to_i
77
+ @callbacks = Hash.new
78
+ send(term_to_binary(:init))
79
+ poll_request(false)
80
+ end
81
+
82
+ def self.thread_count
83
+ s = getenv('CLOUDI_API_INIT_THREAD_COUNT')
84
+ s.to_i
85
+ end
86
+
87
+ def subscribe(pattern, function)
88
+ key = @prefix + pattern
89
+ value = @callbacks.fetch(key, nil)
90
+ if value.nil?
91
+ @callbacks[key] = [function]
92
+ else
93
+ value.push(function)
94
+ end
95
+ send(term_to_binary([:subscribe, pattern]))
96
+ end
97
+
98
+ def unsubscribe(pattern)
99
+ key = @prefix + pattern
100
+ value = @callbacks.fetch(key, nil)
101
+ API.assert{value != nil}
102
+ value.shift
103
+ if value.empty?
104
+ @callbacks.delete(key)
105
+ end
106
+ send(term_to_binary([:unsubscribe, pattern]))
107
+ end
108
+
109
+ def send_async(name, request,
110
+ timeout=nil, request_info=nil, priority=nil)
111
+ if timeout.nil?
112
+ timeout = @timeoutAsync
113
+ end
114
+ if request_info.nil?
115
+ request_info = ''
116
+ end
117
+ if priority.nil?
118
+ priority = @priorityDefault
119
+ end
120
+ send(term_to_binary([:send_async, name,
121
+ OtpErlangBinary.new(request_info),
122
+ OtpErlangBinary.new(request),
123
+ timeout, priority]))
124
+ return poll_request(false)
125
+ end
126
+
127
+ def send_sync(name, request,
128
+ timeout=nil, request_info=nil, priority=nil)
129
+ if timeout.nil?
130
+ timeout = @timeoutSync
131
+ end
132
+ if request_info.nil?
133
+ request_info = ''
134
+ end
135
+ if priority.nil?
136
+ priority = @priorityDefault
137
+ end
138
+ send(term_to_binary([:send_sync, name,
139
+ OtpErlangBinary.new(request_info),
140
+ OtpErlangBinary.new(request),
141
+ timeout, priority]))
142
+ return poll_request(false)
143
+ end
144
+
145
+ def mcast_async(name, request,
146
+ timeout=nil, request_info=nil, priority=nil)
147
+ if timeout.nil?
148
+ timeout = @timeoutAsync
149
+ end
150
+ if request_info.nil?
151
+ request_info = ''
152
+ end
153
+ if priority.nil?
154
+ priority = @priorityDefault
155
+ end
156
+ send(term_to_binary([:mcast_async, name,
157
+ OtpErlangBinary.new(request_info),
158
+ OtpErlangBinary.new(request),
159
+ timeout, priority]))
160
+ return poll_request(false)
161
+ end
162
+
163
+ def forward_(command, name, request_info, request,
164
+ timeout, priority, trans_id, pid)
165
+ case command
166
+ when ASYNC
167
+ forward_async(name, request_info, request,
168
+ timeout, priority, trans_id, pid)
169
+ when SYNC
170
+ forward_sync(name, request_info, request,
171
+ timeout, priority, trans_id, pid)
172
+ end
173
+ end
174
+
175
+ def forward_async(name, request_info, request,
176
+ timeout, priority, trans_id, pid)
177
+ if @requestTimeoutAdjustment
178
+ if timeout == @request_timeout
179
+ elapsed = [0,
180
+ ((Time.now - @request_timer) * 1000.0).floor].max
181
+ if elapsed > timeout
182
+ timeout = 0
183
+ else
184
+ timeout -= elapsed
185
+ end
186
+ end
187
+ end
188
+ send(term_to_binary([:forward_async, name,
189
+ OtpErlangBinary.new(request_info),
190
+ OtpErlangBinary.new(request),
191
+ timeout, priority,
192
+ OtpErlangBinary.new(trans_id), pid]))
193
+ raise ForwardAsyncException.new()
194
+ end
195
+
196
+ def forward_sync(name, request_info, request,
197
+ timeout, priority, trans_id, pid)
198
+ if @requestTimeoutAdjustment
199
+ if timeout == @request_timeout
200
+ elapsed = [0,
201
+ ((Time.now - @request_timer) * 1000.0).floor].max
202
+ if elapsed > timeout
203
+ timeout = 0
204
+ else
205
+ timeout -= elapsed
206
+ end
207
+ end
208
+ end
209
+ send(term_to_binary([:forward_sync, name,
210
+ OtpErlangBinary.new(request_info),
211
+ OtpErlangBinary.new(request),
212
+ timeout, priority,
213
+ OtpErlangBinary.new(trans_id), pid]))
214
+ raise ForwardSyncException.new()
215
+ end
216
+
217
+ def return_(command, name, pattern, response_info, response,
218
+ timeout, trans_id, pid)
219
+ case command
220
+ when ASYNC
221
+ return_async(name, pattern, response_info, response,
222
+ timeout, trans_id, pid)
223
+ when SYNC
224
+ return_sync(name, pattern, response_info, response,
225
+ timeout, trans_id, pid)
226
+ end
227
+ end
228
+
229
+ def return_async(name, pattern, response_info, response,
230
+ timeout, trans_id, pid)
231
+ if @requestTimeoutAdjustment
232
+ if timeout == @request_timeout
233
+ elapsed = [0,
234
+ ((Time.now - @request_timer) * 1000.0).floor].max
235
+ if elapsed > timeout
236
+ response_info = ''
237
+ response = ''
238
+ timeout = 0
239
+ else
240
+ timeout -= elapsed
241
+ end
242
+ end
243
+ end
244
+ send(term_to_binary([:return_async, name, pattern,
245
+ OtpErlangBinary.new(response_info),
246
+ OtpErlangBinary.new(response),
247
+ timeout,
248
+ OtpErlangBinary.new(trans_id), pid]))
249
+ raise ReturnAsyncException.new()
250
+ end
251
+
252
+ def return_sync(name, pattern, response_info, response,
253
+ timeout, trans_id, pid)
254
+ if @requestTimeoutAdjustment
255
+ if timeout == @request_timeout
256
+ elapsed = [0,
257
+ ((Time.now - @request_timer) * 1000.0).floor].max
258
+ if elapsed > timeout
259
+ response_info = ''
260
+ response = ''
261
+ timeout = 0
262
+ else
263
+ timeout -= elapsed
264
+ end
265
+ end
266
+ end
267
+ send(term_to_binary([:return_sync, name, pattern,
268
+ OtpErlangBinary.new(response_info),
269
+ OtpErlangBinary.new(response),
270
+ timeout,
271
+ OtpErlangBinary.new(trans_id), pid]))
272
+ raise ReturnSyncException.new()
273
+ end
274
+
275
+ def recv_async(timeout=nil, trans_id=nil, consume=true)
276
+ if timeout.nil?
277
+ timeout = @timeoutSync
278
+ end
279
+ if trans_id.nil?
280
+ trans_id = 0.chr * 16
281
+ end
282
+ send(term_to_binary([:recv_async, timeout,
283
+ OtpErlangBinary.new(trans_id), consume]))
284
+ return poll_request(false)
285
+ end
286
+
287
+ def process_index
288
+ return @processIndex
289
+ end
290
+
291
+ def process_count
292
+ return @processCount
293
+ end
294
+
295
+ def process_count_max
296
+ return @processCountMax
297
+ end
298
+
299
+ def process_count_min
300
+ return @processCountMin
301
+ end
302
+
303
+ def prefix
304
+ return @prefix
305
+ end
306
+
307
+ def timeout_async
308
+ return @timeoutAsync
309
+ end
310
+
311
+ def timeout_sync
312
+ return @timeoutSync
313
+ end
314
+
315
+ def callback(command, name, pattern, request_info, request,
316
+ timeout, priority, trans_id, pid)
317
+ request_time_start = nil
318
+ if @requestTimeoutAdjustment
319
+ @request_timer = Time.now
320
+ @request_timeout = timeout
321
+ end
322
+ function_queue = @callbacks.fetch(pattern, nil)
323
+ API.assert{function_queue != nil}
324
+ function = function_queue.shift
325
+ function_queue.push(function)
326
+ case command
327
+ when MESSAGE_SEND_ASYNC
328
+ begin
329
+ response = function.call(ASYNC, name, pattern,
330
+ request_info, request,
331
+ timeout, priority, trans_id, pid)
332
+ if response.kind_of?(Array)
333
+ API.assert{response.length == 2}
334
+ response_info = response[0]
335
+ response = response[1]
336
+ if not response_info.kind_of?(String)
337
+ response_info = ''
338
+ end
339
+ else
340
+ response_info = ''
341
+ end
342
+ if not response.kind_of?(String)
343
+ response = ''
344
+ end
345
+ rescue ReturnAsyncException
346
+ return
347
+ rescue ForwardAsyncException
348
+ return
349
+ rescue ReturnSyncException => e
350
+ $stderr.puts e.message
351
+ $stderr.puts e.backtrace
352
+ API.assert{false}
353
+ return
354
+ rescue ForwardSyncException => e
355
+ $stderr.puts e.message
356
+ $stderr.puts e.backtrace
357
+ API.assert{false}
358
+ return
359
+ rescue
360
+ $stderr.puts $!.message
361
+ $stderr.puts $!.backtrace
362
+ response_info = ''
363
+ response = ''
364
+ end
365
+ begin
366
+ return_async(name, pattern, response_info, response,
367
+ timeout, trans_id, pid)
368
+ rescue ReturnAsyncException
369
+ end
370
+ when MESSAGE_SEND_SYNC
371
+ begin
372
+ response = function.call(SYNC, name, pattern,
373
+ request_info, request,
374
+ timeout, priority, trans_id, pid)
375
+ if response.kind_of?(Array)
376
+ API.assert{response.length == 2}
377
+ response_info = response[0]
378
+ response = response[1]
379
+ if not response_info.kind_of?(String)
380
+ response_info = ''
381
+ end
382
+ else
383
+ response_info = ''
384
+ end
385
+ if not response.kind_of?(String)
386
+ response = ''
387
+ end
388
+ rescue ReturnSyncException
389
+ return
390
+ rescue ForwardSyncException
391
+ return
392
+ rescue ReturnAsyncException => e
393
+ $stderr.puts e.message
394
+ $stderr.puts e.backtrace
395
+ API.assert{false}
396
+ return
397
+ rescue ForwardAsyncException => e
398
+ $stderr.puts e.message
399
+ $stderr.puts e.backtrace
400
+ API.assert{false}
401
+ return
402
+ rescue
403
+ $stderr.puts $!.message
404
+ $stderr.puts $!.backtrace
405
+ response_info = ''
406
+ response = ''
407
+ end
408
+ begin
409
+ return_sync(name, pattern, response_info, response,
410
+ timeout, trans_id, pid)
411
+ rescue ReturnSyncException
412
+ end
413
+ else
414
+ raise MessageDecodingException
415
+ end
416
+ end
417
+
418
+ def poll_request(external)
419
+ if external and not @initialization_complete
420
+ send(term_to_binary(:polling))
421
+ @initialization_complete = true
422
+ end
423
+
424
+ ready = false
425
+ while ready == false
426
+ result = IO.select([@s], nil, [@s])
427
+ if result[2].length > 0
428
+ return nil
429
+ end
430
+ if result[0].length > 0
431
+ ready = true
432
+ end
433
+ end
434
+
435
+ data = recv('')
436
+ if data.bytesize == 0
437
+ return nil
438
+ end
439
+
440
+ loop do
441
+ i = 0; j = 4
442
+ command = data[i, j].unpack('L')[0]
443
+ case command
444
+ when MESSAGE_INIT
445
+ i += j; j = 4 + 4 + 4 + 4 + 4
446
+ tmp = data[i, j].unpack('LLLLL')
447
+ @processIndex = tmp[0]
448
+ @processCount = tmp[1]
449
+ @processCountMax = tmp[2]
450
+ @processCountMin = tmp[3]
451
+ prefixSize = tmp[4]
452
+ i += j; j = prefixSize + 4 + 4 + 1 + 1
453
+ tmp = data[i, j].unpack("Z#{prefixSize}LLcC")
454
+ @prefix = tmp[0]
455
+ @timeoutAsync = tmp[1]
456
+ @timeoutSync = tmp[2]
457
+ @priorityDefault = tmp[3]
458
+ @requestTimeoutAdjustment = (tmp[4] != 0)
459
+ i += j
460
+ if i != data.length
461
+ raise MessageDecodingException
462
+ end
463
+ return
464
+ when MESSAGE_SEND_ASYNC, MESSAGE_SEND_SYNC
465
+ i += j; j = 4
466
+ nameSize = data[i, j].unpack('L')[0]
467
+ i += j; j = nameSize + 4
468
+ tmp = data[i, j].unpack("Z#{nameSize}L")
469
+ name = tmp[0]
470
+ patternSize = tmp[1]
471
+ i += j; j = patternSize + 4
472
+ tmp = data[i, j].unpack("Z#{patternSize}L")
473
+ pattern = tmp[0]
474
+ requestInfoSize = tmp[1]
475
+ i += j; j = requestInfoSize + 1 + 4
476
+ tmp = data[i, j].unpack("a#{requestInfoSize}xL")
477
+ request_info = tmp[0]
478
+ requestSize = tmp[1]
479
+ i += j; j = requestSize + 1 + 4 + 1 + 16 + 4
480
+ tmp = data[i, j].unpack("a#{requestSize}xLca16L")
481
+ request = tmp[0]
482
+ timeout = tmp[1]
483
+ priority = tmp[2]
484
+ trans_id = tmp[3]
485
+ pidSize = tmp[4]
486
+ i += j; j = pidSize
487
+ pid = data[i, j].unpack("a#{pidSize}")[0]
488
+ i += j
489
+ if i != data.length
490
+ raise MessageDecodingException
491
+ end
492
+ data.clear()
493
+ callback(command, name, pattern, request_info, request,
494
+ timeout, priority, trans_id, binary_to_term(pid))
495
+ when MESSAGE_RECV_ASYNC, MESSAGE_RETURN_SYNC
496
+ i += j; j = 4
497
+ responseInfoSize = data[i, j].unpack('L')[0]
498
+ i += j; j = responseInfoSize + 1 + 4
499
+ tmp = data[i, j].unpack("a#{responseInfoSize}xL")
500
+ response_info = tmp[0]
501
+ responseSize = tmp[1]
502
+ i += j; j = responseSize + 1 + 16
503
+ tmp = data[i, j].unpack("a#{responseSize}xa16")
504
+ response = tmp[0]
505
+ trans_id = tmp[1]
506
+ i += j
507
+ if i != data.length
508
+ raise MessageDecodingException
509
+ end
510
+ return [response_info, response, trans_id]
511
+ when MESSAGE_RETURN_ASYNC
512
+ i += j; j = 16
513
+ trans_id = data[i, j].unpack('a16')[0]
514
+ i += j
515
+ if i != data.length
516
+ raise MessageDecodingException
517
+ end
518
+ return trans_id
519
+ when MESSAGE_RETURNS_ASYNC
520
+ i += j; j = 4
521
+ transIdCount = data[i, j].unpack('L')[0]
522
+ i += j; j = 16 * transIdCount
523
+ transIdList = data[i, j].unpack('a16' * transIdCount)
524
+ i += j
525
+ if i != data.length
526
+ raise MessageDecodingException
527
+ end
528
+ return transIdList
529
+ when MESSAGE_KEEPALIVE
530
+ send(term_to_binary(:keepalive))
531
+ i += j
532
+ if i < data.length
533
+ raise MessageDecodingException
534
+ end
535
+ data.slice!(0, i)
536
+ if data.length > 0
537
+ if IO.select([@s], nil, nil, 0).nil?
538
+ next
539
+ end
540
+ end
541
+ else
542
+ raise MessageDecodingException
543
+ end
544
+
545
+ ready = false
546
+ while ready == false
547
+ result = IO.select([@s], nil, [@s])
548
+ if result[2].length > 0
549
+ return nil
550
+ end
551
+ if result[0].length > 0
552
+ ready = true
553
+ end
554
+ end
555
+
556
+ data = recv(data)
557
+ if data.bytesize == 0
558
+ return nil
559
+ end
560
+ end
561
+ end
562
+
563
+ def poll
564
+ poll_request(true)
565
+ end
566
+
567
+ def binary_key_value_parse(binary)
568
+ result = {}
569
+ data = binary.split(NULL.chr)
570
+ (0...(data.length)).step(2).each do |i|
571
+ value = result[data[i]]
572
+ if value == nil
573
+ result[data[i]] = data[i + 1]
574
+ elsif value.kind_of?(Array)
575
+ value << data[i + 1]
576
+ else
577
+ result[data[i]] = [value, data[i + 1]]
578
+ end
579
+ end
580
+ result
581
+ end
582
+
583
+ def request_http_qs_parse(request)
584
+ binary_key_value_parse(request)
585
+ end
586
+
587
+ def info_key_value_parse(message_info)
588
+ binary_key_value_parse(message_info)
589
+ end
590
+
591
+ def self.assert
592
+ raise 'Assertion failed !' unless yield # if $DEBUG
593
+ end
594
+
595
+ private :callback
596
+ private :poll_request
597
+ private :binary_key_value_parse
598
+ private
599
+
600
+ def send(data)
601
+ if @use_header
602
+ data = [data.length].pack('N') + data
603
+ end
604
+ @s.write(data)
605
+ end
606
+
607
+ def recv(data)
608
+ if @use_header
609
+ while data.length < 4
610
+ fragment = @s.readpartial(@size)
611
+ data += fragment
612
+ end
613
+ total = data[0,4].unpack('N')[0]
614
+ data.slice!(0..3)
615
+ while data.length < total
616
+ fragment = @s.readpartial(@size)
617
+ data += fragment
618
+ end
619
+ else
620
+ ready = true
621
+ while ready == true
622
+ fragment = @s.readpartial(@size)
623
+ data += fragment
624
+ ready = (fragment.bytesize == @size)
625
+
626
+ if ready
627
+ ready = ! IO.select([@s], nil, nil, 0).nil?
628
+ end
629
+ end
630
+ end
631
+ data
632
+ end
633
+
634
+ MESSAGE_INIT = 1
635
+ MESSAGE_SEND_ASYNC = 2
636
+ MESSAGE_SEND_SYNC = 3
637
+ MESSAGE_RECV_ASYNC = 4
638
+ MESSAGE_RETURN_ASYNC = 5
639
+ MESSAGE_RETURN_SYNC = 6
640
+ MESSAGE_RETURNS_ASYNC = 7
641
+ MESSAGE_KEEPALIVE = 8
642
+
643
+ NULL = 0
644
+
645
+ def self.getenv(key)
646
+ ENV[key] or raise InvalidInputException
647
+ end
648
+ end
649
+
650
+ class InvalidInputException < Exception
651
+ end
652
+
653
+ class ReturnSyncException < Exception
654
+ end
655
+
656
+ class ReturnAsyncException < Exception
657
+ end
658
+
659
+ class ForwardSyncException < Exception
660
+ end
661
+
662
+ class ForwardAsyncException < Exception
663
+ end
664
+
665
+ class MessageDecodingException < Exception
666
+ end
667
+ end
668
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Truog
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain:
12
+ - ! '-----BEGIN CERTIFICATE-----
13
+
14
+ MIIDMDCCAhigAwIBAgIBADANBgkqhkiG9w0BAQUFADA+MRAwDgYDVQQDDAdtanRy
15
+
16
+ dW9nMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
17
+
18
+ HhcNMTQwNjI0MjAzMDQ2WhcNMTUwNjI0MjAzMDQ2WjA+MRAwDgYDVQQDDAdtanRy
19
+
20
+ dW9nMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
21
+
22
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBOoI/CUuwOhXjks02cT58
23
+
24
+ jLxgsOQ412Xzu4eEKqzNsWMoj/3+qYdb5CR4+51EHtuJHZ8hndL5DTYIO8ylcG11
25
+
26
+ EvyxqOzU+gqC53gCEBhJLivlyMXvGqL8qHPuSKGEMc1Vpzh0WicwNnaT7z3X6aQP
27
+
28
+ UE6qWd1yE9jT7TX+GKcKayBJTufxcBMjtwvzMH4IiVaNjUBHBq2LbeNO1yDPYVzV
29
+
30
+ HWnZCv75vIXdUruFrSZcJgNRYRwzMfHEbf+BcvqqGVV6p3PJgJMrjI8FZ7roIJNf
31
+
32
+ D7ZO96x4ItjGazoTntAZe3EM9QB5Wjsd1cv2IEOISQ6jyvVX5E84Al+MEKhhhFuL
33
+
34
+ AgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFACw0UcBaNl2dQWwgg/Qzeyf
35
+
36
+ cKG7MAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAHjLn+8F8yeOFcKst
37
+
38
+ mKA3m28OIoICMefZOiJfTC9UkVkW+554IXNBu3vVxLc0nlCqmuf/aQGaFBUm9MLA
39
+
40
+ oD5CmlrU9OrEl2fPxqTHAwFgLNre8e2EWtm2OhBg73JTHRVVyBLpSK5GRUDzhJtZ
41
+
42
+ 7a2ocAE2AgFKpISNxIUe4Zz9O2thg3iryLh9prjETJTUfxDjBmHdx+YkNAblRa2w
43
+
44
+ k9A+nCZzZECcR5ZZYSeaK6MCugGmXUhAkDbuWumCzu/RAghlVC9RFFQt7o1SwGQp
45
+
46
+ LdvYOeJbviyiH1q1rC3NAJNC4P7Q41zx1OYa8S9M5qn+JpE0ZsomnZyGunWaya9Q
47
+
48
+ bTD/aw==
49
+
50
+ -----END CERTIFICATE-----
51
+
52
+ '
53
+ date: 2014-06-24 00:00:00.000000000 Z
54
+ dependencies:
55
+ - !ruby/object:Gem::Dependency
56
+ name: erlang_rb
57
+ requirement: &11610740 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.3'
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 1.3.2
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *11610740
69
+ - !ruby/object:Gem::Dependency
70
+ name: erlang_rb
71
+ requirement: &11608600 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: 1.3.2
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: *11608600
83
+ description: Ruby CloudI API
84
+ email: mjtruog@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files:
88
+ - README.markdown
89
+ files:
90
+ - lib/cloudi.rb
91
+ - README.markdown
92
+ homepage: http://cloudi.org
93
+ licenses:
94
+ - BSD
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.11
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: CloudI API
117
+ test_files: []
metadata.gz.sig ADDED
Binary file