flotype-bridge 0.2.0.beta.1 → 0.2.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  #Flotype Bridge for Javascript
2
- Flotype Bridge enables cross-language RPC for interserver and client-server communication.
2
+ Flotype Bridge is a unified messaging system that allows you to easily build cross-language services to share data and realtime updates among your servers and your clients
3
3
 
4
4
  ##Installation
5
5
  Quick install: Using [RubyGems](https://rubygems.org/), do `gem install flotype-bridge --pre`
@@ -16,8 +16,8 @@ Clone this repository using `git clone git@bitbucket.org:flotype/bridge-ruby.git
16
16
  loop.
17
17
 
18
18
  ##Documentation and Support
19
- * API Reference: http://www.flotype.com/resources/api
20
- * Getting Started: http://www.flotype.com/resources/gettingstarted
19
+ * API Reference: http://flotype.com/docs/api/ruby/
20
+ * Getting Started: http://www.flotype.com/docs/gettingstarted/ruby/
21
21
  * About Flotype and Flotype Bridge: http://www.flotype.com/
22
22
 
23
23
  The `examples` directory of this library contains sample applications for Flotype Bridge.
@@ -47,7 +47,7 @@
47
47
  <nav id="file-list-section" class="section">
48
48
  <h3 class="section-header">Defined In</h3>
49
49
  <ul>
50
- <li>.\lib\bridge.rb
50
+ <li>lib\bridge.rb
51
51
  </ul>
52
52
  </nav>
53
53
 
@@ -82,6 +82,8 @@
82
82
 
83
83
  <li><a href="#method-i-leave_channel">#leave_channel</a>
84
84
 
85
+ <li><a href="#method-i-on">#on</a>
86
+
85
87
  <li><a href="#method-i-publish_service">#publish_service</a>
86
88
 
87
89
  <li><a href="#method-i-ready">#ready</a>
@@ -192,27 +194,32 @@ server to connect to. Overrides <code>:redirector</code> when both
192
194
 
193
195
 
194
196
  <div class="method-source-code" id="new-source">
195
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 43</span>
197
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 43</span>
196
198
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">options</span> = {})
197
199
 
200
+ <span class="ruby-comment"># Set default options</span>
198
201
  <span class="ruby-ivar">@options</span> = {
199
202
  <span class="ruby-value">:redirector</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-string">'http://redirector.flotype.com'</span>,
200
203
  <span class="ruby-value">:reconnect</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-keyword">true</span>,
201
204
  <span class="ruby-value">:log</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-value">2</span>, <span class="ruby-comment"># 0 for no output</span>
202
205
  }
203
-
206
+
204
207
  <span class="ruby-ivar">@options</span> = <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">options</span>)
205
208
 
206
- <span class="ruby-constant">Util</span>.<span class="ruby-identifier">set_log_level</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value">:log</span>]);
209
+ <span class="ruby-constant">Util</span>.<span class="ruby-identifier">set_log_level</span>(<span class="ruby-ivar">@options</span>[<span class="ruby-value">:log</span>])
207
210
 
208
211
  <span class="ruby-ivar">@store</span> = {}
212
+ <span class="ruby-comment"># Initialize system service call</span>
209
213
  <span class="ruby-ivar">@store</span>[<span class="ruby-string">'system'</span>] = <span class="ruby-constant">SystemService</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>)
210
214
 
215
+ <span class="ruby-comment"># Indicates whether server is connected and handshaken</span>
211
216
  <span class="ruby-ivar">@is_ready</span> = <span class="ruby-keyword">false</span>
212
217
 
218
+ <span class="ruby-comment"># Create connection object</span>
213
219
  <span class="ruby-ivar">@connection</span> = <span class="ruby-constant">Connection</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>)
214
220
 
215
- <span class="ruby-ivar">@queue</span> = []
221
+ <span class="ruby-comment"># Store event handlers</span>
222
+ <span class="ruby-ivar">@events</span> = {}
216
223
 
217
224
  <span class="ruby-keyword">end</span></pre>
218
225
  </div><!-- new-source -->
@@ -255,7 +262,7 @@ href="Bridge.html">Bridge</a> is connected and ready.</p>
255
262
 
256
263
 
257
264
  <div class="method-source-code" id="connect-source">
258
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 224</span>
265
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 269</span>
259
266
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">connect</span> &amp;<span class="ruby-identifier">callback</span>
260
267
  <span class="ruby-keyword">self</span>.<span class="ruby-identifier">ready</span> &amp;<span class="ruby-identifier">callback</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">callback</span>
261
268
  <span class="ruby-ivar">@connection</span>.<span class="ruby-identifier">start</span>
@@ -318,8 +325,9 @@ channel name.</p>
318
325
 
319
326
 
320
327
  <div class="method-source-code" id="get_channel-source">
321
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 158</span>
328
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 203</span>
322
329
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">get_channel</span> <span class="ruby-identifier">name</span>, &amp;<span class="ruby-identifier">callback</span>
330
+ <span class="ruby-comment"># Send GETCHANNEL command in order to establih link for channel if client is not member</span>
323
331
  <span class="ruby-ivar">@connection</span>.<span class="ruby-identifier">send_command</span>(<span class="ruby-value">:GETCHANNEL</span>, {<span class="ruby-value">:name</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">name</span>})
324
332
  <span class="ruby-identifier">ref</span> = <span class="ruby-constant">Reference</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>, [<span class="ruby-string">'channel'</span>, <span class="ruby-identifier">name</span>, <span class="ruby-node">&quot;channel:#{name}&quot;</span>])
325
333
  <span class="ruby-identifier">callback</span>.<span class="ruby-identifier">call</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-identifier">name</span>) <span class="ruby-keyword">if</span> <span class="ruby-identifier">callback</span>
@@ -382,7 +390,7 @@ service name.</p>
382
390
 
383
391
 
384
392
  <div class="method-source-code" id="get_service-source">
385
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 134</span>
393
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 179</span>
386
394
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">get_service</span> <span class="ruby-identifier">name</span>, &amp;<span class="ruby-identifier">callback</span>
387
395
  <span class="ruby-identifier">ref</span> = <span class="ruby-constant">Reference</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>, [<span class="ruby-string">'named'</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">name</span>])
388
396
  <span class="ruby-identifier">callback</span>.<span class="ruby-identifier">call</span>(<span class="ruby-identifier">ref</span>, <span class="ruby-identifier">name</span>) <span class="ruby-keyword">if</span> <span class="ruby-identifier">callback</span>
@@ -439,7 +447,7 @@ channel</p>
439
447
 
440
448
 
441
449
  <div class="method-source-code" id="join_channel-source">
442
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 179</span>
450
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 225</span>
443
451
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">join_channel</span> <span class="ruby-identifier">name</span>, <span class="ruby-identifier">handler</span>, &amp;<span class="ruby-identifier">callback</span>
444
452
  <span class="ruby-ivar">@connection</span>.<span class="ruby-identifier">send_command</span>(<span class="ruby-value">:JOINCHANNEL</span>, {<span class="ruby-value">:name</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">name</span>, <span class="ruby-value">:handler</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Serializer</span>.<span class="ruby-identifier">serialize</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">handler</span>), <span class="ruby-value">:callback</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Serializer</span>.<span class="ruby-identifier">serialize</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">callback</span>)})
445
453
  <span class="ruby-keyword">end</span></pre>
@@ -499,7 +507,7 @@ calls from the channel</p>
499
507
 
500
508
 
501
509
  <div class="method-source-code" id="leave_channel-source">
502
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 198</span>
510
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 244</span>
503
511
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">leave_channel</span> <span class="ruby-identifier">channel</span>, <span class="ruby-identifier">handler</span>, &amp;<span class="ruby-identifier">callback</span>
504
512
  <span class="ruby-ivar">@connection</span>.<span class="ruby-identifier">send_command</span>(<span class="ruby-value">:LEAVECHANNEL</span>, {<span class="ruby-value">:name</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">name</span>, <span class="ruby-value">:handler</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Serializer</span>.<span class="ruby-identifier">serialize</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">handler</span>), <span class="ruby-value">:callback</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-constant">Serializer</span>.<span class="ruby-identifier">serialize</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">callback</span>)})
505
513
  <span class="ruby-keyword">end</span></pre>
@@ -513,6 +521,65 @@ calls from the channel</p>
513
521
  </div><!-- leave_channel-method -->
514
522
 
515
523
 
524
+ <div id="method-i-on" class="method-detail ">
525
+
526
+
527
+ <div class="method-heading">
528
+ <span class="method-callseq">
529
+ on(name) { |*args| block }
530
+ </span>
531
+
532
+ <span class="method-click-advice">click to toggle source</span>
533
+
534
+ </div>
535
+
536
+
537
+
538
+ <div class="method-description">
539
+
540
+ <p>Adds the given block as a handler for the event specified by
541
+ <code>name</code>. Calling multiple times will result in multiple handlers
542
+ being attached to the event</p>
543
+
544
+ <h3 id="method-i-on-label-Attributes++">Attributes </h3>
545
+ <dl class="rdoc-list note-list"><dt><code>name</code>
546
+ <dd>
547
+ <p>The name of the event for the given block to listen to</p>
548
+ </dd></dl>
549
+
550
+ <h3 id="method-i-on-label-Events++">Events </h3>
551
+
552
+ <p>List of events <a href="Bridge.html">Bridge</a> emits</p>
553
+ <dl class="rdoc-list note-list"><dt><code>'ready' ()</code>
554
+ <dd>
555
+ <p><a href="Bridge.html">Bridge</a> is connected and ready. Not emitted on
556
+ reconnects</p>
557
+ </dd><dt><code>'remoteError' (error_message)</code>
558
+ <dd>
559
+ <p>A remote error has occurred in <a href="Bridge.html">Bridge</a>. The error
560
+ message is provided as a parameter</p>
561
+ </dd></dl>
562
+
563
+
564
+
565
+ <div class="method-source-code" id="on-source">
566
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 121</span>
567
+ <span class="ruby-keyword">def</span> <span class="ruby-identifier">on</span> <span class="ruby-identifier">name</span>, &amp;<span class="ruby-identifier">fn</span>
568
+ <span class="ruby-keyword">if</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@events</span>.<span class="ruby-identifier">key?</span> <span class="ruby-identifier">name</span>
569
+ <span class="ruby-ivar">@events</span>[<span class="ruby-identifier">name</span>] = [];
570
+ <span class="ruby-keyword">end</span>
571
+ <span class="ruby-ivar">@events</span>[<span class="ruby-identifier">name</span>] <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">fn</span>
572
+ <span class="ruby-keyword">end</span></pre>
573
+ </div><!-- on-source -->
574
+
575
+ </div>
576
+
577
+
578
+
579
+
580
+ </div><!-- on-method -->
581
+
582
+
516
583
  <div id="method-i-publish_service" class="method-detail ">
517
584
 
518
585
 
@@ -548,7 +615,7 @@ be published with</p>
548
615
 
549
616
 
550
617
  <div class="method-source-code" id="publish_service-source">
551
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 107</span>
618
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 152</span>
552
619
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">publish_service</span> <span class="ruby-identifier">name</span>, <span class="ruby-identifier">handler</span>, &amp;<span class="ruby-identifier">callback</span>
553
620
  <span class="ruby-keyword">if</span> <span class="ruby-identifier">name</span> <span class="ruby-operator">==</span> <span class="ruby-string">'system'</span>
554
621
  <span class="ruby-constant">Util</span>.<span class="ruby-identifier">error</span>(<span class="ruby-node">&quot;Invalid service name: #{name}&quot;</span>)
@@ -590,13 +657,12 @@ href="Bridge.html">Bridge</a> is already ready.</p>
590
657
 
591
658
 
592
659
  <div class="method-source-code" id="ready-source">
593
- <pre><span class="ruby-comment"># File .\lib\bridge.rb, line 208</span>
660
+ <pre><span class="ruby-comment"># File lib\bridge.rb, line 254</span>
594
661
  <span class="ruby-keyword">def</span> <span class="ruby-identifier">ready</span> &amp;<span class="ruby-identifier">callback</span>
595
- <span class="ruby-identifier">puts</span> <span class="ruby-string">'adding'</span>
596
662
  <span class="ruby-keyword">if</span> <span class="ruby-ivar">@is_ready</span>
597
663
  <span class="ruby-identifier">callback</span>.<span class="ruby-identifier">call</span>
598
664
  <span class="ruby-keyword">else</span>
599
- <span class="ruby-ivar">@queue</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">callback</span>
665
+ <span class="ruby-identifier">on</span> <span class="ruby-string">'ready'</span>, &amp;<span class="ruby-identifier">callback</span>
600
666
  <span class="ruby-keyword">end</span>
601
667
  <span class="ruby-keyword">end</span></pre>
602
668
  </div><!-- ready-source -->
data/doc/Bridge.html CHANGED
@@ -47,7 +47,7 @@
47
47
  <nav id="file-list-section" class="section">
48
48
  <h3 class="section-header">Defined In</h3>
49
49
  <ul>
50
- <li>.\lib\bridge.rb
50
+ <li>lib\bridge.rb
51
51
  </ul>
52
52
  </nav>
53
53
 
data/doc/created.rid CHANGED
@@ -1,2 +1,2 @@
1
- Fri, 23 Mar 2012 13:01:16 -0700
2
- .\lib\bridge.rb Fri, 23 Mar 2012 13:01:02 -0700
1
+ Sat, 07 Apr 2012 02:37:02 -0700
2
+ lib\bridge.rb Sat, 07 Apr 2012 02:36:34 -0700
@@ -1 +1 @@
1
- var search_data = {"index":{"searchIndex":["bridge","bridge","connect()","get_channel()","get_service()","join_channel()","leave_channel()","new()","publish_service()","ready()"],"longSearchIndex":["bridge","bridge::bridge","bridge::bridge#connect()","bridge::bridge#get_channel()","bridge::bridge#get_service()","bridge::bridge#join_channel()","bridge::bridge#leave_channel()","bridge::bridge::new()","bridge::bridge#publish_service()","bridge::bridge#ready()"],"info":[["Bridge","","Bridge.html","","<p>Flotype Bridge\n<p>Bridge is a cross-language and platform framework for realtime\ncommunication and RPC\n<p>The ...\n"],["Bridge::Bridge","","Bridge/Bridge.html","",""],["connect","Bridge::Bridge","Bridge/Bridge.html#method-i-connect","(&callback)","<p>Starts the connection to the Bridge server.\n<p>If a block is given, calls the given block when Bridge is ...\n"],["get_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-get_channel","(name, &callback)","<p>Retrives a channel from Bridge with the given name.\n<p>Calling a method on the channel object will result ...\n"],["get_service","Bridge::Bridge","Bridge/Bridge.html#method-i-get_service","(name, &callback)","<p>Retrives a service published to Bridge with the given name.\n<p>If multiple Bridge clients have a published ...\n"],["join_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-join_channel","(name, handler, &callback)","<p>Provides a remote object, ruby object or module as a receiver for methods\ncalls on a Bridge channel. ...\n"],["leave_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-leave_channel","(channel, handler, &callback)","<p>Leaves a Bridge channel with the given name and handler object.\n<p>The given handler can be a remote object, ...\n"],["new","Bridge::Bridge","Bridge/Bridge.html#method-c-new","(options = {})","<p>Create an instance of the Bridge object. This object will be used for\nBridge interactions\n<p>Bridge#connect ...\n"],["publish_service","Bridge::Bridge","Bridge/Bridge.html#method-i-publish_service","(name, handler, &callback)","<p>Publishes a ruby object or module as a Bridge service with the given name.\n<p>If a block is given, calls ...\n"],["ready","Bridge::Bridge","Bridge/Bridge.html#method-i-ready","(&callback)","<p>Calls the given block when Bridge is connected and ready. Calls the given\nblock immediately if Bridge ...\n"]]}}
1
+ var search_data = {"index":{"searchIndex":["bridge","bridge","connect()","get_channel()","get_service()","join_channel()","leave_channel()","new()","on()","publish_service()","ready()"],"longSearchIndex":["bridge","bridge::bridge","bridge::bridge#connect()","bridge::bridge#get_channel()","bridge::bridge#get_service()","bridge::bridge#join_channel()","bridge::bridge#leave_channel()","bridge::bridge::new()","bridge::bridge#on()","bridge::bridge#publish_service()","bridge::bridge#ready()"],"info":[["Bridge","","Bridge.html","","<p>Flotype Bridge\n<p>Bridge is a cross-language and platform framework for realtime\ncommunication and RPC\n<p>The ...\n"],["Bridge::Bridge","","Bridge/Bridge.html","",""],["connect","Bridge::Bridge","Bridge/Bridge.html#method-i-connect","(&callback)","<p>Starts the connection to the Bridge server.\n<p>If a block is given, calls the given block when Bridge is ...\n"],["get_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-get_channel","(name, &callback)","<p>Retrives a channel from Bridge with the given name.\n<p>Calling a method on the channel object will result ...\n"],["get_service","Bridge::Bridge","Bridge/Bridge.html#method-i-get_service","(name, &callback)","<p>Retrives a service published to Bridge with the given name.\n<p>If multiple Bridge clients have a published ...\n"],["join_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-join_channel","(name, handler, &callback)","<p>Provides a remote object, ruby object or module as a receiver for methods\ncalls on a Bridge channel. ...\n"],["leave_channel","Bridge::Bridge","Bridge/Bridge.html#method-i-leave_channel","(channel, handler, &callback)","<p>Leaves a Bridge channel with the given name and handler object.\n<p>The given handler can be a remote object, ...\n"],["new","Bridge::Bridge","Bridge/Bridge.html#method-c-new","(options = {})","<p>Create an instance of the Bridge object. This object will be used for\nBridge interactions\n<p>Bridge#connect ...\n"],["on","Bridge::Bridge","Bridge/Bridge.html#method-i-on","(name, &fn)","<p>Adds the given block as a handler for the event specified by\n<code>name</code>. Calling multiple times will result ...\n"],["publish_service","Bridge::Bridge","Bridge/Bridge.html#method-i-publish_service","(name, handler, &callback)","<p>Publishes a ruby object or module as a Bridge service with the given name.\n<p>If a block is given, calls ...\n"],["ready","Bridge::Bridge","Bridge/Bridge.html#method-i-ready","(&callback)","<p>Calls the given block when Bridge is connected and ready. Calls the given\nblock immediately if Bridge ...\n"]]}}
@@ -55,6 +55,8 @@
55
55
 
56
56
  <li class="method"><a href="Bridge/Bridge.html#method-i-leave_channel">#leave_channel &mdash; Bridge::Bridge</a>
57
57
 
58
+ <li class="method"><a href="Bridge/Bridge.html#method-i-on">#on &mdash; Bridge::Bridge</a>
59
+
58
60
  <li class="method"><a href="Bridge/Bridge.html#method-i-publish_service">#publish_service &mdash; Bridge::Bridge</a>
59
61
 
60
62
  <li class="method"><a href="Bridge/Bridge.html#method-i-ready">#ready &mdash; Bridge::Bridge</a>
@@ -0,0 +1,21 @@
1
+ require 'bridge'
2
+
3
+ EventMachine.run do
4
+
5
+ bridge = Bridge::Bridge.new(:api_key => 'myapikey')
6
+
7
+ class ChatHandler
8
+ def message sender, msg
9
+ puts "#{sender}: #{msg}"
10
+ end
11
+ end
12
+
13
+ bridge.connect
14
+
15
+ auth = bridge.get_service('auth')
16
+ auth.join('flotype-lovers', 'secret123', ChatHandler.new) do |channel, name|
17
+ puts "Joined: #{name}"
18
+ channel.message('steve', 'Flotype Bridge is nifty')
19
+ end
20
+
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'bridge'
2
+
3
+ EventMachine.run do
4
+
5
+ bridge = Bridge::Bridge.new(:api_key => 'myapikey')
6
+
7
+ class AuthHandler
8
+ def initialize bridge
9
+ @bridge = bridge
10
+ end
11
+
12
+ def join name, password, handler, &callback
13
+ if password == 'secret123'
14
+ @bridge.join_channel(name, handler, &callback)
15
+ puts 'Welcome!'
16
+ else
17
+ puts 'Sorry!'
18
+ end
19
+ end
20
+ end
21
+
22
+ bridge.connect
23
+ bridge.publish_service('auth', AuthHandler.new(bridge))
24
+ end
@@ -0,0 +1,47 @@
1
+ require 'bridge'
2
+
3
+ EventMachine.run do
4
+ bridge = Bridge::Bridge.new(:api_key => 'myapikey')
5
+ bridge.connect
6
+
7
+
8
+ #
9
+ # Joining a Bridge channel
10
+ #
11
+ # In order to join a Bridge channel, clients must provide the name
12
+ # of the channel to join and a handler object on which RPC calls
13
+ # in the channel will act on. Note that the client that is joined
14
+ # to the channel is whoever created the handler, not necessarily the
15
+ # client executing the join command. This means clients can join other
16
+ # clients to channels by having a reference to an object of theirs.
17
+ #
18
+ # Only Bridge clients using the private API key may call the join command.
19
+ # However, those clients may join other clients using the public API key on their behalf.
20
+ #
21
+ class TestHandler
22
+ def log msg
23
+ puts "Got message: #{msg}"
24
+ end
25
+ end
26
+
27
+ bridge.join_channel 'testChannel', TestHandler.new do
28
+ ready bridge
29
+ end
30
+
31
+ def ready bridge
32
+ #
33
+ # Getting and calling a Bridge channel
34
+ #
35
+ # This can be done from any Bridge client connected to the same
36
+ # Bridge server, regardless of language.
37
+ # When a function call is made to a channel object, the requested
38
+ # function will be executed on everyone in the channel
39
+ #
40
+ # Only Bridge clients using the private API key may call the join command.
41
+ #
42
+ bridge.get_channel 'testChannel' do |testChannel, name|
43
+ puts 'Sending message'
44
+ testChannel.log 'hello'
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ require 'bridge'
2
+
3
+ EventMachine.run do
4
+ bridge = Bridge::Bridge.new(:api_key => 'myapikey')
5
+ bridge.connect
6
+
7
+
8
+ #
9
+ # Publishing a Bridge service
10
+ #
11
+ # Any Javascript object can be published. A published service
12
+ # can be retrieved by any Bridge client with the same API key pair.
13
+ #
14
+ # Only Bridge clients using the prviate API key may publish services.
15
+ #
16
+ class TestService
17
+ def ping
18
+ puts 'Received ping request!'
19
+ yield 'Pong'
20
+ end
21
+ end
22
+
23
+ bridge.publish_service 'testService', TestService.new
24
+
25
+
26
+
27
+ #
28
+ # Retrieving a Bridge service
29
+ #
30
+ # This can be done from any Bridge client connected to the same
31
+ # Bridge server, regardless of language.
32
+ # If multiple clients publish a Bridge service, getService will
33
+ # retrieve from the publisher with the least load.
34
+ #
35
+ bridge.get_service 'testService' do |testService, name|
36
+ puts 'Sending ping request'
37
+ testService.ping do |msg|
38
+ puts msg
39
+ end
40
+ end
41
+ end
data/lib/bridge.rb CHANGED
@@ -17,7 +17,7 @@ module Bridge
17
17
 
18
18
  class Bridge
19
19
 
20
- attr_accessor :options, :connection, :queue, :store, :is_ready #:nodoc:
20
+ attr_accessor :options, :connection, :store, :is_ready #:nodoc:
21
21
 
22
22
  # :call-seq:
23
23
  # new(options={})
@@ -63,8 +63,8 @@ module Bridge
63
63
  # Create connection object
64
64
  @connection = Connection.new(self)
65
65
 
66
- # Store ready event handler
67
- @queue = []
66
+ # Store event handlers
67
+ @events = {}
68
68
 
69
69
  end
70
70
 
@@ -103,6 +103,36 @@ module Bridge
103
103
  Reference.new(self, ['client', @connection.client_id, name], ops)
104
104
  end
105
105
 
106
+ # :call-seq:
107
+ # on(name) { |*args| block }
108
+ #
109
+ # Adds the given block as a handler for the event specified by <tt>name</tt>. Calling multiple times will result in multiple handlers being attached to the event
110
+ #
111
+ # === Attributes
112
+ #
113
+ # +name+:: The name of the event for the given block to listen to
114
+ #
115
+ # === Events
116
+ #
117
+ # List of events Bridge emits
118
+ #
119
+ # <tt>'ready' ()</tt>:: Bridge is connected and ready. Not emitted on reconnects
120
+ # <tt>'remoteError' (error_message)</tt>:: A remote error has occurred in Bridge. The error message is provided as a parameter
121
+ def on name, &fn
122
+ if !@events.key? name
123
+ @events[name] = [];
124
+ end
125
+ @events[name] << fn
126
+ end
127
+
128
+ def emit name, args=[] #:nodoc:
129
+ if @events.key? name
130
+ @events[name].each do |fn|
131
+ fn.call *args
132
+ end
133
+ end
134
+ end
135
+
106
136
  def send args, destination #:nodoc:
107
137
  @connection.send_command(:SEND, { :args => Serializer.serialize(self, args), :destination => destination })
108
138
  end
@@ -225,7 +255,7 @@ module Bridge
225
255
  if @is_ready
226
256
  callback.call
227
257
  else
228
- @queue << callback
258
+ on 'ready', &callback
229
259
  end
230
260
  end
231
261
 
@@ -246,21 +276,21 @@ module Bridge
246
276
  # Erlang gateway.
247
277
  class SystemService #:nodoc:
248
278
  def initialize bridge
249
- @store = bridge.store
279
+ @bridge = bridge
250
280
  end
251
281
 
252
282
  def hookChannelHandler name, handler, callback = nil
253
283
  # Retrieve requested handler
254
- obj = @store[handler.address[2]]
284
+ obj = @bridge.store[handler.address[2]]
255
285
  # Store under channel name
256
- @store["channel:#{name}"] = obj
286
+ @bridge.store["channel:#{name}"] = obj
257
287
  # Send callback with reference to channel and handler operations
258
288
  callback.call(Reference.new(self, ['channel', name, "channel:#{name}"], Util.find_ops(obj)), name) if callback
259
289
  end
260
290
 
261
291
  def getService name, callback
262
- if @store.key? name
263
- callback.call(@store[name], name)
292
+ if @bridge.store.key? name
293
+ callback.call(@bridge.store[name], name)
264
294
  else
265
295
  callback.call(nil, name)
266
296
  end
@@ -268,6 +298,7 @@ module Bridge
268
298
 
269
299
  def remoteError msg
270
300
  Util.warn msg
301
+ @bridge.emit 'remote_error', [msg]
271
302
  end
272
303
  end
273
304
 
data/lib/connection.rb CHANGED
@@ -81,10 +81,8 @@ module Bridge
81
81
  Util.info('Handshake complete')
82
82
  # Trigger ready callback
83
83
  if not @bridge.is_ready
84
- @bridge.queue.each do |fun|
85
- fun.call
86
- end
87
84
  @bridge.is_ready = true
85
+ @bridge.emit 'ready'
88
86
  end
89
87
  end
90
88
  end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bridge
2
- VERSION = "0.2.0.beta.1"
2
+ VERSION = "0.2.0.beta.2"
3
3
  end
metadata CHANGED
@@ -1,68 +1,98 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: flotype-bridge
3
- version: !ruby/object:Gem::Version
4
- version: 0.2.0.beta.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 62196359
5
5
  prerelease: 6
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ - beta
11
+ - 2
12
+ version: 0.2.0.beta.2
6
13
  platform: ruby
7
- authors:
14
+ authors:
8
15
  - Flotype
9
16
  autorequire:
10
17
  bindir: bin
11
18
  cert_chain: []
12
- date: 2012-04-06 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
19
+
20
+ date: 2012-04-20 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
15
23
  name: eventmachine
16
- requirement: &70366802877940 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
17
26
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 47
31
+ segments:
32
+ - 0
33
+ - 12
34
+ - 0
21
35
  version: 0.12.0
22
36
  type: :runtime
23
- prerelease: false
24
- version_requirements: *70366802877940
25
- - !ruby/object:Gem::Dependency
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
26
39
  name: json
27
- requirement: &70366802877100 !ruby/object:Gem::Requirement
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
28
42
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 1
49
+ - 5
50
+ - 0
32
51
  version: 1.5.0
33
52
  type: :runtime
34
- prerelease: false
35
- version_requirements: *70366802877100
36
- - !ruby/object:Gem::Dependency
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
37
55
  name: yard
38
- requirement: &70366802876120 !ruby/object:Gem::Requirement
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
39
58
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 7
63
+ segments:
64
+ - 0
65
+ - 7
66
+ - 2
43
67
  version: 0.7.2
44
68
  type: :development
45
- prerelease: false
46
- version_requirements: *70366802876120
47
- - !ruby/object:Gem::Dependency
69
+ version_requirements: *id003
70
+ - !ruby/object:Gem::Dependency
48
71
  name: rake-compiler
49
- requirement: &70366802875420 !ruby/object:Gem::Requirement
72
+ prerelease: false
73
+ requirement: &id004 !ruby/object:Gem::Requirement
50
74
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 17
79
+ segments:
80
+ - 0
81
+ - 7
82
+ - 9
54
83
  version: 0.7.9
55
84
  type: :development
56
- prerelease: false
57
- version_requirements: *70366802875420
85
+ version_requirements: *id004
58
86
  description: Ruby client for Flotype Bridge.
59
- email:
87
+ email:
60
88
  - team@flotype.com
61
89
  executables: []
90
+
62
91
  extensions: []
63
- extra_rdoc_files:
92
+
93
+ extra_rdoc_files:
64
94
  - README.md
65
- files:
95
+ files:
66
96
  - LICENSE
67
97
  - README.md
68
98
  - Rakefile
@@ -102,15 +132,10 @@ files:
102
132
  - doc/js/searcher.js
103
133
  - doc/rdoc.css
104
134
  - doc/table_of_contents.html
105
- - examples/chat/chat_client.rb
106
- - examples/chat/chat_server.rb
107
- - examples/chat/public/css/style.css
108
- - examples/chat/public/js/all.js
109
- - examples/chat/public/js/bridge.min.js
110
- - examples/chat/public/js/index.js
111
- - examples/chat/views/index.erb
112
- - examples/chat/views/layout.erb
113
- - examples/pong/pong.rb
135
+ - examples/chat/chatclient.rb
136
+ - examples/chat/chatserver.rb
137
+ - examples/simple/channels.rb
138
+ - examples/simple/services.rb
114
139
  - flotype-bridge.gemspec
115
140
  - lib/bridge.rb
116
141
  - lib/connection.rb
@@ -135,32 +160,43 @@ files:
135
160
  - test/unit/test_util.rb
136
161
  homepage: http://flotype.com
137
162
  licenses: []
163
+
138
164
  post_install_message:
139
- rdoc_options:
165
+ rdoc_options:
140
166
  - --title
141
167
  - Bridge
142
168
  - --main
143
169
  - README.md
144
170
  - -x
145
171
  - lib/bb/version
146
- require_paths:
172
+ require_paths:
147
173
  - lib
148
- required_ruby_version: !ruby/object:Gem::Requirement
174
+ required_ruby_version: !ruby/object:Gem::Requirement
149
175
  none: false
150
- requirements:
151
- - - ! '>='
152
- - !ruby/object:Gem::Version
153
- version: '0'
154
- required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ hash: 3
180
+ segments:
181
+ - 0
182
+ version: "0"
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
184
  none: false
156
- requirements:
157
- - - ! '>'
158
- - !ruby/object:Gem::Version
185
+ requirements:
186
+ - - ">"
187
+ - !ruby/object:Gem::Version
188
+ hash: 25
189
+ segments:
190
+ - 1
191
+ - 3
192
+ - 1
159
193
  version: 1.3.1
160
194
  requirements: []
195
+
161
196
  rubyforge_project:
162
- rubygems_version: 1.8.10
197
+ rubygems_version: 1.8.7
163
198
  signing_key:
164
199
  specification_version: 3
165
200
  summary: Ruby/Bridge library
166
201
  test_files: []
202
+
@@ -1,21 +0,0 @@
1
- require 'bridge'
2
-
3
- EventMachine.run do
4
-
5
- bridge = Bridge::Bridge.new(:api_key => 'abcdefgh', :log => 5)
6
-
7
- class ChatHandler
8
- def message sender, msg
9
- print sender, ":", msg
10
- end
11
- end
12
-
13
- bridge.connect
14
-
15
- auth = bridge.get_service('auth')
16
- auth.join('flotype-lovers', 'secret123', ChatHandler.new) do |channel, name|
17
- print "Joined: ", name
18
- end
19
-
20
- end
21
-
@@ -1,24 +0,0 @@
1
- require 'bridge'
2
-
3
- EventMachine.run do
4
-
5
- bridge = Bridge::Bridge.new(:api_key => 'abcdefgh')
6
-
7
- class AuthHandler
8
- def initialize bridge
9
- @bridge = bridge
10
- end
11
-
12
- def join name, password, handler, &callback
13
- if password == 'secret123'
14
- @bridge.join_channel(name, handler, &callback)
15
- puts 'Welcome!'
16
- else
17
- puts 'Sorry!'
18
- end
19
- end
20
- end
21
-
22
- bridge.connect
23
- bridge.publish_service('auth', AuthHandler.new(bridge))
24
- end
@@ -1,4 +0,0 @@
1
- html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{font-size:100%;}
2
- a {outline: none;} /* Gets rid of Firefox's dotted borders */
3
- a img {border: none;} /* Gets rid of IE's blue borders */
4
-
@@ -1,5 +0,0 @@
1
- var bridge;
2
- $(function(){
3
- bridge = new Bridge({ apiKey: "abcdefgh" }).connect();
4
- });
5
-
@@ -1,2 +0,0 @@
1
- /*! bridge.min.js build:0.0.1, production. Copyright(c) 2011 Flotype <team@flotype.com> MIT Licensed */
2
- function Reference(a,b,c){var d=this;for(var e in c){var f=c[e];f&&(this[f]=function(a,b){return function(){var c=[].slice.apply(arguments);a._call(b,c)}}(this,f))}this._operations=c||[],this._bridge=a,this._address=b}function Connection(a){var b=this;this.bridge=a,this.options=a._options,this.sockBuffer=new SockBuffer,this.sock=this.sockBuffer,this.interval=400}function SockBuffer(){this.buffer=[]}function Bridge(a){var b=this,c={redirector:"http://redirector.flotype.com",reconnect:!0,log:2,tcp:!1},d={hookChannelHandler:function(a,c,d){var e=b._store[c._address[2]];b._store["channel:"+a]=e;if(d){var f=new Reference(b,["channel",a,"channel:"+a],util.findOps(e));d(f,a)}},getService:function(a,c){util.hasProp(b._store,a)?c(b._store[a],a):c(null,a)},remoteError:function(a){util.warn(a),b.emit("remoteError",[a])}};this._options=util.extend(c,a),util.setLogLevel(this._options.log),this._store={system:d},this._ready=!1,this._connection=new Connection(this),this._events={}}var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";return e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g,e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));return e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g,e}}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),typeof reviver=="function"?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(),SockJS=function(){var a=document,b=window,c=function(){};c.prototype.addEventListener=function(a,b){this._listeners||(this._listeners={}),a in this._listeners||(this._listeners[a]=[]);var c=this._listeners[a];e.arrIndexOf(c,b)===-1&&c.push(b);return},c.prototype.removeEventListener=function(a,b){if(!(this._listeners&&a in this._listeners))return;var c=this._listeners[a],d=e.arrIndexOf(c,b);if(d!==-1){c.length>1?this._listeners[a]=c.slice(0,d).concat(c.slice(d+1)):delete this._listeners[a];return}return},c.prototype.dispatchEvent=function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d<this._listeners[b].length;d++)this._listeners[b][d].apply(this,c)};var d=function(a,b){this.type=a;if(typeof b!="undefined")for(var c in b){if(!b.hasOwnProperty(c))continue;this[c]=b[c]}};d.prototype.toString=function(){var a=[];for(var b in this){if(!this.hasOwnProperty(b))continue;var c=this[b];typeof c=="function"&&(c="[function]"),a.push(b+"="+c)}return"SimpleEvent("+a.join(", ")+")"};var e={},f="abcdefghijklmnopqrstuvwxyz0123456789_";e.random_string=function(a,b){b=b||f.length;var c,d=[];for(c=0;c<a;c++)d.push(f.substr(Math.floor(Math.random()*b),1));return d.join("")},e.random_number=function(a){return Math.floor(Math.random()*a)},e.random_number_string=function(a){var b=(""+(a-1)).length,c=Array(b+1).join("0");return(c+e.random_number(a)).slice(-b)},e.getOrigin=function(a){a+="/";var b=a.split("/").slice(0,3);return b.join("/")},e.objectExtend=function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a};var g="_jp";e.polluteGlobalNamespace=function(){g in b||(b[g]={})},e.closeFrame=function(a,b){return"c"+JSON.stringify([a,b])},e.userSetCode=function(a){return a===1e3||a>=3e3&&a<=4999},e.log=function(){b.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)},e.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b,arguments)}},e.amendUrl=function(b){var c=a.location;if(!b)throw new Error("Wrong url for SockJS");return b.indexOf("//")===0&&(b=c.protocol+b),b.indexOf("/")===0&&(b=c.protocol+"//"+c.host+b),b=b.replace(/[/]+$/,""),b},e.arrIndexOf=function(a,b){for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1},e.delay=function(a,b){return typeof a=="function"&&(b=a,a=0),setTimeout(b,a)};var h=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,i={"\0":"\\u0000","":"\\u0001","":"\\u0002","":"\\u0003","":"\\u0004","":"\\u0005","":"\\u0006","":"\\u0007","\b":"\\b","\t":"\\t","\n":"\\n"," ":"\\u000b","\f":"\\f","\r":"\\r","":"\\u000e","":"\\u000f","":"\\u0010","":"\\u0011","":"\\u0012","":"\\u0013","":"\\u0014","":"\\u0015","":"\\u0016","":"\\u0017","":"\\u0018","":"\\u0019","":"\\u001a","":"\\u001b","":"\\u001c","":"\\u001d","":"\\u001e","":"\\u001f",'"':'\\"',"\\":"\\\\","":"\\u007f","\u0080":"\\u0080","\u0081":"\\u0081","\u0082":"\\u0082","\u0083":"\\u0083","\u0084":"\\u0084","\u0085":"\\u0085","\u0086":"\\u0086","\u0087":"\\u0087","\u0088":"\\u0088","\u0089":"\\u0089","\u008a":"\\u008a","\u008b":"\\u008b","\u008c":"\\u008c","\u008d":"\\u008d","\u008e":"\\u008e","\u008f":"\\u008f","\u0090":"\\u0090","\u0091":"\\u0091","\u0092":"\\u0092","\u0093":"\\u0093","\u0094":"\\u0094","\u0095":"\\u0095","\u0096":"\\u0096","\u0097":"\\u0097","\u0098":"\\u0098","\u0099":"\\u0099","\u009a":"\\u009a","\u009b":"\\u009b","\u009c":"\\u009c","\u009d":"\\u009d","\u009e":"\\u009e","\u009f":"\\u009f","\u00ad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"},j=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,k,l=JSON&&JSON.stringify||function(a){return h.lastIndex=0,h.test(a)&&(a=a.replace(h,function(a){return i[a]})),'"'+a+'"'},m=function(a){var b,c={},d=[];for(b=0;b<65536;b++)d.push(String.fromCharCode(b));return a.lastIndex=0,d.join("").replace(a,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),a.lastIndex=0,c};e.quote=function(a){var b=l(a);return j.lastIndex=0,j.test(b)?(k||(k=m(j)),b.replace(j,function(a){return k[a]})):b};var n="_sockjs_global";e.createHook=function(){var a="a"+e.random_string(8);if(!(n in b)){var c={};b[n]=function(a){return a in c||(c[a]={id:a,del:function(){delete c[a]}}),c[a]}}return b[n](a)},e.attachMessage=function(a){e.attachEvent("message",a)},e.attachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.addEventListener(c,d,!1):(a.attachEvent("on"+c,d),b.attachEvent("on"+c,d))},e.detachMessage=function(a){e.detachEvent("message",a)},e.detachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.removeEventListener(c,d,!1):(a.detachEvent("on"+c,d),b.detachEvent("on"+c,d))};var o={"User-Agent":"",Accept:"","Accept-Language":"","Content-Type":"text/plain;charset=UTF-8"};navigator&&(navigator.userAgent.indexOf("Chrome")!=-1||navigator.userAgent.indexOf("Safari")!=-1)&&delete o["User-Agent"],e.createXDR=function(a,b,c,d){var f={status:null,responseText:"",readyState:1},g=new XDomainRequest;b+=(b.indexOf("?")===-1?"?":"&")+"t="+e.random_string(8);var h=function(){if(g){i=g.onerror=g.ontimeout=g.onprogress=g.onload=null;try{g.abort()}catch(a){}g=d=null}},i=g.ontimeout=g.onerror=function(){f.status=500,f.readyState=4,d(f),h()};g.onload=function(){f.status=200,f.readyState=4,f.responseText=g.responseText,d(f),h()},g.onprogress=function(){f.status=200,f.readyState=3,f.responseText=g.responseText,d(f)};try{g.open(a,b),g.send(c)}catch(j){e.delay(i)}return function(a){d&&(d(f,null,a),h())}},e.createXHR=function(a,c,d,f){var g;if(b.ActiveXObject){c+=(c.indexOf("?")===-1?"?":"&")+"t="+ +(new Date);try{g=new ActiveXObject("Microsoft.XMLHTTP")}catch(h){}}g||(g=new XMLHttpRequest),g.open(a,c,!0);for(var i in o)try{g.setRequestHeader(i,o[i])}catch(h){delete o[i]}"withCredentials"in g&&(g.withCredentials="true");var j=function(){if(g){try{g.onreadystatechange=null}catch(a){g.onreadystatechange=function(){}}try{g.abort()}catch(b){}e.detachEvent("unload",j)}f=g=null};return g.onreadystatechange=function(a){g&&f&&(f(g,a),g&&g.readyState===4&&j())},g.send(d),e.attachEvent("unload",j),function(a){f&&(f(g,null,a),j())}},e.createIframe=function(b,c){var d=a.createElement("iframe"),f,g=function(){clearTimeout(f);try{d.onload=null}catch(a){}d.onerror=null},h=function(){d&&(g(),d.src="about:blank",setTimeout(function(){d&&d.parentNode.removeChild(d),d=null},0),e.detachEvent("unload",h))},i=function(a){d&&(h(),c(a))};return d.src=b,d.style.display="none",d.style.position="absolute",d.onerror=function(){i("onerror")},d.onload=function(){clearTimeout(f),f=setTimeout(function(){i("onload timeout")},2e3)},a.body.appendChild(d),f=setTimeout(function(){i("timeout")},5e3),e.attachEvent("unload",h),{iframe:d,cleanup:h,loaded:g}},e.createHtmlfile=function(a,c){var d=new ActiveXObject("htmlfile"),f,h,i=function(){clearTimeout(f)},j=function(){if(d){i(),e.detachEvent("unload",j);try{h.src="about:blank"}catch(a){}h.parentNode.removeChild(h),h=d=null,CollectGarbage()}},k=function(a){d&&(j(),c(a))};d.open(),d.write('<html><script>document.domain="'+document.domain+'";'+"</script></html>"),d.close(),d.parentWindow[g]=b[g];var l=d.createElement("div");return d.body.appendChild(l),h=d.createElement("iframe"),l.appendChild(h),h.src=a,f=setTimeout(function(){k("timeout")},5e3),e.attachEvent("unload",j),{iframe:h,cleanup:j,loaded:i}};var p=function(){var b=this,c=function(a){b.state=p[a];var c={state:b.state,name:a};b.dispatchEvent(new d("change",c)),b.dispatchEvent(new d(a,c))};c("init"),a.body?c("load"):e.attachEvent("load",function(){c("load")}),e.attachEvent("beforeunload",function(){c("beforeunload")}),e.attachEvent("unload",function(){c("unload")})};p.prototype=new c,p.init=0,p.load=1,p.beforeunload=2,p.unload=3;var q=new p,r=function(a,b,c){var d=this;d._options={devel:!1,debug:!1,chunking:undefined},c&&e.objectExtend(d._options,c),d._base_url=e.amendUrl(a),d._server=d._options.server||e.random_number_string(1e3),d._connid=e.random_string(8),d._trans_url=d._base_url+"/"+d._server+"/"+d._connid,d._protocols=["websocket","xhr-streaming","iframe-eventsource","iframe-htmlfile","xhr-polling","iframe-xhr-polling","jsonp-polling"];switch(typeof b){case"undefined":break;case"string":d._protocols=[b];break;default:d._protocols=b}d.protocol=null,d.readyState=r.CONNECTING,d._didClose()};r.prototype=new c,r.version="0.1.2",r.CONNECTING=0,r.OPEN=1,r.CLOSING=2,r.CLOSED=3,r.prototype._debug=function(){this._options.debug&&e.log.apply(e,arguments)},r.prototype._dispatchOpen=function(){var a=this;a.readyState===r.CONNECTING?(a._transport_tref&&(clearTimeout(a._transport_tref),a._transport_tref=null),a.readyState=r.OPEN,a.dispatchEvent(new d("open"))):a._didClose(1006,"Server lost session")},r.prototype._dispatchMessage=function(a){var b=this;if(b.readyState!==r.OPEN)return;b.dispatchEvent(new d("message",{data:a}))},r.prototype._dispatchHeartbeat=function(a){var b=this;if(b.readyState!==r.OPEN)return;b.dispatchEvent(new d("heartbeat",{}))},r.prototype._didClose=function(a,b){var c=this;if(c.readyState!==r.CONNECTING&&c.readyState!==r.OPEN&&c.readyState!==r.CLOSING)throw new Error("INVALID_STATE_ERR");c._transport&&c._transport.doCleanup(),c._transport=null,c._transport_tref&&(clearTimeout(c._transport_tref),c._transport_tref=null);var f=new d("close",{code:a,reason:b,wasClean:e.userSetCode(a)});if(!e.userSetCode(a)&&c.readyState===r.CONNECTING){if(c._try_next_protocol(f)){c._transport_tref=setTimeout(function(){c.readyState===r.CONNECTING&&c._didClose(2007,"Transport timeouted")},5001);return}f=new d("close",{code:2e3,reason:"All transports failed",wasClean:!1,last_event:f})}c.readyState=r.CLOSED,e.delay(function(){c.dispatchEvent(f)})},r.prototype._didMessage=function(a){var b=this,c=a.slice(0,1);switch(c){case"o":b._dispatchOpen();break;case"a":var d=JSON.parse(a.slice(1)||"[]");for(var e=0;e<d.length;e++)b._dispatchMessage(d[e]);break;case"m":var d=JSON.parse(a.slice(1)||"null");b._dispatchMessage(d);break;case"c":var d=JSON.parse(a.slice(1)||"[]");b._didClose(d[0],d[1]);break;case"h":b._dispatchHeartbeat()}},r.prototype._try_next_protocol=function(b){var c=this;c.protocol&&(c._debug("Closed transport:",c.protocol,""+b),c.protocol=null);for(;;){var d=c.protocol=c._protocols.shift();if(!d)return!1;if(r[d]&&r[d].need_chunking===!0&&c._options.chunking===undefined)return c._protocols.unshift(d),c.protocol="chunking-test",c._options.chunking=!1,K(c._base_url,function(a){c._options.chunking=a,c._try_next_protocol()},c._options),!0;if(r[d]&&r[d].need_body===!0&&!a.body)return c._protocols.unshift(d),c.protocol="waiting-for-load",e.attachEvent("load",function(){c._try_next_protocol()}),!0;if(!(!r[d]||r[d].need_chunking===!0&&c._options.chunking!==!0||!r[d].enabled(c._options)))return c._debug("Opening transport:",d),c._transport=new r[d](c,c._trans_url,c._base_url),!0;c._debug("Skipping transport:",d)}},r.prototype.close=function(a,b){var c=this;if(a&&!e.userSetCode(a))throw new Error("INVALID_ACCESS_ERR");return c.readyState!==r.CONNECTING&&c.readyState!==r.OPEN?!1:(c.readyState=r.CLOSING,c._didClose(a||1e3,b||"Normal closure"),!0)},r.prototype.send=function(a){var b=this;if(b.readyState===r.CONNECTING)throw new Error("INVALID_STATE_ERR");return b.readyState===r.OPEN&&b._transport.doSend(e.quote(""+a)),!0};var s=r.websocket=function(a,b){var c=this,d=b+"/websocket";d.slice(0,5)==="https"?d="wss"+d.slice(5):d="ws"+d.slice(4),c.ri=a,c.url=d;var f=window.WebSocket||window.MozWebSocket;if(q.state>=p.beforeunload){e.log("Can't open a WebSocket connection after onbeforeunload!");return}c.ws=new f(c.url),c.ws.onmessage=function(a){c.ri._didMessage(a.data)},c.ws.onclose=function(){c.ri._didMessage(e.closeFrame(1006,"WebSocket connection broken"))}};s.prototype.doSend=function(a){this.ws.send(a)},s.prototype.doCleanup=function(){var a=this,b=a.ws;b&&(b.onmessage=b.onclose=null,b.close(),a.ri=a.ws=null)},s.enabled=function(){return!!window.WebSocket||!!window.MozWebSocket};var t=function(){};t.prototype.send_constructor=function(a){var b=this;b.send_buffer=[],b.sender=a},t.prototype.doSend=function(a){var b=this;b.send_buffer.push(a),b.send_stop||b.send_schedule()},t.prototype.send_schedule_wait=function(){var a=this,b;a.send_stop=function(){a.send_stop=null,clearTimeout(b)},b=e.delay(25,function(){a.send_stop=null,a.send_schedule()})},t.prototype.send_schedule=function(){var a=this;if(a.send_buffer.length>0){var b="["+a.send_buffer.join(",")+"]";a.send_stop=a.sender(a.trans_url,b,function(){a.send_stop=null,a.send_schedule_wait()}),a.send_buffer=[]}},t.prototype.send_destructor=function(){var a=this;a._send_stop&&a._send_stop(),a._send_stop=null};var u=function(b,c,d){var f=this;if(!("_send_form"in f)){var g=f._send_form=a.createElement("form"),h=f._send_area=a.createElement("textarea");h.name="d",g.style.display="none",g.style.position="absolute",g.method="POST",g.enctype="application/x-www-form-urlencoded",g.acceptCharset="UTF-8",g.appendChild(h),a.body.appendChild(g)}var g=f._send_form,h=f._send_area,i="a"+e.random_string(8);g.target=i,g.action=b+"/jsonp_send?i="+i;var j;try{j=a.createElement('<iframe name="'+i+'">')}catch(k){j=a.createElement("iframe"),j.name=i}j.id=i,g.appendChild(j),j.style.display="none",h.value=c,g.submit();var l=function(a){if(!j.onerror)return;j.onreadystatechange=j.onerror=j.onload=null,e.delay(500,function(){j.parentNode.removeChild(j),j=null}),h.value=null,d()};return j.onerror=j.onload=l,j.onreadystatechange=function(a){j.readyState=="complete"&&l()},l},v=function(a,b,c){var d=function(a,b,d){(a.readyState===4||d)&&c(a.status,d)};return e.createXHR("POST",a+"/xhr_send",b,d)},w=function(a,b,c){var d=function(a,b,d){(a.readyState===4||d)&&c(a.status,d)},f=window.XDomainRequest?e.createXDR:e.createXHR;return f("POST",a+"/xhr_send",b,d)},x=function(b,c){var d,f=a.createElement("script"),g,h=function(a){g&&(g.parentNode.removeChild(g),g=null),f&&(clearTimeout(d),f.parentNode.removeChild(f),f.onreadystatechange=f.onerror=f.onload=f.onclick=null,f=null,c(a),c=null)},i=!1,j=null;f.id="a"+e.random_string(8),f.src=b,f.type="text/javascript",f.charset="UTF-8",f.onerror=function(a){j||(j=setTimeout(function(){i||h(e.closeFrame(1006,"JSONP script loaded abnormally (onerror)"))},1e3))},f.onload=function(a){h(e.closeFrame(1006,"JSONP script loaded abnormally (onload)"))},f.onreadystatechange=function(a){if(/loaded|closed/.test(f.readyState)){if(f&&f.htmlFor&&f.onclick){i=!0;try{f.onclick()}catch(b){}}f&&h(e.closeFrame(1006,"JSONP script loaded abnormally (onreadystatechange)"))}};if(typeof f.async=="undefined"&&a.attachEvent)if(!/opera/i.test(navigator.userAgent)){try{f.htmlFor=f.id,f.event="onclick"}catch(k){}f.async=!0}else g=a.createElement("script"),g.text="try{var a = document.getElementById('"+f.id+"'); if (a)a.onerror();}catch(x){};",f.async=g.async=!1;typeof f.async!="undefined"&&(f.async=!0),d=setTimeout(function(){h(e.closeFrame(1006,"JSONP script loaded abnormally (timeout)"))},35e3);var l=a.getElementsByTagName("head")[0];return l.insertBefore(f,l.firstChild),g&&l.insertBefore(g,l.firstChild),h},y=r["jsonp-polling"]=function(a,b){e.polluteGlobalNamespace();var c=this;c.ri=a,c.trans_url=b,c.send_constructor(u),c._schedule_recv()};y.prototype=new t,y.prototype._schedule_recv=function(){var a=this,b=function(b){a._recv_stop=null,b&&(a._is_closing||a.ri._didMessage(b)),a._is_closing||a._schedule_recv()};a._recv_stop=z(a.trans_url+"/jsonp",x,b)},y.enabled=function(){return!0},y.need_body=!0,y.prototype.doCleanup=function(){var a=this;a._is_closing=!0,a._recv_stop&&a._recv_stop(),a.ri=a._recv_stop=null,a.send_destructor()};var z=function(a,c,d){var f="a"+e.random_string(6),h=a+"?c="+escape(g+"."+f),i=function(a){delete b[g][f],d(a)},j=c(h,i);b[g][f]=j;var k=function(){b[g][f]&&b[g][f](e.closeFrame(1e3,"JSONP user aborted read"))};return k},A=r["xhr-streaming"]=function(a,b){var c=this;c.ri=a,c.trans_url=b,c.send_constructor(w),c.poll=new R(a,W,b+"/xhr_streaming",{cors:!0})};A.prototype=new t,A.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)},A.enabled=function(a){return a.cookie!==!0&&window.XDomainRequest?!0:window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest?!0:!1},A.need_chunking=!0;var B=r["xhr-polling"]=function(a,b){var c=this;c.ri=a,c.trans_url=b,c.send_constructor(w),c.poll=new R(a,W,b+"/xhr",{cors:!0})};B.prototype=new t,B.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)},B.enabled=A.enabled;var C=function(){};C.prototype.i_constructor=function(a,b,c){var d=this;d.ri=a,d.origin=e.getOrigin(c),d.base_url=c,d.trans_url=b;var f=c+"/iframe.html";d.ri._options.devel&&(f+="?t="+ +(new Date)),d.window_id=e.random_string(8),f+="#"+d.window_id,d.iframeObj=e.createIframe(f,function(a){d.ri._didClose(1006,"Unable to load an iframe ("+a+")")}),d.onmessage_cb=e.bind(d.onmessage,d),e.attachMessage(d.onmessage_cb)},C.prototype.doCleanup=function(){var a=this;if(a.iframeObj){e.detachMessage(a.onmessage_cb);try{a.iframeObj.iframe.contentWindow&&a.postMessage("c")}catch(b){}a.iframeObj.cleanup(),a.iframeObj=null,a.onmessage_cb=a.iframeObj=null}},C.prototype.onmessage=function(a){var b=this;if(a.origin!==b.origin)return;var c=a.data.slice(0,8),d=a.data.slice(8,9),e=a.data.slice(9);if(c!==b.window_id)return;switch(d){case"s":b.iframeObj.loaded(),b.postMessage("s",JSON.stringify([r.version,b.protocol,b.trans_url,b.base_url]));break;case"t":b.ri._didMessage(e)}},C.prototype.postMessage=function(a,b){var c=this;c.iframeObj.iframe.contentWindow.postMessage(c.window_id+a+(b||""),c.origin)},C.prototype.doSend=function(a){this.postMessage("m",a)},C.enabled=function(){var a=navigator&&navigator.userAgent&&navigator.userAgent.indexOf("Konqueror")!==-1;return(typeof b.postMessage=="function"||typeof b.postMessage=="object")&&!a};var D,E=function(a,c){parent!==b?parent.postMessage(D+a+(c||""),"*"):e.log("Can't postMessage, no parent window.",a,c)},F=function(){};F.prototype._didClose=function(a,b){E("t",e.closeFrame(a,b))},F.prototype._didMessage=function(a){E("t",a)},F.prototype._doSend=function(a){this._transport.doSend(a)},F.prototype._doCleanup=function(){this._transport.doCleanup()},r.bootstrap_iframe=function(){var b;D=a.location.hash.slice(1);var c=function(a){if(a.source!==parent)return;var c=a.data.slice(0,8),d=a.data.slice(8,9),f=a.data.slice(9);if(c!==D)return;switch(d){case"s":var g=JSON.parse(f),h=g[0],i=g[1],j=g[2],k=g[3];h!==r.version&&e.log('Incompatibile SockJS! Main site uses: "'+h+'", the iframe:'+' "'+r.version+'".'),b=new F,b._transport=new F[i](b,j,k);break;case"m":b._doSend(f);break;case"c":b._doCleanup(),b=null}};e.attachMessage(c),E("s")};var G=function(a,b,c){var d=new W(a+"/chunking_test",{cors:c}),f=0;d.onmessage=function(a){var b=a.responsetext.split("h\n").length;a.readystate===3&&b>0&&b<6&&(f=b,d.abort())},d.onclose=function(a){d=d.onmessage=d.onclose=null,e.log("Chunking test: "+(f?"passed":"failed")+" ("+f+" chunk received)"),b(!!f)}},H=F["w-iframe-chunking-test"]=function(a,b,c){G(c,function(b){a._didMessage("m"+b),a._didClose()},!1)};H.prototype.doCleanup=function(){};var I=r.chunkingTest=function(c,d,f){c=e.amendUrl(c);if(b.XDomainRequest||b.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest){G(c,d,!0);return}a.body?J(c,d,f):e.attachEvent("load",function(){J(c,d,f)})},J=function(a,b,c){if(C.enabled()){var d=new C;d.protocol="w-iframe-chunking-test";var e=function(a){d&&(b(a==="mtrue"),d.doCleanup(),d=null)},f={_options:c||{},_didClose:e,_didMessage:e};d.i_constructor(f,"",a);return}setTimeout(function(){b(!1)},0);return},K=function(){var a,b=0;return function(c,d){var e=(new Date).getTime();e-b>1e4?I(c,function(c){a=c,b=(new Date).getTime(),d(a)}):setTimeout(function(){d(a)},0)}}(),L=r["iframe-eventsource"]=function(){var a=this;a.protocol="w-iframe-eventsource",a.i_constructor.apply(a,arguments)};L.prototype=new C,L.enabled=function(){return"EventSource"in window&&C.enabled()},L.need_chunking=!0,L.need_body=!0;var M=F["w-iframe-eventsource"]=function(a,b){var c=this;c.ri=a,c.trans_url=b,c.send_constructor(v),c.poll=new R(a,S,b+"/eventsource")};M.prototype=new t,M.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)};var N=r["iframe-xhr-polling"]=function(){var a=this;a.protocol="w-iframe-xhr-polling",a.i_constructor.apply(a,arguments)};N.prototype=new C,N.enabled=function(){return window.XMLHttpRequest&&C.enabled()},N.need_body=!0;var O=F["w-iframe-xhr-polling"]=function(a,b){var c=this;c.trans_url=b,c.send_constructor(v),c.poll=new R(a,W,b+"/xhr",{cors:!1})};O.prototype=new t,O.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)};var P=r["iframe-htmlfile"]=function(){var a=this;a.protocol="w-iframe-htmlfile",a.i_constructor.apply(a,arguments)};P.prototype=new C,P.enabled=function(a){var b=U();return a.cookie!==!1&&C.enabled()},P.need_chunking=!0,P.need_body=!0;var Q=F["w-iframe-htmlfile"]=function(a,b){var c=this;c.trans_url=b,c.send_constructor(v),c.poll=new R(a,V,b+"/htmlfile")};Q.prototype=new t,Q.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)};var R=function(a,b,c,d){var e=this;e.ri=a,e.Receiver=b,e.recv_url=c,e.opts=d,e._scheduleRecv()};R.prototype._scheduleRecv=function(){var a=this,b=a.poll=new a.Receiver(a.recv_url,a.opts),c=0;b.onmessage=function(b){c+=1,a.ri._didMessage(b.data)},b.onclose=function(c){a.poll=b=b.onmessage=b.onclose=null,a.poll_is_closing||(c.reason==="permanent"?a.ri._didClose(1006,"Polling error ("+c.reason+")"):a._scheduleRecv())}},R.prototype.abort=function(){var a=this;a.poll_is_closing=!0,a.poll&&a.poll.abort()};var S=function(a){var b=this,c=new EventSource(a);c.onmessage=function(a){b.dispatchEvent(new d("message",{data:unescape(a.data)}))},b.es_close=c.onerror=function(a,f){var g=f?"user":c.readyState!==2?"network":"permanent";b.es_close=c.onmessage=c.onerror=null,c.close(),c=null,e.delay(200,function(){b.dispatchEvent(new d("close",{reason:g}))})}};S.prototype=new c,S.prototype.abort=function(){var a=this;a.es_close&&a.es_close({},!0)};var T,U=function(){if(T===undefined)if("ActiveXObject"in window)try{T=!!(new ActiveXObject("htmlfile"))}catch(a){}else T=!1;return T},V=function(a){var c=this;e.polluteGlobalNamespace(),c.id="a"+e.random_string(6,26),a+=(a.indexOf("?")===-1?"?":"&")+"c="+escape(g+"."+c.id);var f=U()?e.createHtmlfile:e.createIframe,h;b[g][c.id]={start:function(){h.loaded()},message:function(a){c.dispatchEvent(new d("message",{data:a}))},stop:function(){c.iframe_close({},"network")}},c.iframe_close=function(a,e){h.cleanup(),c.iframe_close=h=null,delete b[g][c.id],c.dispatchEvent(new d("close",{reason:e}))},h=f(a,function(a){c.iframe_close({},"permanent")})};V.prototype=new c,V.prototype.abort=function(){var a=this;a.iframe_close&&a.iframe_close({},"user")};var W=function(a,c){var f=this,g=0,h=function(a,b,c){if(a.readyState===3||a.readyState===4){try{var e=a.responseText,h=a.status}catch(i){}if(e&&h===200){var j=[];for(;;){var k=e.slice(g),l=k.indexOf("\n");if(l===-1)break;g+=l+1;var m=k.slice(0,l);f.dispatchEvent(new d("message",{data:m,readystate:a.readyState,responsetext:e}))}}}if(a.readyState===4||c){var n=c?"user":a.status===200?"network":"permanent";f.xhr_close=null,f.dispatchEvent(new d("close",{reason:n}))}},i=c.cors&&b.XDomainRequest?e.createXDR:e.createXHR;f.xhr_close=i("POST",a,null,h)};return W.prototype=new c,W.prototype.abort=function(){var a=this;a.xhr_close&&a.xhr_close(!0)},r.getUtils=function(){return e},r.getIframeTransport=function(){return C},r}(),"_sockjs_onload"in window&&setTimeout(_sockjs_onload,1);var log;window.console&&console.log?log=function(){console.log.apply(console,arguments)}:log=function(){};var util={hasProp:function(a,b){return Object.prototype.hasOwnProperty.call(Object(a),b)},extend:function(a,b){function d(){this.constructor=a}if(a===undefined||b===undefined)return a;for(var c in b)util.hasProp(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a},generateGuid:function(){var a="",b="abcdefghijklmnopqrstuvwxyz0123456789";for(var c=0;c<12;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a},typeOf:function(a){var b=typeof a;return b==="object"&&(a?typeof a.length=="number"&&!a.propertyIsEnumerable("length")&&typeof a.splice=="function"&&(b="array"):b="null"),b},findOps:function(a){var b=[];for(var c in a)typeof a[c]=="function"&&util.isValid(c)&&b.push(c);return b},isValid:function(a){return a.charAt(0)!=="_"},inherit:function(a,b){var c=function(){};c.prototype=b.prototype,a.prototype=new c},stringify:JSON.stringify,parse:JSON.parse,log:log,info:function(){util.log.apply(this,arguments)},warn:function(){util.log.apply(this,arguments)},error:function(){util.log.apply(this,arguments)},setLogLevel:function(a){a<3&&(util.info=function(){}),a<2&&(util.warn=function(){}),a<1&&(util.error=function(){})},refCallback:function(a){var b=function(){var b=[].slice.apply(arguments);a._call("callback",b)};return b._reference=a,b._toDict=function(){return a._toDict()},b.callback=b,b}},Serializer={serialize:function(a,b){var c=util.typeOf(b),d;switch(c){case"object":if(b===null)d=null;else if("_toDict"in b)d=b._toDict();else{var e=util.findOps(b);if(e.length>0)d=a._storeObject(b,e)._toDict();else{d={};for(var f in b){var g=b[f];d[f]=Serializer.serialize(a,g)}}}break;case"array":d=[];for(var h=0,i=b.length;h<i;h++){var g=b[h];d.push(Serializer.serialize(a,g))}break;case"function":util.hasProp("_reference")?d=b._toDict():d=a._storeObject({callback:b},["callback"])._toDict();break;default:d=b}return d},unserialize:function(a,b){var c;for(var d in b){var e=b[d];if(typeof e=="object")if(util.hasProp(e,"ref")){var f=new Reference(a,e.ref,e.operations);e.operations&&e.operations.length===1&&e.operations[0]==="callback"?b[d]=util.refCallback(f):b[d]=f}else Serializer.unserialize(a,e)}}};Reference.prototype._toDict=function(a){var b={},c=this._address;return a&&(c=c.slice(),c.push(a)),b.ref=c,c.length<4&&(b.operations=this._operations),b},Reference.prototype._call=function(a,b){util.info("Calling",this._address+"."+a);var c=this._toDict(a);this._bridge._send(b,c)},Connection.prototype.redirector=function(){var a=this;if(this.options.tcp){var b=url.parse(this.options.redirector);http.get({host:b.hostname,port:b.port,path:"/redirect/"+this.options.apiKey},function(b){var c="";b.on("data",function(a){c+=a}),b.on("end",function(){try{var b=JSON.parse(c);a.options.host=b.data.bridge_host,a.options.port=b.data.bridge_port,!a.options.host||!a.options.port?util.error("Could not find host and port in JSON"):a.establishConnection()}catch(d){util.error("Unable to parse redirector response "+c)}})}).on("error",function(a){util.error("Unable to contact redirector")})}else{window.bridgeHost=function(b,c,d){a.options.host=c,a.options.port=parseInt(d,10),!a.options.host||!a.options.port?util.error("Could not find host and port in JSON"):a.establishConnection(),delete window.bridgeHost};var c=document.createElement("script");c.setAttribute("src",this.options.redirector+"/redirect/"+this.options.apiKey+"/jsonp"),document.getElementsByTagName("head")[0].appendChild(c)}},Connection.prototype.reconnect=function(){util.info("Attempting reconnect");var a=this;this.interval<32768&&setTimeout(function(){a.establishConnection()},this.interval*=2)},Connection.prototype.establishConnection=function(){var a=this,b;this.options.tcp?(util.info("Starting TCP connection",this.options.host,this.options.port),b=(new TCP(this.options)).sock):(util.info("Starting SockJS connection"),b=new SockJS("http://"+this.options.host+":"+this.options.port+"/bridge",this.options.protocols,this.options.sockjs)),b.bridge=this.bridge,b.onmessage=function(c){util.info("clientId and secret received",c.data);var d=c.data.toString().split("|");d.length!==2?a.processMessage(c):(a.clientId=d[0],a.secret=d[1],a.interval=400,a.sock.processQueue(b,a.clientId),a.sock=b,a.sock.onmessage=a.processMessage,util.info("Handshake complete"),a.bridge._ready||(a.bridge._ready=!0,a.bridge.emit("ready")))},b.onopen=function(){util.info("Beginning handshake");var c=util.stringify({command:"CONNECT",data:{session:[a.clientId||null,a.secret||null],api_key:a.options.apiKey}});b.send(c)},b.onclose=function(){util.warn("Connection closed"),a.sock=a.sockBuffer,a.options.reconnect&&a.reconnect()}},Connection.prototype.processMessage=function(a){try{util.info("Received",a.data),a=util.parse(a.data),Serializer.unserialize(this.bridge,a);var b=a.destination;if(!b){util.warn("No destination in message",a);return}this.bridge._execute(a.destination._address,a.args)}catch(c){util.error("Message parsing failed: ",c.message,c.stack)}},Connection.prototype.sendCommand=function(a,b){var c=util.stringify({command:a,data:b});util.info("Sending",c),this.sock.send(c)},Connection.prototype.start=function(){!this.options.host||!this.options.port?this.redirector():this.establishConnection()},SockBuffer.prototype.send=function(a){this.buffer.push(a)},SockBuffer.prototype.processQueue=function(a,b){for(var c=0,d=this.buffer.length;c<d;c++)a.send(this.buffer[c].replace('"client",null','"client","'+b+'"'));this.buffer=[]},Bridge.prototype._execute=function(a,b){var c=this._store[a[2]],d=c[a[3]];d?d.apply(c,b):util.warn("Could not find object to handle",a)},Bridge.prototype._storeObject=function(a,b){var c=util.generateGuid();return this._store[c]=a,new Reference(this,["client",this._connection.clientId,c],b)},Bridge.prototype.on=function(a,b){return util.hasProp(this._events,a)||(this._events[a]=[]),this._events[a].push(b),this},Bridge.prototype.emit=function(a,b){if(util.hasProp(this._events,a)){var c=this._events[a].slice(0);for(var d=0,e=c.length;d<e;d++)c[d].apply(this,b===undefined?[]:b)}return this},Bridge.prototype.removeEvent=function(a,b){if(util.hasProp(this._events,a))for(var c=0,d=this._events[a].length;c<d;c++)this._events[a][c]===b&&this._events[a].splice(c,1);return this},Bridge.prototype._send=function(a,b){this._connection.sendCommand("SEND",{args:Serializer.serialize(this,a),destination:b})},Bridge.prototype.publishService=function(a,b,c){a==="system"?util.error("Invalid service name: "+a):(this._store[a]=b,this._connection.sendCommand("JOINWORKERPOOL",{name:a,callback:Serializer.serialize(this,c)}))},Bridge.prototype.getService=function(a,b){this._connection.sendCommand("GETOPS",{name:a,callback:Serializer.serialize(this,b)})},Bridge.prototype.getChannel=function(a,b){var c=this;this._connection.sendCommand("GETCHANNEL",{name:a,callback:Serializer.serialize(this,function(a,d){d=d.split(":")[1];if(a===null){b(null,d);return}b(new Reference(c,["channel",d,"channel:"+d],a._operations),d)})})},Bridge.prototype.joinChannel=function(a,b,c){this._connection.sendCommand("JOINCHANNEL",{name:a,handler:Serializer.serialize(this,b),callback:Serializer.serialize(this,c)})},Bridge.prototype.leaveChannel=function(a,b,c){this._connection.sendCommand("LEAVECHANNEL",{name:a,handler:Serializer.serialize(this,b),callback:Serializer.serialize(this,c)})},Bridge.prototype.ready=function(a){this._ready?a():this.on("ready",a)},Bridge.prototype.connect=function(a){return a&&this.ready(a),this._connection.start(),this}
@@ -1,14 +0,0 @@
1
- $(function(){
2
-
3
- bridge.getService('chatserver', function(chat){
4
- chat.join('lobby', {msg: function(name, msg){
5
- $('#messages').append(name + ': ' + msg + '<br>');
6
- }}, function(lobby) {
7
- $('#y').click(function(){
8
- lobby.msg('someone', $('#x').val());
9
- $('#x').val('');
10
- });
11
- });
12
- });
13
-
14
- });
@@ -1,5 +0,0 @@
1
- <div id="messages"></div>
2
-
3
-
4
- <input type="text" id="x">
5
- <input type="button" id="y" value="submit">
@@ -1,23 +0,0 @@
1
- <!DOCTYPE HTML>
2
- <html lang="en">
3
- <head>
4
- <title></title>
5
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
- <meta http-equiv="Content-Language" content="en-us">
7
- <meta name="description" content="">
8
- <meta name="keywords" content="">
9
-
10
-
11
- <link href="/css/style.css" rel="stylesheet" type="text/css">
12
-
13
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
14
- <script type="text/javascript" src="/js/bridge.min.js"></script>
15
- <script type="text/javascript" src="/js/all.js"></script>
16
- <script type="text/javascript" src="/js/<%= title %>.js"></script>
17
-
18
- </head>
19
-
20
- <body>
21
- <%= yield %>
22
- </body>
23
- </html>
@@ -1,29 +0,0 @@
1
- require 'eventmachine'
2
- require 'bridge'
3
-
4
-
5
- module EchoModule
6
- def self.echo name, msg
7
- puts(name + ": " + msg)
8
- end
9
- def self.pong msg, count, fun
10
- if msg == "ping"
11
- puts :pong
12
- fun.call(count + 1)
13
- end
14
- end
15
- end
16
-
17
- EventMachine::run {
18
- Bridge::initialize({ :reconnect => false,
19
- :host => '127.0.0.1',
20
- :port => 8090})
21
- Bridge::ready lambda {
22
- puts 'Connected.'
23
- }
24
- puts 'enqueued ready func'
25
- Bridge::publish_service("pong", EchoModule)
26
- puts 'published pong service'
27
- Bridge::join_channel("duuuude", EchoModule, lambda {puts "Duuude."})
28
- puts 'joined channel'
29
- }