├── .gitignore ├── src ├── lib-suffix.js ├── lib-prefix.js ├── class-license.js ├── json-licence.js ├── socky-licence.js ├── web-socket-js-licence.js ├── channels-collection.js ├── presence-channel.js ├── class.js ├── events.js ├── utils.js ├── channel.js ├── private-channel.js ├── socky-manager.js └── socky.js ├── dist ├── 0.4.0 │ └── WebSocketMain.swf ├── 0.4.1 │ └── WebSocketMain.swf ├── 0.4 │ ├── assets │ │ ├── WebSocketMain.swf │ │ ├── json2.min.js │ │ ├── json2.js │ │ └── flashfallback.min.js │ ├── socky.min.js │ └── socky.js ├── 0.4.2 │ ├── assets │ │ ├── WebSocketMain.swf │ │ ├── json2.min.js │ │ ├── json2.js │ │ └── flashfallback.min.js │ ├── socky.min.js │ └── socky.js └── 0.5.0-beta1 │ ├── assets │ ├── WebSocketMain.swf │ ├── json2.min.js │ ├── flashfallback.min.js │ └── json2.js │ └── socky.min.js ├── Gemfile ├── .gitmodules ├── Rakefile ├── example ├── config.ru └── index.html ├── test ├── config.ru ├── lib │ └── jasmine-1.0.2 │ │ ├── MIT.LICENSE │ │ ├── jasmine.css │ │ └── jasmine-html.js ├── runner.html └── spec │ └── SockySpec.js ├── Gemfile.lock ├── CHANGELOG.md ├── JFile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ -------------------------------------------------------------------------------- /src/lib-suffix.js: -------------------------------------------------------------------------------- 1 | })(); -------------------------------------------------------------------------------- /src/lib-prefix.js: -------------------------------------------------------------------------------- 1 | (function() { -------------------------------------------------------------------------------- /dist/0.4.0/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpallen99/socky-client-js/master/dist/0.4.0/WebSocketMain.swf -------------------------------------------------------------------------------- /dist/0.4.1/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpallen99/socky-client-js/master/dist/0.4.1/WebSocketMain.swf -------------------------------------------------------------------------------- /dist/0.4/assets/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpallen99/socky-client-js/master/dist/0.4/assets/WebSocketMain.swf -------------------------------------------------------------------------------- /dist/0.4.2/assets/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpallen99/socky-client-js/master/dist/0.4.2/assets/WebSocketMain.swf -------------------------------------------------------------------------------- /dist/0.5.0-beta1/assets/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smpallen99/socky-client-js/master/dist/0.5.0-beta1/assets/WebSocketMain.swf -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # A sample Gemfile 2 | source "http://rubygems.org" 3 | 4 | gem 'jbundle', "~> 0.0.8" 5 | gem 'socky-authenticator', '~> 0.5.0.beta5' 6 | gem 'thin' 7 | -------------------------------------------------------------------------------- /src/class-license.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Simple JavaScript Inheritance 3 | * By John Resig http://ejohn.org/ 4 | * MIT Licensed. 5 | * 6 | * Inspired by base2 and Prototype 7 | */ 8 | -------------------------------------------------------------------------------- /src/json-licence.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * http://www.JSON.org/json2.js 3 | * Public Domain. 4 | * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 5 | * See http://www.JSON.org/js.html 6 | */ 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/web-socket-js"] 2 | path = src/web-socket-js 3 | url = git://github.com/gimite/web-socket-js.git 4 | ignore = dirty 5 | [submodule "src/json"] 6 | path = src/json 7 | url = git://github.com/douglascrockford/JSON-js.git 8 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | 4 | require 'jbundle' 5 | 6 | task :default => :build 7 | 8 | desc 'Bundle and minify source files.' 9 | task :build do 10 | JBundle.config_from_file 'JFile' 11 | JBundle.write! 12 | end -------------------------------------------------------------------------------- /src/socky-licence.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socky JavaScript Library 3 | * 4 | * @version 5 | * @author Bernard Potocki 6 | * @author Stefano Verna 7 | * @licence The MIT licence. 8 | * @source http://github.com/socky/socky-client-js 9 | */ -------------------------------------------------------------------------------- /example/config.ru: -------------------------------------------------------------------------------- 1 | require 'rack' 2 | require 'json' 3 | require 'socky/authenticator' 4 | 5 | Socky::Authenticator.secret = 'my_secret' 6 | 7 | authenticator = proc do |env| 8 | request = Rack::Request.new(env) 9 | 10 | response = Socky::Authenticator.authenticate(request.params, :allow_changing_rights => true) 11 | [ 200, {}, response.to_json ] 12 | end 13 | 14 | 15 | map '/socky/auth' do 16 | run authenticator 17 | end 18 | 19 | map '/' do 20 | run Rack::Directory.new("..") 21 | end -------------------------------------------------------------------------------- /src/web-socket-js-licence.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This library contains code with the following licences: 3 | * 4 | * web_socket.js: 5 | * 6 | * Copyright: Hiroshi Ichikawa 7 | * License: New BSD License 8 | * Reference: http://dev.w3.org/html5/websockets/ 9 | * Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol 10 | * 11 | * swfobject.js: 12 | * 13 | * SWFObject v2.2 14 | * is released under the MIT License 15 | */ 16 | -------------------------------------------------------------------------------- /test/config.ru: -------------------------------------------------------------------------------- 1 | require 'rack' 2 | require 'json' 3 | require 'socky/authenticator' 4 | 5 | Socky::Authenticator.secret = 'my_secret' 6 | 7 | authenticator = proc do |env| 8 | request = Rack::Request.new(env) 9 | 10 | if request.params['channel'].to_s.match(/invalid/) 11 | [ 403, {}, []] 12 | else 13 | response = Socky::Authenticator.authenticate(request.params, true) 14 | [ 200, {}, response.to_json] 15 | end 16 | end 17 | 18 | 19 | map '/socky/auth' do 20 | run authenticator 21 | end 22 | 23 | map '/' do 24 | run Rack::Directory.new("..") 25 | end -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | closure-compiler (1.1.1) 5 | daemons (1.1.4) 6 | eventmachine (0.12.10) 7 | jbundle (0.0.12) 8 | closure-compiler 9 | rack 10 | thor 11 | json (1.5.3) 12 | rack (1.3.2) 13 | ruby-hmac (0.4.0) 14 | socky-authenticator (0.5.0.beta5) 15 | json 16 | ruby-hmac 17 | thin (1.2.11) 18 | daemons (>= 1.0.9) 19 | eventmachine (>= 0.12.6) 20 | rack (>= 1.0.0) 21 | thor (0.14.6) 22 | 23 | PLATFORMS 24 | ruby 25 | 26 | DEPENDENCIES 27 | jbundle (~> 0.0.8) 28 | socky-authenticator (~> 0.5.0.beta5) 29 | thin 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.5.0-beta1 / 2011-08-01 4 | 5 | Socky was rewritten from scratch. From this version it's based on 6 | open protocol, and have a lot of new features. Some of them: 7 | 8 | - New, standarized communication protocol(it will be easy to implement Socky in other languages) 9 | - New user authentication process - much faster and more secure 10 | - Allow users to dynamicly subscribe/unsubscribe from channels 11 | - New events system - easier to learn and much more powerfull 12 | 13 | ## 0.4.2 / 2011-02-03 14 | 15 | - new features: 16 | - load json and flash fallback only when needed 17 | - bugfixes: 18 | - prevent starting connection before all assets are loaded 19 | 20 | ## 0.4.1 / 2010-11-04 21 | 22 | - new features: 23 | - use rake instead of make to build script 24 | - bugfixes: 25 | - added missing json library 26 | 27 | ## 0.4.0 / 2010-10-27 28 | 29 | - new features: 30 | - extract to separate library 31 | - bugfixes 32 | - none 33 | -------------------------------------------------------------------------------- /test/lib/jasmine-1.0.2/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2010 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/runner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Test Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /JFile: -------------------------------------------------------------------------------- 1 | # JBundle configuration file 2 | # https://github.com/ismasan/jbundle 3 | 4 | target_dir './dist' 5 | src_dir './src' 6 | 7 | version '0.5.0-beta1' 8 | 9 | bundle 'socky.js' do 10 | license 'socky-licence.js' 11 | license 'class-license.js' 12 | file 'lib-prefix.js' 13 | file 'class.js' 14 | file 'events.js' 15 | file 'socky.js' 16 | file 'utils.js' 17 | file 'channels-collection.js' 18 | file 'channel.js' 19 | file 'private-channel.js' 20 | file 'presence-channel.js' 21 | file 'socky-manager.js' 22 | file 'lib-suffix.js' 23 | end 24 | 25 | bundle 'assets/flashfallback.js' do 26 | license 'socky-licence.js' 27 | license 'web-socket-js-licence.js' 28 | file 'web-socket-js/swfobject.js' 29 | file 'web-socket-js/web_socket.js' 30 | end 31 | 32 | bundle 'assets/json2.js' do 33 | license 'json-licence.js' 34 | file 'json/json2.js' 35 | end 36 | 37 | # Just copy this file across 38 | file 'web-socket-js/WebSocketMainInsecure.swf' => 'assets/WebSocketMain.swf' 39 | 40 | # Runs for every bundle and license source. 41 | filter do |src, config| 42 | src = src.gsub //, config.version.to_s 43 | src = src.gsub //, "http://js.socky.org/v#{version}/assets" 44 | end 45 | 46 | # some_dependency.js 47 | filter :src do |src, config| 48 | src.gsub //, '' 49 | end 50 | 51 | # some_dependency.min.js 52 | filter :min do |src, config| 53 | src.gsub //, '.min' 54 | end -------------------------------------------------------------------------------- /src/channels-collection.js: -------------------------------------------------------------------------------- 1 | Socky.ChannelsCollection = Class.extend({ 2 | 3 | each: function(iterator) { 4 | Socky.Utils.each(this._channels, function(channel) { 5 | iterator(channel); 6 | }); 7 | }, 8 | 9 | init: function(socky) { 10 | this._socky = socky; 11 | this._channels = {}; 12 | }, 13 | 14 | add: function(obj, permissions, data) { 15 | var self = this; 16 | if (obj instanceof Socky.ChannelsCollection) { 17 | Socky.Utils.extend(this._channels, obj._channels); 18 | } else { 19 | var channel_name = obj; 20 | var existing_channel = this.find(channel_name); 21 | if (!existing_channel) { 22 | var channel = null; 23 | if (channel_name.indexOf("private-") === 0) { 24 | channel = new Socky.PrivateChannel(channel_name, this._socky, permissions); 25 | } else if (channel_name.indexOf("presence-") === 0) { 26 | channel = new Socky.PresenceChannel(channel_name, this._socky, permissions, data); 27 | } else { 28 | channel = new Socky.Channel(channel_name, this._socky); 29 | } 30 | this._channels[channel_name] = channel; 31 | return channel; 32 | } 33 | } 34 | }, 35 | 36 | find: function(channel_name) { 37 | return this._channels[channel_name]; 38 | }, 39 | 40 | remove: function(channel_name) { 41 | delete this._channels[channel_name]; 42 | }, 43 | 44 | channel_names: function() { 45 | var channel_names = []; 46 | for (var channel_name in this._channels) { 47 | channel_names.push(channel_name) 48 | } 49 | return channel_names; 50 | } 51 | 52 | }); 53 | -------------------------------------------------------------------------------- /src/presence-channel.js: -------------------------------------------------------------------------------- 1 | Socky.PresenceChannel = Socky.PrivateChannel.extend({ 2 | 3 | init: function(channel_name, socky, options) { 4 | this._super(channel_name, socky, options); 5 | this._members = {}; 6 | this._subscription_data = JSON.stringify(options['data']); 7 | this.raw_event_bind('socky:member:added', Socky.Utils.bind(this.on_member_added, this)); 8 | this.raw_event_bind('socky:member:removed', Socky.Utils.bind(this.on_member_removed, this)); 9 | }, 10 | 11 | disconnect: function(){ 12 | this._members = {}; 13 | }, 14 | 15 | is_presence: function() { 16 | return true; 17 | }, 18 | 19 | acknowledge_subscription: function(data) { 20 | this._super(data); 21 | for (var i = 0; i < data.members.length; i++) { 22 | var member = data.members[i]; 23 | this._members[member.connection_id] = member.data; 24 | } 25 | }, 26 | 27 | on_member_added: function(data) { 28 | this._members[data.connection_id] = data.data; 29 | this._trigger('public', 'socky:member:added', data.data); 30 | }, 31 | 32 | on_member_removed: function(data) { 33 | var member = this._members[data.connection_id]; 34 | delete this._members[data.connection_id]; 35 | this._trigger('public', 'socky:member:removed', member); 36 | }, 37 | 38 | generate_subscription_payload: function() { 39 | var payload = this._super(); 40 | if (this._permissions.hide === true) { 41 | payload.hide = true; 42 | } 43 | payload.data = this._subscription_data; 44 | return payload; 45 | }, 46 | 47 | members: function() { 48 | return this._members; 49 | } 50 | 51 | }); 52 | 53 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | Untitled Page 8 | 9 | 10 | 30 | 35 | 36 | 37 |
38 |

Socky Example

39 |
    40 | 41 | 42 | 43 |
    44 | 45 | -------------------------------------------------------------------------------- /src/class.js: -------------------------------------------------------------------------------- 1 | 2 | var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; 3 | // The base Class implementation (does nothing) 4 | var Class = function(){}; 5 | 6 | // Create a new Class that inherits from this class 7 | Class.extend = function(prop) { 8 | var _super = this.prototype; 9 | 10 | // Instantiate a base class (but only create the instance, 11 | // don't run the init constructor) 12 | initializing = true; 13 | var prototype = new this(); 14 | initializing = false; 15 | 16 | // Copy the properties over onto the new prototype 17 | for (var name in prop) { 18 | // Check if we're overwriting an existing function 19 | prototype[name] = typeof prop[name] == "function" && 20 | typeof _super[name] == "function" && fnTest.test(prop[name]) ? 21 | (function(name, fn){ 22 | return function() { 23 | var tmp = this._super; 24 | 25 | // Add a new ._super() method that is the same method 26 | // but on the super-class 27 | this._super = _super[name]; 28 | 29 | // The method only need to be bound temporarily, so we 30 | // remove it when we're done executing 31 | var ret = fn.apply(this, arguments); 32 | this._super = tmp; 33 | 34 | return ret; 35 | }; 36 | })(name, prop[name]) : 37 | prop[name]; 38 | } 39 | 40 | // The dummy class constructor 41 | function Class() { 42 | // All construction is actually done in the init method 43 | if ( !initializing && this.init ) 44 | this.init.apply(this, arguments); 45 | } 46 | 47 | // Populate our constructed prototype object 48 | Class.prototype = prototype; 49 | 50 | // Enforce the constructor to be what we expect 51 | Class.constructor = Class; 52 | 53 | // And make this class extendable 54 | Class.extend = arguments.callee; 55 | 56 | return Class; 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /src/events.js: -------------------------------------------------------------------------------- 1 | Events = Class.extend({ 2 | 3 | // Bind an event, specified by a string name, `ev`, to a `callback` function. 4 | // Passing `"all"` will bind the callback to all events fired. 5 | _bind : function(scope, ev, callback) { 6 | this._callbacks = this._callbacks || {}; 7 | var calls = this._callbacks[scope] || (this._callbacks[scope] = {}); 8 | var list = this._callbacks[scope][ev] || (this._callbacks[scope][ev] = []); 9 | list.push(callback); 10 | return this; 11 | }, 12 | 13 | // Remove one or many callbacks. If `callback` is null, removes all 14 | // callbacks for the event. If `ev` is null, removes all bound callbacks 15 | // for all events. 16 | _unbind : function(scope, ev, callback) { 17 | var calls; 18 | if (this._callbacks && !ev) { 19 | this._callbacks[scope] = {}; 20 | } else if (calls = this._callbacks[scope]) { 21 | if (!callback) { 22 | calls[ev] = []; 23 | } else { 24 | var list = calls[ev]; 25 | if (!list) return this; 26 | for (var i = 0, l = list.length; i < l; i++) { 27 | if (callback === list[i]) { 28 | list.splice(i, 1); 29 | break; 30 | } 31 | } 32 | } 33 | } 34 | return this; 35 | }, 36 | 37 | // Trigger an event, firing all bound callbacks. Callbacks are passed the 38 | // same arguments as `trigger` is, apart from the event name. 39 | // Listening for `"all"` passes the true event name as the first argument. 40 | _trigger : function(scope, ev) { 41 | var list, calls, i, l; 42 | if (!this._callbacks || !(calls = this._callbacks[scope])) return this; 43 | if (calls[ev]) { 44 | list = calls[ev].slice(0); 45 | for (i = 0, l = list.length; i < l; i++) { 46 | list[i].apply(this, Array.prototype.slice.call(arguments, 2)); 47 | } 48 | } 49 | if (calls['all']) { 50 | list = calls['all'].slice(0); 51 | for (i = 0, l = list.length; i < l; i++) { 52 | list[i].apply(this, Array.prototype.slice.call(arguments, 1)); 53 | } 54 | } 55 | return this; 56 | } 57 | 58 | }); -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | Socky.Utils = { 2 | breaker: {}, 3 | log: function() { 4 | if (console && console.log) { 5 | var args = Array.prototype.slice.call(arguments); 6 | args.unshift(">> Socky"); 7 | Function.prototype.apply.apply(console.log, [console, args]); 8 | } 9 | }, 10 | is_number: function(obj) { 11 | return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed)); 12 | }, 13 | each: function(obj, iterator, context) { 14 | if (obj == null) return; 15 | if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { 16 | obj.forEach(iterator, context); 17 | } else if (Socky.Utils.is_number(obj.length)) { 18 | for (var i = 0, l = obj.length; i < l; i++) { 19 | if (iterator.call(context, obj[i], i, obj) === Socky.Utils.breaker) return; 20 | } 21 | } else { 22 | for (var key in obj) { 23 | if (hasOwnProperty.call(obj, key)) { 24 | if (iterator.call(context, obj[key], key, obj) === Socky.Utils.breaker) return; 25 | } 26 | } 27 | } 28 | }, 29 | find: function(obj, iterator, context) { 30 | var result; 31 | Socky.Utils.any(obj, function(value, index, list) { 32 | if (iterator.call(context, value, index, list)) { 33 | result = value; 34 | return true; 35 | } 36 | }); 37 | return result; 38 | }, 39 | any: function(obj, iterator, context) { 40 | var result = false; 41 | if (obj == null) return result; 42 | Socky.Utils.each(obj, function(value, index, list) { 43 | if (result = iterator.call(context, value, index, list)) return Socky.Utils.breaker; 44 | }); 45 | return result; 46 | }, 47 | extend: function(obj) { 48 | Socky.Utils.each(Array.prototype.slice.call(arguments, 1), function(source) { 49 | for (var prop in source) { 50 | obj[prop] = source[prop]; 51 | } 52 | }); 53 | return obj; 54 | }, 55 | bind: function(f, context, args) { 56 | return function() { 57 | return f.apply(context, Array.prototype.slice.call(args || []).concat(Array.prototype.slice.call(arguments))); 58 | } 59 | }, 60 | parseJSON: function(data) { 61 | try { 62 | return JSON.parse(data); 63 | } catch(e) { 64 | return data; 65 | } 66 | } 67 | }; 68 | -------------------------------------------------------------------------------- /src/channel.js: -------------------------------------------------------------------------------- 1 | Socky.Channel = Events.extend({ 2 | init: function(channel_name, socky) { 3 | this._socky = socky; 4 | this._name = channel_name; 5 | this._callbacks = {}; 6 | this._global_callbacks = []; 7 | this._subscribed = false; 8 | this._auth = null; 9 | this.raw_event_bind('socky:subscribe:success', Socky.Utils.bind(this.acknowledge_subscription, this)); 10 | }, 11 | 12 | disconnect: function(){ 13 | }, 14 | 15 | acknowledge_subscription: function(data){ 16 | this._subscribed = true; 17 | this._trigger('public', 'socky:subscribe:success', data.members); 18 | }, 19 | 20 | is_private: function(){ 21 | return false; 22 | }, 23 | 24 | is_presence: function(){ 25 | return false; 26 | }, 27 | 28 | subscribe: function() { 29 | if (this._started_subscribe) { 30 | return; 31 | } 32 | this._started_subscribe = true; 33 | var self = this; 34 | this.authorize( 35 | function(data) { 36 | self._auth = data.auth; 37 | self.send_event('socky:subscribe', self.generate_subscription_payload()); 38 | }, 39 | function(data) { 40 | self._socky.send_locally({ 41 | event: 'socky:subscribe:failure', 42 | channel: self._name 43 | }); 44 | } 45 | ); 46 | }, 47 | 48 | generate_subscription_payload: function() { 49 | return null; 50 | }, 51 | 52 | unsubscribe: function() { 53 | this.send_event('socky:unsubscribe'); 54 | }, 55 | 56 | authorize: function(callback){ 57 | // normal channels don't require auth 58 | callback({}); 59 | }, 60 | 61 | send_event: function(event_name, payload) { 62 | payload = payload || {}; 63 | payload.event = event_name; 64 | payload.channel = this._name; 65 | payload.auth = this._auth; 66 | this._socky.send(payload); 67 | }, 68 | 69 | receive_event: function(event_name, payload) { 70 | if(payload.event.match(/^socky:/)) { 71 | // notify internal handlers 72 | this._trigger('raw', payload.event, payload); 73 | } else { 74 | // notify the external (client) handlers, passing them just the 'data' param 75 | this._trigger('public', payload.event, payload.data); 76 | } 77 | }, 78 | 79 | raw_event_bind: function(event, callback) { 80 | this._bind('raw', event, callback); 81 | }, 82 | 83 | raw_event_unbind: function(event, callback) { 84 | this._unbind('raw', event, callback); 85 | }, 86 | 87 | bind: function(event, callback) { 88 | this._bind('public', event, callback); 89 | }, 90 | 91 | unbind: function(event, callback) { 92 | this._unbind('public', event, callback); 93 | }, 94 | 95 | trigger: function(event, data) { 96 | this.send_event(event, {data: data}); 97 | } 98 | 99 | }); 100 | -------------------------------------------------------------------------------- /dist/0.4/assets/json2.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * http://www.JSON.org/json2.js 3 | * Public Domain. 4 | * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 5 | * See http://www.JSON.org/js.html 6 | */ 7 | 8 | var JSON;JSON||(JSON={}); 9 | (function(){function l(b){return b<10?"0"+b:b}function o(b){p.lastIndex=0;return p.test(b)?'"'+b.replace(p,function(f){var c=r[f];return typeof c==="string"?c:"\\u"+("0000"+f.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+b+'"'}function m(b,f){var c,d,g,j,i=h,e,a=f[b];if(a&&typeof a==="object"&&typeof a.toJSON==="function")a=a.toJSON(b);if(typeof k==="function")a=k.call(f,b,a);switch(typeof a){case "string":return o(a);case "number":return isFinite(a)?String(a):"null";case "boolean":case "null":return String(a);case "object":if(!a)return"null"; 10 | h+=n;e=[];if(Object.prototype.toString.apply(a)==="[object Array]"){j=a.length;for(c=0;c 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | */ 9 | 10 | window.SOCKY_ASSET_LOCATION="http://js.socky.org/v0.4/assets";Socky=function(a,b,c){this.host=a;this.port=b;this.params=c;Socky.isReady?this.connect():Socky.instances.push(this)};Socky.isReady=false;Socky.instances=[];Socky.CONNECTING=0;Socky.AUTHENTICATING=1;Socky.OPEN=2;Socky.CLOSED=3;Socky.UNAUTHENTICATED=4; 11 | Socky.prototype.connect=function(){var a=this;a.state=Socky.CONNECTING;var b=new WebSocket(this.host+":"+this.port+"/?"+this.params);b.onopen=function(){a.onopen()};b.onmessage=function(c){a.onmessage(c)};b.onclose=function(){a.onclose()};b.onerror=function(){a.onerror()}};Socky.ready=function(){Socky.isReady=true;for(var a=0;a0?_require(a,b):b()})(); 17 | -------------------------------------------------------------------------------- /dist/0.4/socky.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socky JavaScript Library 3 | * 4 | * @version 0.4.2 5 | * @author Bernard Potocki 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | */ 9 | 10 | window.SOCKY_ASSET_LOCATION="http://js.socky.org/v0.4/assets";Socky=function(a,b,c){this.host=a;this.port=b;this.params=c;Socky.isReady?this.connect():Socky.instances.push(this)};Socky.isReady=false;Socky.instances=[];Socky.CONNECTING=0;Socky.AUTHENTICATING=1;Socky.OPEN=2;Socky.CLOSED=3;Socky.UNAUTHENTICATED=4; 11 | Socky.prototype.connect=function(){var a=this;a.state=Socky.CONNECTING;var b=new WebSocket(this.host+":"+this.port+"/?"+this.params);b.onopen=function(){a.onopen()};b.onmessage=function(c){a.onmessage(c)};b.onclose=function(){a.onclose()};b.onerror=function(){a.onerror()}};Socky.ready=function(){Socky.isReady=true;for(var a=0;a0?_require(a,b):b()})(); 17 | -------------------------------------------------------------------------------- /test/lib/jasmine-1.0.2/jasmine.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; 3 | } 4 | 5 | 6 | .jasmine_reporter a:visited, .jasmine_reporter a { 7 | color: #303; 8 | } 9 | 10 | .jasmine_reporter a:hover, .jasmine_reporter a:active { 11 | color: blue; 12 | } 13 | 14 | .run_spec { 15 | float:right; 16 | padding-right: 5px; 17 | font-size: .8em; 18 | text-decoration: none; 19 | } 20 | 21 | .jasmine_reporter { 22 | margin: 0 5px; 23 | } 24 | 25 | .banner { 26 | color: #303; 27 | background-color: #fef; 28 | padding: 5px; 29 | } 30 | 31 | .logo { 32 | float: left; 33 | font-size: 1.1em; 34 | padding-left: 5px; 35 | } 36 | 37 | .logo .version { 38 | font-size: .6em; 39 | padding-left: 1em; 40 | } 41 | 42 | .runner.running { 43 | background-color: yellow; 44 | } 45 | 46 | 47 | .options { 48 | text-align: right; 49 | font-size: .8em; 50 | } 51 | 52 | 53 | 54 | 55 | .suite { 56 | border: 1px outset gray; 57 | margin: 5px 0; 58 | padding-left: 1em; 59 | } 60 | 61 | .suite .suite { 62 | margin: 5px; 63 | } 64 | 65 | .suite.passed { 66 | background-color: #dfd; 67 | } 68 | 69 | .suite.failed { 70 | background-color: #fdd; 71 | } 72 | 73 | .spec { 74 | margin: 5px; 75 | padding-left: 1em; 76 | clear: both; 77 | } 78 | 79 | .spec.failed, .spec.passed, .spec.skipped { 80 | padding-bottom: 5px; 81 | border: 1px solid gray; 82 | } 83 | 84 | .spec.failed { 85 | background-color: #fbb; 86 | border-color: red; 87 | } 88 | 89 | .spec.passed { 90 | background-color: #bfb; 91 | border-color: green; 92 | } 93 | 94 | .spec.skipped { 95 | background-color: #bbb; 96 | } 97 | 98 | .messages { 99 | border-left: 1px dashed gray; 100 | padding-left: 1em; 101 | padding-right: 1em; 102 | } 103 | 104 | .passed { 105 | background-color: #cfc; 106 | display: none; 107 | } 108 | 109 | .failed { 110 | background-color: #fbb; 111 | } 112 | 113 | .skipped { 114 | color: #777; 115 | background-color: #eee; 116 | display: none; 117 | } 118 | 119 | 120 | /*.resultMessage {*/ 121 | /*white-space: pre;*/ 122 | /*}*/ 123 | 124 | .resultMessage span.result { 125 | display: block; 126 | line-height: 2em; 127 | color: black; 128 | } 129 | 130 | .resultMessage .mismatch { 131 | color: black; 132 | } 133 | 134 | .stackTrace { 135 | white-space: pre; 136 | font-size: .8em; 137 | margin-left: 10px; 138 | max-height: 5em; 139 | overflow: auto; 140 | border: 1px inset red; 141 | padding: 1em; 142 | background: #eef; 143 | } 144 | 145 | .finished-at { 146 | padding-left: 1em; 147 | font-size: .6em; 148 | } 149 | 150 | .show-passed .passed, 151 | .show-skipped .skipped { 152 | display: block; 153 | } 154 | 155 | 156 | #jasmine_content { 157 | position:fixed; 158 | right: 100%; 159 | } 160 | 161 | .runner { 162 | border: 1px solid gray; 163 | display: block; 164 | margin: 5px 0; 165 | padding: 2px 0 2px 10px; 166 | } 167 | -------------------------------------------------------------------------------- /src/private-channel.js: -------------------------------------------------------------------------------- 1 | Socky.PrivateChannel = Socky.Channel.extend({ 2 | 3 | init: function(channel_name, socky, options) { 4 | this._super(channel_name, socky); 5 | var default_permissions = { 6 | read: true, 7 | write: false, 8 | presence: false 9 | }; 10 | this._permissions = Socky.Utils.extend({}, default_permissions, options); 11 | }, 12 | 13 | is_private: function(){ 14 | return true; 15 | }, 16 | 17 | authorize: function(success_callback, failure_callback){ 18 | if (this._socky.auth_transport() == "ajax") { 19 | this.authorize_via_ajax(success_callback, failure_callback); 20 | } else { 21 | this.authorize_via_jsonp(success_callback, failure_callback); 22 | } 23 | }, 24 | 25 | generate_subscription_payload: function() { 26 | var payload = {}; 27 | if (this._permissions.read === false) { 28 | payload.read = false; 29 | } 30 | if (this._permissions.write === true) { 31 | payload.write = true; 32 | } 33 | return payload; 34 | }, 35 | 36 | generate_auth_payload: function() { 37 | var payload = { 38 | 'event': 'socky:subscribe', 39 | 'channel': this._name, 40 | 'connection_id': this._socky.connection_id() 41 | }; 42 | Socky.Utils.extend(payload, this.generate_subscription_payload()); 43 | return payload; 44 | }, 45 | 46 | generate_auth_payload_string: function() { 47 | var params = []; 48 | var payload = this.generate_auth_payload(); 49 | for (var i in payload) { 50 | params.push(i + '=' + encodeURIComponent(payload[i])); 51 | } 52 | return params.join('&'); 53 | }, 54 | 55 | authorize_via_ajax: function(success_callback, failure_callback){ 56 | var self = this; 57 | var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); 58 | xhr.open("POST", this._socky.auth_endpoint(), true); 59 | xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 60 | xhr.onreadystatechange = function() { 61 | if (xhr.readyState == 4) { 62 | if (xhr.status == 200) { 63 | var data = Socky.Utils.parseJSON(xhr.responseText); 64 | success_callback(data); 65 | } else { 66 | failure_callback(); 67 | } 68 | } else { 69 | failure_callback(); 70 | } 71 | }; 72 | var payload = this.generate_auth_payload_string(); 73 | xhr.send(payload); 74 | }, 75 | 76 | authorize_via_jsonp: function(success_callback, failure_callback) { 77 | 78 | var callback_name = this._name; 79 | var success_called = false; 80 | Socky.Manager._jsonp_auth_callbacks[callback_name] = function(data) { 81 | success_called = true; 82 | success_callback(data); 83 | }; 84 | 85 | var payload = this.generate_auth_payload_string(); 86 | 87 | var full_callback_name = "Socky.Manager._jsonp_auth_callbacks['" + callback_name + "']" 88 | var script_url = this._socky.auth_endpoint(); 89 | script_url += '?callback=' + encodeURIComponent(full_callback_name); 90 | script_url += '&' + payload; 91 | 92 | var script = document.createElement("script"); 93 | script.src = script_url; 94 | var head = document.getElementsByTagName("head")[0] || document.documentElement; 95 | head.insertBefore(script, head.firstChild); 96 | 97 | setTimeout(function() { 98 | if (!success_called) { 99 | failure_callback(); 100 | } 101 | }, 10000); 102 | 103 | } 104 | 105 | }); -------------------------------------------------------------------------------- /src/socky-manager.js: -------------------------------------------------------------------------------- 1 | Socky.Manager = { 2 | 3 | // private attributes 4 | _is_inited: false, 5 | _is_websocket_driver_loaded: false, 6 | _jsonp_auth_callbacks: {}, 7 | _socky_instances: [], 8 | _assets_location: '', 9 | _flash_debug: false, 10 | _default_options: { 11 | debug: false, 12 | url: 'ws://'+window.location.hostname+':'+8080+'/websocket', 13 | auth_endpoint: "/socky/auth", 14 | auth_transport: "ajax" 15 | }, 16 | 17 | // public methods 18 | 19 | is_inited: function() { 20 | return this._is_inited; 21 | }, 22 | 23 | is_driver_loaded: function() { 24 | return this._is_websocket_driver_loaded; 25 | }, 26 | 27 | add_socky_instance: function(socky) { 28 | this._socky_instances.push(socky); 29 | }, 30 | 31 | default_options: function() { 32 | return this._default_options; 33 | }, 34 | 35 | set_default_options: function(default_options) { 36 | this._default_options = Socky.Utils.extend({}, this._default_options, default_options); 37 | }, 38 | 39 | set_assets_location: function(assets) { 40 | this._assets_location = assets; 41 | }, 42 | 43 | set_flash_debug: function(debug) { 44 | this._flash_debug = debug; 45 | }, 46 | 47 | init: function(assets_location) { 48 | 49 | if (this._is_inited) { 50 | return; 51 | } 52 | 53 | this._is_inited = true; 54 | 55 | Socky.Utils.log("inited"); 56 | 57 | if (assets_location) { 58 | this.set_assets_location(assets_location); 59 | } 60 | 61 | var scripts_to_require = []; 62 | 63 | var success_callback = Socky.Utils.bind(function() { 64 | Socky.Utils.log("Websockets driver loaded"); 65 | this._web_sockets_loaded(); 66 | }, this); 67 | 68 | // Check for JSON dependency 69 | if (window['JSON'] == undefined) { 70 | Socky.Utils.log("no JSON support, requiring it"); 71 | scripts_to_require.push(this._assets_location + '/json2.js'); 72 | } 73 | 74 | // Check for Flash fallback dep. Wrap initialization. 75 | if (window['WebSocket'] == undefined) { 76 | 77 | Socky.Utils.log("no WebSocket driver available, requiring it"); 78 | 79 | // Don't let WebSockets.js initialize on load. Inconsistent accross browsers. 80 | window.WEB_SOCKET_SWF_LOCATION = this._assets_location + "/WebSocketMain.swf"; 81 | window.WEB_SOCKET_DEBUG = this._flash_debug; 82 | window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true; 83 | 84 | scripts_to_require.push(this._assets_location + '/flashfallback.js'); 85 | } 86 | 87 | if (scripts_to_require.length > 0){ 88 | this._require_scripts(scripts_to_require, success_callback); 89 | } else { 90 | success_callback(); 91 | } 92 | }, 93 | 94 | // private methods 95 | 96 | _web_sockets_loaded: function() { 97 | this._is_websocket_driver_loaded = true; 98 | Socky.Utils.each(this._socky_instances, function(socky) { 99 | if (!socky.is_connected()) { 100 | socky.connect(); 101 | } 102 | }); 103 | }, 104 | 105 | _require_scripts: function(scripts, callback) { 106 | 107 | var scripts_count = 0; 108 | var handle_script_loaded; 109 | 110 | if (document.addEventListener) { 111 | handle_script_loaded = function(elem, callback) { 112 | elem.addEventListener('load', callback, false) 113 | } 114 | } else { 115 | handle_script_loaded = function(elem, callback) { 116 | elem.attachEvent('onreadystatechange', function() { 117 | if (elem.readyState == 'loaded' || elem.readyState == 'complete') { 118 | callback(); 119 | } 120 | }); 121 | } 122 | } 123 | 124 | var check_if_ready = Socky.Utils.bind(function(callback) { 125 | scripts_count++; 126 | if (scripts.length == scripts_count) { 127 | // Opera needs the timeout for page initialization weirdness 128 | Socky.Utils.log("All the require script have been loaded!"); 129 | setTimeout(callback, 0); 130 | } 131 | }, this); 132 | 133 | var add_script = Socky.Utils.bind(function(src, callback) { 134 | callback = callback || function() {} 135 | var head = document.getElementsByTagName('head')[0]; 136 | var script = document.createElement('script'); 137 | script.setAttribute('src', src); 138 | script.setAttribute('type', 'text/javascript'); 139 | script.setAttribute('async', true); 140 | 141 | Socky.Utils.log("Adding script", src); 142 | 143 | handle_script_loaded(script, function() { 144 | check_if_ready(callback); 145 | }); 146 | 147 | head.appendChild(script); 148 | }, this); 149 | 150 | for (var i = 0; i < scripts.length; i++) { 151 | add_script(scripts[i], callback); 152 | } 153 | } 154 | 155 | }; 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Socky - JavaScript Client 2 | 3 | ## Installation 4 | 5 | You can copy all files from directory of specific version('dist' subdirectories) or use our CDN version. 6 | 7 | In your header you only need to link main file - socky.js or socky.min.js. 8 | 9 | ``` html 10 | 11 | ``` 12 | 13 | ## Basic usage 14 | 15 | To initialize Socky connection you only need to create Socky.Client instance with full Socky server url: 16 | 17 | ``` javascript 18 | var socky = new Socky.Client('ws://ws.example.org/websocket/my_app'); 19 | ``` 20 | 21 | Note that server url include protocol namespace('websocket') and application name('my_app'). 22 | 23 | In order to connect to channel you can call: 24 | 25 | ``` javascript 26 | var channel = socky.subscribe("channel1"); 27 | ``` 28 | 29 | And unsubscribe later: 30 | 31 | ``` javascript 32 | socky.unsubscribe("channel1"); 33 | ``` 34 | 35 | Please note that you can subscribe to as many channels as you want. 36 | 37 | ## Private and Presence channels 38 | 39 | At default you can connect and listen to any public channel. But some channels are restricted to 40 | authenticated users only. These channels have names starting from 'private-' and 'presence-' - so for example 41 | 'private-chat' will be restricted channel, but 'chat' is public, and both of them are handled separately. 42 | 43 | One part of Socky family is "authenticator" - please read there more to find how to use it in your language. 44 | At default Socky JS Client is assuming that authentication backend is located at the same server that page that 45 | are requesting connection and under path '/socky/auth' - if ajax call to this path will fail then authentication 46 | result will be failure and no connection will be made. You can change authentication backend location by changing 47 | 'auth_endpoint' variable of your Socky Client. 48 | 49 | For presence channel you can provide your user data that will be visible to other users: 50 | 51 | ``` javascript 52 | var channel = socky.subscribe("presence-channel", { data: { login: 'my login', sex: 'male' }}); 53 | ``` 54 | 55 | ## Callbacks 56 | 57 | Socky is using jQuery-inspired callbacks to handle various events between users. After connecting to server you can 58 | handle them by "binding" them to specific event. Example: 59 | 60 | ``` javascript 61 | socky.bind("my_event", function(data) { 62 | alert(data); 63 | }); 64 | ``` 65 | 66 | Each time server will send event called 'my_event' your callback will be fired. Thanks to that you can easly handle 67 | multiple different situations by binding different callbacks to events. 68 | 69 | The same way you can bind events to channel so only events sent to that channel will trigger callback: 70 | 71 | ``` javascript 72 | channel.bind("my_event", function(data) { 73 | }); 74 | ``` 75 | 76 | Except of your own events there are few predefined events that will be fired by Socky itself: 77 | 78 | - socky:connection:established - called when connection with Socky Server is made 79 | - socky:connection:closed - called when connection with Socky Server is closed 80 | - socky:connection:error - called when connection with Socky Server cannot be established. Data will contain reason. 81 | - socky:subscribe:success - called when you successfully join channel. Data will be presend only for presence channels and will contain list of already connected users 82 | - socky:subscribe:failure - called when you cannot join channel. Usually this means that you cannot receive authorization. 83 | - socky:member:added - called only for presence channel when new user is connecting. Data will contain user data. 84 | - socky:member:removed - called only for presence channel when user is disconnecting. Data will contain user data. 85 | 86 | ## User rights 87 | 88 | Each user have 2 default rights, and one additional for presence channels. Those rights are: receive messages, send messages and hide from other users. At default only first one is enabled, but when connecting to restricted channel you can request changing one or more of this rights. If authenticator will allow such rights change then you could enable sending events, disable receiving events(i.e. write-only mode) and hide from other users. In order to do so you will need to privide them as params: 89 | 90 | ``` javascript 91 | var channel = socky.subscribe("presence-channel", { read: false, write: true, hide: true }}); 92 | ``` 93 | 94 | ## Triggering events 95 | 96 | If you join channel with write right enabled then you will be able to trigger events on this channel(and this channel only - each channel will require this right separately) In order to do so you only need to call 'trigger' method with data to send: 97 | 98 | ``` javascript 99 | channel.trigger("my_event", { some_data: 'my message' }); 100 | ``` 101 | 102 | ## License 103 | 104 | (The MIT License) 105 | 106 | Copyright (c) 2010 Bernard Potocki 107 | 108 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 109 | 110 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 111 | 112 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/socky.js: -------------------------------------------------------------------------------- 1 | this.Socky = {}; 2 | 3 | this.Socky.Client = Events.extend({ 4 | 5 | init: function(url, options) { 6 | 7 | if (!Socky.Manager.is_inited()) { 8 | Socky.Manager.init(options ? options.assets_location : null); 9 | } 10 | 11 | this._options = Socky.Utils.extend({}, Socky.Manager.default_options(), options, {url: url}); 12 | this._channels = new Socky.ChannelsCollection(this); 13 | this._is_connected = false; 14 | this._connection_id = null; 15 | this._connection = null; 16 | 17 | if (Socky.Manager.is_driver_loaded()) { 18 | this.connect(); 19 | } else { 20 | this.log('WebSocket driver still unavailable, waiting...'); 21 | } 22 | 23 | this.raw_event_bind('socky:connection:established', Socky.Utils.bind(this._on_connection_established, this)); 24 | 25 | Socky.Manager.add_socky_instance(this); 26 | }, 27 | 28 | auth_transport: function() { 29 | return this._options.auth_transport; 30 | }, 31 | 32 | auth_endpoint: function() { 33 | return this._options.auth_endpoint; 34 | }, 35 | 36 | connection_id: function() { 37 | return this._connection_id; 38 | }, 39 | 40 | is_connected: function() { 41 | return this._is_connected; 42 | }, 43 | 44 | connect: function() { 45 | var self = this; 46 | 47 | if (this._connection) { 48 | return; 49 | } 50 | 51 | if (window.WebSocket) { 52 | var url = this._options.url; 53 | this.log('connecting', url); 54 | this._connection = new WebSocket(url); 55 | this._connection.onopen = Socky.Utils.bind(this.on_socket_open, this); 56 | this._connection.onmessage = Socky.Utils.bind(this.on_socket_message, this); 57 | this._connection.onclose = Socky.Utils.bind(this.on_socket_close, this); 58 | this._connection.onerror = Socky.Utils.bind(this.on_socket_error, this); 59 | setTimeout(Socky.Utils.bind(function() { 60 | if (!this._connection_open) { 61 | this._connection = null; 62 | // simulate a remote event 63 | this.send_locally({ 64 | event: 'socky:connection:error', 65 | reason: 'down' 66 | }); 67 | } 68 | }, this), 10000); 69 | } else { 70 | this.log('WebSocket unavailable'); 71 | this._connection = {}; 72 | } 73 | }, 74 | 75 | on_socket_open: function() { 76 | this.log('connected to socket, waiting for connection_id'); 77 | this._connection_open = true; 78 | }, 79 | 80 | on_socket_message: function(evt) { 81 | var params = Socky.Utils.parseJSON(evt.data); 82 | 83 | if (typeof(params.data) == 'string') { 84 | params.data = Socky.Utils.parseJSON(params.data); 85 | } 86 | 87 | this.log('received message', JSON.stringify(params)); 88 | 89 | // first notify internal handlers 90 | this._trigger('raw', params.event, params); 91 | 92 | // notify the external (client) handlers 93 | this._trigger('public', params.event, params); 94 | 95 | if (params.channel) { 96 | // then notify channels' internal handlers 97 | var channel = this.channel(params.channel); 98 | if (channel) { 99 | channel.receive_event(params.event, params); 100 | } 101 | } 102 | 103 | }, 104 | 105 | on_socket_error: function(evt) { 106 | this.log('error', evt.data); 107 | this._is_connected = false; 108 | }, 109 | 110 | on_socket_close: function() { 111 | this.log('disconnected'); 112 | this._is_connected = false; 113 | this.send_locally({ 114 | event: 'socky:connection:closed' 115 | }); 116 | }, 117 | 118 | log: function() { 119 | Socky.Utils.log.apply(Socky.Manager, arguments); 120 | }, 121 | 122 | subscribe: function(channel_name, permissions, data) { 123 | var channel = this._channels.add(channel_name, permissions, data); 124 | if (this._is_connected) { 125 | channel.subscribe(); 126 | } 127 | return channel; 128 | }, 129 | 130 | unsubscribe: function(channel_name) { 131 | var channel = this.channel(channel_name); 132 | if (channel) { 133 | if (this._is_connected) { 134 | channel.unsubscribe(); 135 | } 136 | this._channels.remove(channel_name); 137 | } else { 138 | this.send_locally({ 139 | event: 'socky:unsubscribe:failure', 140 | channel: channel_name 141 | }); 142 | } 143 | }, 144 | 145 | send_locally: function(payload) { 146 | this.on_socket_message({ 147 | data: payload 148 | }); 149 | }, 150 | 151 | send: function(payload) { 152 | payload.connection_id = this._connection_id; 153 | var strigified_params = JSON.stringify(payload); 154 | this.log("sending message", strigified_params); 155 | this._connection.send(strigified_params); 156 | return this; 157 | }, 158 | 159 | raw_event_bind: function(event, callback) { 160 | this._bind('raw', event, callback); 161 | }, 162 | 163 | raw_event_unbind: function(event, callback) { 164 | this._unbind('raw', event, callback); 165 | }, 166 | 167 | bind: function(event, callback) { 168 | this._bind('public', event, callback); 169 | }, 170 | 171 | unbind: function(event, callback) { 172 | this._unbind('public', event, callback); 173 | }, 174 | 175 | channel: function(channel_name) { 176 | return this._channels.find(channel_name); 177 | }, 178 | 179 | close: function() { 180 | if (this._connection) { 181 | this._connection.close(); 182 | } 183 | }, 184 | 185 | // private methods 186 | 187 | _on_connection_established: function(data) { 188 | Socky.Utils.log("connection_id", data.connection_id); 189 | this._connection_id = data.connection_id; 190 | this._is_connected = true; 191 | this._subscribe_pending_channels(); 192 | }, 193 | 194 | _subscribe_pending_channels: function() { 195 | this._channels.each(function(channel) { 196 | channel.subscribe(); 197 | }); 198 | } 199 | 200 | }); -------------------------------------------------------------------------------- /dist/0.4/socky.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socky JavaScript Library 3 | * 4 | * @version 0.4.2 5 | * @author Bernard Potocki 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | */ 9 | 10 | // Asset location for Socky(flash fallback and JSON files) 11 | window.SOCKY_ASSET_LOCATION = 'http://js.socky.org/v0.4/assets'; 12 | 13 | Socky = function(host, port, params) { 14 | this.host = host; 15 | this.port = port; 16 | this.params = params; 17 | // Open only if everything is loaded 18 | if(Socky.isReady) { 19 | this.connect(); 20 | } else { 21 | Socky.instances.push(this); 22 | } 23 | }; 24 | 25 | // Initializers 26 | Socky.isReady = false; 27 | Socky.instances = []; 28 | 29 | // Socky states 30 | Socky.CONNECTING = 0; 31 | Socky.AUTHENTICATING = 1; 32 | Socky.OPEN = 2; 33 | Socky.CLOSED = 3; 34 | Socky.UNAUTHENTICATED = 4; 35 | 36 | Socky.prototype.connect = function() { 37 | var instance = this; 38 | instance.state = Socky.CONNECTING; 39 | 40 | var ws = new WebSocket(this.host + ':' + this.port + '/?' + this.params); 41 | ws.onopen = function() { instance.onopen(); }; 42 | ws.onmessage = function(evt) { instance.onmessage(evt); }; 43 | ws.onclose = function() { instance.onclose(); }; 44 | ws.onerror = function() { instance.onerror(); }; 45 | }; 46 | 47 | 48 | 49 | // ***** Private methods ***** 50 | // Try to avoid any modification of these methods 51 | // Modification of these methods may cause script to work invalid 52 | // Please see 'public methods' below 53 | // *************************** 54 | 55 | // Run instances that are not already initialized 56 | Socky.ready = function () { 57 | Socky.isReady = true; 58 | for(var i = 0; i < Socky.instances.length; i++) { 59 | if(Socky.instances[i].state == undefined) Socky.instances[i].connect(); 60 | } 61 | } 62 | 63 | // Called when connection is opened 64 | Socky.prototype.onopen = function() { 65 | this.state = Socky.AUTHENTICATING; 66 | this.respond_to_connect(); 67 | }; 68 | 69 | // Called when socket message is received 70 | Socky.prototype.onmessage = function(evt) { 71 | try { 72 | var request = JSON.parse(evt.data); 73 | switch (request.type) { 74 | case "message": 75 | this.respond_to_message(request.body); 76 | break; 77 | case "authentication": 78 | if(request.body == "success") { 79 | this.state = Socky.OPEN; 80 | this.respond_to_authentication_success(); 81 | } else { 82 | this.state = Socky.UNAUTHENTICATED; 83 | this.respond_to_authentication_failure(); 84 | } 85 | break; 86 | } 87 | } catch (e) { 88 | console.error(e.toString()); 89 | } 90 | }; 91 | 92 | // Called when socket connection is closed 93 | Socky.prototype.onclose = function() { 94 | if(this.state != Socky.CLOSED && this.state != Socky.UNAUTHENTICATED) { 95 | this.respond_to_disconnect(); 96 | } 97 | }; 98 | 99 | // Called when error occurs 100 | // Currently unused 101 | Socky.prototype.onerror = function() {}; 102 | 103 | 104 | 105 | // ***** Public methods ***** 106 | // These methods can be freely modified. 107 | // The change should not affect the normal operation of the script. 108 | // ************************** 109 | 110 | // Called after connection but before authentication confirmation is received 111 | // At this point user is still not allowed to receive messages 112 | Socky.prototype.respond_to_connect = function() { 113 | }; 114 | 115 | // Called when authentication confirmation is received. 116 | // At this point user will be able to receive messages 117 | Socky.prototype.respond_to_authentication_success = function() { 118 | }; 119 | 120 | // Called when authentication is rejected by server 121 | // This usually means that secret is invalid or that authentication server is unavailable 122 | // This method will NOT be called if connection with Socky server will be broken - see respond_to_disconnect 123 | Socky.prototype.respond_to_authentication_failure = function() { 124 | }; 125 | 126 | // Called when new message is received 127 | // Note that msg is not sanitized - it can be any script received. 128 | Socky.prototype.respond_to_message = function(msg) { 129 | eval(msg); 130 | }; 131 | 132 | // Called when connection is broken between client and server 133 | // This usually happens when user lost his connection or when Socky server is down. 134 | // At default it will try to reconnect after 1 second. 135 | Socky.prototype.respond_to_disconnect = function() { 136 | var instance = this; 137 | setTimeout(function() { instance.connect(); }, 1000); 138 | } 139 | // ***** Asset loading ***** 140 | // These methods should not be modified. 141 | // They load JSON and flash fallback if they are required 142 | // ************************* 143 | 144 | // Function to load external javascript 145 | var _require = (function () { 146 | 147 | var handleScriptLoaded; 148 | if (document.addEventListener) { 149 | handleScriptLoaded = function (elem, callback) { 150 | elem.addEventListener('load', callback, false) 151 | } 152 | } else { 153 | handleScriptLoaded = function(elem, callback) { 154 | elem.attachEvent('onreadystatechange', function () { 155 | if(elem.readyState == 'loaded' || elem.readyState == 'complete') callback() 156 | }) 157 | } 158 | } 159 | 160 | return function (deps, callback) { 161 | var dep_count = 0, 162 | dep_length = deps.length; 163 | 164 | function checkReady (callback) { 165 | dep_count++; 166 | if ( dep_length == dep_count ) { 167 | // Opera needs the timeout for page initialization weirdness 168 | setTimeout(callback, 0); 169 | } 170 | } 171 | 172 | function addScript (src, callback) { 173 | callback = callback || function(){} 174 | var head = document.getElementsByTagName('head')[0]; 175 | var script = document.createElement('script'); 176 | script.setAttribute('src', src); 177 | script.setAttribute("type","text/javascript"); 178 | script.setAttribute('async', true); 179 | 180 | handleScriptLoaded(script, function () { 181 | checkReady(callback); 182 | }); 183 | 184 | head.appendChild(script); 185 | } 186 | 187 | for(var i = 0; i < dep_length; i++) { 188 | addScript(deps[i], callback); 189 | } 190 | } 191 | })(); 192 | 193 | // Check if JSON and WebSocket is available 194 | ;(function() { 195 | var deps = [], 196 | callback = function () { 197 | Socky.ready() 198 | } 199 | // Check for JSON dependency 200 | if (window['JSON'] == undefined) { 201 | deps.push(SOCKY_ASSET_LOCATION + '/json2.js'); 202 | } 203 | // Check for Flash fallback dep. Wrap initialization. 204 | if (window['WebSocket'] == undefined) { 205 | // Don't let WebSockets.js initialize on load. Inconsistent accross browsers. 206 | window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; 207 | // Set URL of your WebSocketMain.swf here: 208 | window.WEB_SOCKET_SWF_LOCATION = SOCKY_ASSET_LOCATION + "/WebSocketMain.swf"; 209 | // Set this to dump debug message from Flash to console.log: 210 | window.WEB_SOCKET_DEBUG = false; 211 | deps.push(SOCKY_ASSET_LOCATION + '/flashfallback.js'); 212 | callback = function(){ 213 | FABridge.addInitializationCallback('webSocket', function () { 214 | Socky.ready(); 215 | }) 216 | // Run this AFTER adding the callback above 217 | WebSocket.__initialize(); 218 | } 219 | } 220 | 221 | if( deps.length > 0){ 222 | _require(deps, callback); 223 | } else { 224 | callback(); 225 | } 226 | 227 | })(); 228 | -------------------------------------------------------------------------------- /dist/0.4.2/socky.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socky JavaScript Library 3 | * 4 | * @version 0.4.2 5 | * @author Bernard Potocki 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | */ 9 | 10 | // Asset location for Socky(flash fallback and JSON files) 11 | window.SOCKY_ASSET_LOCATION = 'http://js.socky.org/v0.4/assets'; 12 | 13 | Socky = function(host, port, params) { 14 | this.host = host; 15 | this.port = port; 16 | this.params = params; 17 | // Open only if everything is loaded 18 | if(Socky.isReady) { 19 | this.connect(); 20 | } else { 21 | Socky.instances.push(this); 22 | } 23 | }; 24 | 25 | // Initializers 26 | Socky.isReady = false; 27 | Socky.instances = []; 28 | 29 | // Socky states 30 | Socky.CONNECTING = 0; 31 | Socky.AUTHENTICATING = 1; 32 | Socky.OPEN = 2; 33 | Socky.CLOSED = 3; 34 | Socky.UNAUTHENTICATED = 4; 35 | 36 | Socky.prototype.connect = function() { 37 | var instance = this; 38 | instance.state = Socky.CONNECTING; 39 | 40 | var ws = new WebSocket(this.host + ':' + this.port + '/?' + this.params); 41 | ws.onopen = function() { instance.onopen(); }; 42 | ws.onmessage = function(evt) { instance.onmessage(evt); }; 43 | ws.onclose = function() { instance.onclose(); }; 44 | ws.onerror = function() { instance.onerror(); }; 45 | }; 46 | 47 | 48 | 49 | // ***** Private methods ***** 50 | // Try to avoid any modification of these methods 51 | // Modification of these methods may cause script to work invalid 52 | // Please see 'public methods' below 53 | // *************************** 54 | 55 | // Run instances that are not already initialized 56 | Socky.ready = function () { 57 | Socky.isReady = true; 58 | for(var i = 0; i < Socky.instances.length; i++) { 59 | if(Socky.instances[i].state == undefined) Socky.instances[i].connect(); 60 | } 61 | } 62 | 63 | // Called when connection is opened 64 | Socky.prototype.onopen = function() { 65 | this.state = Socky.AUTHENTICATING; 66 | this.respond_to_connect(); 67 | }; 68 | 69 | // Called when socket message is received 70 | Socky.prototype.onmessage = function(evt) { 71 | try { 72 | var request = JSON.parse(evt.data); 73 | switch (request.type) { 74 | case "message": 75 | this.respond_to_message(request.body); 76 | break; 77 | case "authentication": 78 | if(request.body == "success") { 79 | this.state = Socky.OPEN; 80 | this.respond_to_authentication_success(); 81 | } else { 82 | this.state = Socky.UNAUTHENTICATED; 83 | this.respond_to_authentication_failure(); 84 | } 85 | break; 86 | } 87 | } catch (e) { 88 | console.error(e.toString()); 89 | } 90 | }; 91 | 92 | // Called when socket connection is closed 93 | Socky.prototype.onclose = function() { 94 | if(this.state != Socky.CLOSED && this.state != Socky.UNAUTHENTICATED) { 95 | this.respond_to_disconnect(); 96 | } 97 | }; 98 | 99 | // Called when error occurs 100 | // Currently unused 101 | Socky.prototype.onerror = function() {}; 102 | 103 | 104 | 105 | // ***** Public methods ***** 106 | // These methods can be freely modified. 107 | // The change should not affect the normal operation of the script. 108 | // ************************** 109 | 110 | // Called after connection but before authentication confirmation is received 111 | // At this point user is still not allowed to receive messages 112 | Socky.prototype.respond_to_connect = function() { 113 | }; 114 | 115 | // Called when authentication confirmation is received. 116 | // At this point user will be able to receive messages 117 | Socky.prototype.respond_to_authentication_success = function() { 118 | }; 119 | 120 | // Called when authentication is rejected by server 121 | // This usually means that secret is invalid or that authentication server is unavailable 122 | // This method will NOT be called if connection with Socky server will be broken - see respond_to_disconnect 123 | Socky.prototype.respond_to_authentication_failure = function() { 124 | }; 125 | 126 | // Called when new message is received 127 | // Note that msg is not sanitized - it can be any script received. 128 | Socky.prototype.respond_to_message = function(msg) { 129 | eval(msg); 130 | }; 131 | 132 | // Called when connection is broken between client and server 133 | // This usually happens when user lost his connection or when Socky server is down. 134 | // At default it will try to reconnect after 1 second. 135 | Socky.prototype.respond_to_disconnect = function() { 136 | var instance = this; 137 | setTimeout(function() { instance.connect(); }, 1000); 138 | } 139 | // ***** Asset loading ***** 140 | // These methods should not be modified. 141 | // They load JSON and flash fallback if they are required 142 | // ************************* 143 | 144 | // Function to load external javascript 145 | var _require = (function () { 146 | 147 | var handleScriptLoaded; 148 | if (document.addEventListener) { 149 | handleScriptLoaded = function (elem, callback) { 150 | elem.addEventListener('load', callback, false) 151 | } 152 | } else { 153 | handleScriptLoaded = function(elem, callback) { 154 | elem.attachEvent('onreadystatechange', function () { 155 | if(elem.readyState == 'loaded' || elem.readyState == 'complete') callback() 156 | }) 157 | } 158 | } 159 | 160 | return function (deps, callback) { 161 | var dep_count = 0, 162 | dep_length = deps.length; 163 | 164 | function checkReady (callback) { 165 | dep_count++; 166 | if ( dep_length == dep_count ) { 167 | // Opera needs the timeout for page initialization weirdness 168 | setTimeout(callback, 0); 169 | } 170 | } 171 | 172 | function addScript (src, callback) { 173 | callback = callback || function(){} 174 | var head = document.getElementsByTagName('head')[0]; 175 | var script = document.createElement('script'); 176 | script.setAttribute('src', src); 177 | script.setAttribute("type","text/javascript"); 178 | script.setAttribute('async', true); 179 | 180 | handleScriptLoaded(script, function () { 181 | checkReady(callback); 182 | }); 183 | 184 | head.appendChild(script); 185 | } 186 | 187 | for(var i = 0; i < dep_length; i++) { 188 | addScript(deps[i], callback); 189 | } 190 | } 191 | })(); 192 | 193 | // Check if JSON and WebSocket is available 194 | ;(function() { 195 | var deps = [], 196 | callback = function () { 197 | Socky.ready() 198 | } 199 | // Check for JSON dependency 200 | if (window['JSON'] == undefined) { 201 | deps.push(SOCKY_ASSET_LOCATION + '/json2.js'); 202 | } 203 | // Check for Flash fallback dep. Wrap initialization. 204 | if (window['WebSocket'] == undefined) { 205 | // Don't let WebSockets.js initialize on load. Inconsistent accross browsers. 206 | window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; 207 | // Set URL of your WebSocketMain.swf here: 208 | window.WEB_SOCKET_SWF_LOCATION = SOCKY_ASSET_LOCATION + "/WebSocketMain.swf"; 209 | // Set this to dump debug message from Flash to console.log: 210 | window.WEB_SOCKET_DEBUG = false; 211 | deps.push(SOCKY_ASSET_LOCATION + '/flashfallback.js'); 212 | callback = function(){ 213 | FABridge.addInitializationCallback('webSocket', function () { 214 | Socky.ready(); 215 | }) 216 | // Run this AFTER adding the callback above 217 | WebSocket.__initialize(); 218 | } 219 | } 220 | 221 | if( deps.length > 0){ 222 | _require(deps, callback); 223 | } else { 224 | callback(); 225 | } 226 | 227 | })(); 228 | -------------------------------------------------------------------------------- /test/lib/jasmine-1.0.2/jasmine-html.js: -------------------------------------------------------------------------------- 1 | jasmine.TrivialReporter = function(doc) { 2 | this.document = doc || document; 3 | this.suiteDivs = {}; 4 | this.logRunningSpecs = false; 5 | }; 6 | 7 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 8 | var el = document.createElement(type); 9 | 10 | for (var i = 2; i < arguments.length; i++) { 11 | var child = arguments[i]; 12 | 13 | if (typeof child === 'string') { 14 | el.appendChild(document.createTextNode(child)); 15 | } else { 16 | if (child) { el.appendChild(child); } 17 | } 18 | } 19 | 20 | for (var attr in attrs) { 21 | if (attr == "className") { 22 | el[attr] = attrs[attr]; 23 | } else { 24 | el.setAttribute(attr, attrs[attr]); 25 | } 26 | } 27 | 28 | return el; 29 | }; 30 | 31 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 32 | var showPassed, showSkipped; 33 | 34 | this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, 35 | this.createDom('div', { className: 'banner' }, 36 | this.createDom('div', { className: 'logo' }, 37 | this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"), 38 | this.createDom('span', { className: 'version' }, runner.env.versionString())), 39 | this.createDom('div', { className: 'options' }, 40 | "Show ", 41 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 42 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 43 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 44 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 45 | ) 46 | ), 47 | 48 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 49 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 50 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 51 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 52 | ); 53 | 54 | this.document.body.appendChild(this.outerDiv); 55 | 56 | var suites = runner.suites(); 57 | for (var i = 0; i < suites.length; i++) { 58 | var suite = suites[i]; 59 | var suiteDiv = this.createDom('div', { className: 'suite' }, 60 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 61 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 62 | this.suiteDivs[suite.id] = suiteDiv; 63 | var parentDiv = this.outerDiv; 64 | if (suite.parentSuite) { 65 | parentDiv = this.suiteDivs[suite.parentSuite.id]; 66 | } 67 | parentDiv.appendChild(suiteDiv); 68 | } 69 | 70 | this.startedAt = new Date(); 71 | 72 | var self = this; 73 | showPassed.onclick = function(evt) { 74 | if (showPassed.checked) { 75 | self.outerDiv.className += ' show-passed'; 76 | } else { 77 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 78 | } 79 | }; 80 | 81 | showSkipped.onclick = function(evt) { 82 | if (showSkipped.checked) { 83 | self.outerDiv.className += ' show-skipped'; 84 | } else { 85 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 86 | } 87 | }; 88 | }; 89 | 90 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 91 | var results = runner.results(); 92 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 93 | this.runnerDiv.setAttribute("class", className); 94 | //do it twice for IE 95 | this.runnerDiv.setAttribute("className", className); 96 | var specs = runner.specs(); 97 | var specCount = 0; 98 | for (var i = 0; i < specs.length; i++) { 99 | if (this.specFilter(specs[i])) { 100 | specCount++; 101 | } 102 | } 103 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 104 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 105 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 106 | 107 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 108 | }; 109 | 110 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 111 | var results = suite.results(); 112 | var status = results.passed() ? 'passed' : 'failed'; 113 | if (results.totalCount == 0) { // todo: change this to check results.skipped 114 | status = 'skipped'; 115 | } 116 | this.suiteDivs[suite.id].className += " " + status; 117 | }; 118 | 119 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 120 | if (this.logRunningSpecs) { 121 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 122 | } 123 | }; 124 | 125 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 126 | var results = spec.results(); 127 | var status = results.passed() ? 'passed' : 'failed'; 128 | if (results.skipped) { 129 | status = 'skipped'; 130 | } 131 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 132 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 133 | this.createDom('a', { 134 | className: 'description', 135 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 136 | title: spec.getFullName() 137 | }, spec.description)); 138 | 139 | 140 | var resultItems = results.getItems(); 141 | var messagesDiv = this.createDom('div', { className: 'messages' }); 142 | for (var i = 0; i < resultItems.length; i++) { 143 | var result = resultItems[i]; 144 | 145 | if (result.type == 'log') { 146 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 147 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 148 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 149 | 150 | if (result.trace.stack) { 151 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 152 | } 153 | } 154 | } 155 | 156 | if (messagesDiv.childNodes.length > 0) { 157 | specDiv.appendChild(messagesDiv); 158 | } 159 | 160 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 161 | }; 162 | 163 | jasmine.TrivialReporter.prototype.log = function() { 164 | var console = jasmine.getGlobal().console; 165 | if (console && console.log) { 166 | if (console.log.apply) { 167 | console.log.apply(console, arguments); 168 | } else { 169 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 170 | } 171 | } 172 | }; 173 | 174 | jasmine.TrivialReporter.prototype.getLocation = function() { 175 | return this.document.location; 176 | }; 177 | 178 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 179 | var paramMap = {}; 180 | var params = this.getLocation().search.substring(1).split('&'); 181 | for (var i = 0; i < params.length; i++) { 182 | var p = params[i].split('='); 183 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 184 | } 185 | 186 | if (!paramMap["spec"]) return true; 187 | return spec.getFullName().indexOf(paramMap["spec"]) == 0; 188 | }; 189 | -------------------------------------------------------------------------------- /test/spec/SockySpec.js: -------------------------------------------------------------------------------- 1 | describe('Socky Connection', function () { 2 | 3 | it('should receive a "socky:connection:established" with a proper connection_id', function() { 4 | 5 | var callback; 6 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 7 | 8 | runs(function() { 9 | callback = jasmine.createSpy('Connection established callback'); 10 | socky.bind("socky:connection:established", callback); 11 | }); 12 | 13 | waitsFor(function() { return callback.wasCalled; }, 5000); 14 | 15 | runs(function() { 16 | expect(callback.mostRecentCall.args[0].connection_id).toBeDefined(); 17 | socky.close(); 18 | }); 19 | 20 | }); 21 | 22 | it('should receive a "socky:connection:error" message with "refused" reason when using a wrong app_id', function() { 23 | 24 | var callback; 25 | var socky = new Socky.Client('ws://localhost:3001/websocket/invalid_app'); 26 | 27 | runs(function() { 28 | callback = jasmine.createSpy('Connection error callback'); 29 | socky.bind("socky:connection:error", callback); 30 | }); 31 | 32 | waitsFor(function() { return callback.wasCalled; }, 5000); 33 | 34 | runs(function() { 35 | expect(callback.mostRecentCall.args[0].reason).toEqual('refused'); 36 | socky.close(); 37 | }); 38 | 39 | }); 40 | 41 | it('should receive a "socky:connection:error" message with "down" reason when using a wrong host', function() { 42 | 43 | var callback; 44 | var socky = new Socky.Client('ws://example.com:3001/websocket/invalid_app'); 45 | 46 | runs(function() { 47 | callback = jasmine.createSpy('Connection error callback'); 48 | socky.bind("socky:connection:error", callback); 49 | }); 50 | 51 | waitsFor(function() { return callback.wasCalled; }, 15000); 52 | 53 | runs(function() { 54 | expect(callback.mostRecentCall.args[0].reason).toEqual('down'); 55 | socky.close(); 56 | }); 57 | 58 | }); 59 | 60 | it('should receive a "socky:connection:closed" message when calling .close()', function() { 61 | 62 | var callback; 63 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 64 | 65 | runs(function() { 66 | callback = jasmine.createSpy('Connection established callback'); 67 | socky.bind("socky:connection:established", callback); 68 | }); 69 | 70 | waitsFor(function() { return callback.wasCalled; }, 5000); 71 | 72 | runs(function() { 73 | callback = jasmine.createSpy('Connection closed callback'); 74 | socky.bind("socky:connection:closed", callback); 75 | socky.close(); 76 | }); 77 | 78 | waitsFor(function() { return callback.wasCalled; }, 5000); 79 | 80 | }); 81 | 82 | }); 83 | 84 | describe('Socky Public Channel', function () { 85 | 86 | it('should receive a "socky:subscribe:success" with a proper channel after subscribing', function() { 87 | 88 | var callback; 89 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 90 | 91 | runs(function() { 92 | callback = jasmine.createSpy('Subscribe success callback'); 93 | socky.bind("socky:subscribe:success", callback); 94 | socky.subscribe('test_channel'); 95 | }); 96 | 97 | waitsFor(function() { return callback.wasCalled; }, 5000); 98 | 99 | runs(function() { 100 | expect(callback.mostRecentCall.args[0].channel).toEqual('test_channel'); 101 | socky.close(); 102 | }); 103 | 104 | }); 105 | 106 | it('should receive a "socky:unsubscribe:success" with a proper channel after unsubscribing from subscribed channel', function() { 107 | 108 | var callback; 109 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 110 | 111 | runs(function() { 112 | callback = jasmine.createSpy('Unsubscribe success callback'); 113 | socky.bind("socky:unsubscribe:success", callback); 114 | socky.bind("socky:subscribe:success", function() { 115 | socky.unsubscribe('test_channel');; 116 | }) 117 | socky.subscribe('test_channel'); 118 | }); 119 | 120 | waitsFor(function() { return callback.wasCalled; }, 10000); 121 | 122 | runs(function() { 123 | expect(callback.mostRecentCall.args[0].channel).toEqual('test_channel'); 124 | socky.close(); 125 | }); 126 | 127 | }); 128 | 129 | it('should receive a "socky:unsubscribe:failure" with a proper channel after tring to unsubscribe from not subscribed channel', function() { 130 | 131 | var callback; 132 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 133 | 134 | runs(function() { 135 | callback = jasmine.createSpy('Connection established callback'); 136 | socky.bind("socky:connection:established", callback); 137 | }); 138 | 139 | waitsFor(function() { return callback.wasCalled; }, 5000); 140 | 141 | runs(function() { 142 | callback = jasmine.createSpy('Unsubscribe failure callback'); 143 | socky.bind("socky:unsubscribe:failure", callback); 144 | socky.unsubscribe('test_channel'); 145 | }); 146 | 147 | waitsFor(function() { return callback.wasCalled; }, 5000); 148 | 149 | runs(function() { 150 | expect(callback.mostRecentCall.args[0].channel).toEqual('test_channel'); 151 | socky.close(); 152 | }); 153 | 154 | }); 155 | 156 | }); 157 | 158 | describe('Socky Private Channel', function () { 159 | 160 | it('should receive a "socky:subscribe:success" with a proper channel after subscribing', function() { 161 | 162 | var callback; 163 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 164 | 165 | runs(function() { 166 | callback = jasmine.createSpy('Subscribe success callback'); 167 | socky.bind("socky:subscribe:success", callback); 168 | socky.subscribe('private-test_channel'); 169 | }); 170 | 171 | waitsFor(function() { return callback.wasCalled; }, 5000); 172 | 173 | runs(function() { 174 | expect(callback.mostRecentCall.args[0].channel).toEqual('private-test_channel'); 175 | socky.close(); 176 | }); 177 | 178 | }); 179 | 180 | it('should receive a "socky:subscribe:failure" with a proper channel if subscribe request was rejected', function() { 181 | 182 | var callback; 183 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 184 | 185 | runs(function() { 186 | callback = jasmine.createSpy('Subscribe failure callback'); 187 | socky.bind("socky:subscribe:failure", callback); 188 | socky.subscribe('private-invalid_channel'); 189 | }); 190 | 191 | waitsFor(function() { return callback.wasCalled; }, 5000); 192 | 193 | runs(function() { 194 | expect(callback.mostRecentCall.args[0].channel).toEqual('private-invalid_channel'); 195 | socky.close(); 196 | }); 197 | 198 | }); 199 | 200 | it('should receive a "socky:unsubscribe:success" with a proper channel after unsubscribing from subscribed channel', function() { 201 | 202 | var callback; 203 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 204 | 205 | runs(function() { 206 | callback = jasmine.createSpy('Unsubscribe success callback'); 207 | socky.bind("socky:unsubscribe:success", callback); 208 | socky.bind("socky:subscribe:success", function() { 209 | socky.unsubscribe('private-test_channel');; 210 | }) 211 | socky.subscribe('private-test_channel'); 212 | }); 213 | 214 | waitsFor(function() { return callback.wasCalled; }, 10000); 215 | 216 | runs(function() { 217 | expect(callback.mostRecentCall.args[0].channel).toEqual('private-test_channel'); 218 | socky.close(); 219 | }); 220 | 221 | }); 222 | 223 | it('should receive a "socky:unsubscribe:failure" with a proper channel after try to unsubscribe from not subscribed channel', function() { 224 | 225 | var callback; 226 | var socky = new Socky.Client('ws://localhost:3001/websocket/my_app'); 227 | 228 | runs(function() { 229 | callback = jasmine.createSpy('Connection established callback'); 230 | socky.bind("socky:connection:established", callback); 231 | }); 232 | 233 | waitsFor(function() { return callback.wasCalled; }, 5000); 234 | 235 | runs(function() { 236 | callback = jasmine.createSpy('Unsubscribe failure callback'); 237 | socky.bind("socky:unsubscribe:failure", callback); 238 | socky.unsubscribe('private-test_channel'); 239 | }); 240 | 241 | waitsFor(function() { return callback.wasCalled; }, 5000); 242 | 243 | runs(function() { 244 | expect(callback.mostRecentCall.args[0].channel).toEqual('private-test_channel'); 245 | socky.close(); 246 | }); 247 | 248 | }); 249 | 250 | }); 251 | 252 | /*$(document).ready(function() { 253 | 254 | //// Presence channel 255 | 256 | // presence_subscribe_success 257 | var socky_presence_subscribe_success = new Socky('ws://localhost:3001/websocket/my_app', {assets_location: '../dist/0.5.0-beta1/assets'}); 258 | socky_presence_subscribe_success.bind("socky:subscribe:success", function(payload) { 259 | if(payload.channel == 'presence-presence_subscribe_success') { 260 | pass('presence_subscribe_success'); 261 | socky_presence_subscribe_success.close(); 262 | }; 263 | }); 264 | socky_presence_subscribe_success.subscribe('presence-presence_subscribe_success'); 265 | } 266 | }); 267 | */ -------------------------------------------------------------------------------- /dist/0.5.0-beta1/socky.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socky JavaScript Library 3 | * 4 | * @version 0.5.0-beta1 5 | * @author Bernard Potocki 6 | * @author Stefano Verna 7 | * @licence The MIT licence. 8 | * @source http://github.com/socky/socky-client-js 9 | */ 10 | /*! 11 | * Simple JavaScript Inheritance 12 | * By John Resig http://ejohn.org/ 13 | * MIT Licensed. 14 | * 15 | * Inspired by base2 and Prototype 16 | */ 17 | 18 | (function(){var h=!1,j=/xyz/.test(function(){})?/\b_super\b/:/.*/,i=function(){};i.extend=function(a){function b(){!h&&this.init&&this.init.apply(this,arguments)}var c=this.prototype;h=!0;var d=new this;h=!1;for(var e in a)d[e]=typeof a[e]=="function"&&typeof c[e]=="function"&&j.test(a[e])?function(a,b){return function(){var d=this._super;this._super=c[a];var e=b.apply(this,arguments);this._super=d;return e}}(e,a[e]):a[e];b.prototype=d;b.constructor=b;b.extend=arguments.callee;return b};Events=i.extend({_bind:function(a, 19 | b,c){this._callbacks=this._callbacks||{};this._callbacks[a]||(this._callbacks[a]={});(this._callbacks[a][b]||(this._callbacks[a][b]=[])).push(c);return this},_unbind:function(a,b,c){if(this._callbacks&&!b)this._callbacks[a]={};else if(a=this._callbacks[a])if(c){b=a[b];if(!b)return this;a=0;for(var d=b.length;a> Socky");Function.prototype.apply.apply(console.log, 27 | [console,a])}},is_number:function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)},each:function(a,b,c){if(a!=null)if(Array.prototype.forEach&&a.forEach===Array.prototype.forEach)a.forEach(b,c);else if(Socky.Utils.is_number(a.length))for(var d=0,e=a.length;d0?this._require_scripts(a,b):b()}},_web_sockets_loaded:function(){this._is_websocket_driver_loaded=!0;Socky.Utils.each(this._socky_instances, 41 | function(a){a.is_connected()||a.connect()})},_require_scripts:function(a,b){var c=0,d;d=document.addEventListener?function(a,b){a.addEventListener("load",b,!1)}:function(a,b){a.attachEvent("onreadystatechange",function(){(a.readyState=="loaded"||a.readyState=="complete")&&b()})};for(var e=Socky.Utils.bind(function(b){c++;a.length==c&&(Socky.Utils.log("All the require script have been loaded!"),setTimeout(b,0))},this),f=Socky.Utils.bind(function(a,b){b=b||function(){};var c=document.getElementsByTagName("head")[0], 42 | f=document.createElement("script");f.setAttribute("src",a);f.setAttribute("type","text/javascript");f.setAttribute("async",!0);Socky.Utils.log("Adding script",a);d(f,function(){e(b)});c.appendChild(f)},this),g=0;g 6 | * @author Stefano Verna 7 | * @licence The MIT licence. 8 | * @source http://github.com/socky/socky-client-js 9 | */ 10 | /*! 11 | * This library contains code with the following licences: 12 | * 13 | * web_socket.js: 14 | * 15 | * Copyright: Hiroshi Ichikawa 16 | * License: New BSD License 17 | * Reference: http://dev.w3.org/html5/websockets/ 18 | * Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol 19 | * 20 | * swfobject.js: 21 | * 22 | * SWFObject v2.2 23 | * is released under the MIT License 24 | */ 25 | 26 | var swfobject=function(){function h(){if(!w){try{var b=e.getElementsByTagName("body")[0].appendChild(e.createElement("span"));b.parentNode.removeChild(b)}catch(c){return}w=!0;b=B.length;for(var j=0;j0)for(var c=0;c0){var e=p(j);if(e)if(D(u[c].swfVersion)&&!(f.wk&&f.wk<312)){if(x(j,!0),a)g.success=!0,g.ref=z(j),a(g)}else if(u[c].expressInstall&&r()){g={};g.data=u[c].expressInstall;g.width=e.getAttribute("width")||"0";g.height=e.getAttribute("height")||"0";if(e.getAttribute("class"))g.styleclass=e.getAttribute("class");if(e.getAttribute("align"))g.align=e.getAttribute("align");var i={};e=e.getElementsByTagName("param");for(var d=e.length,m=0;m');g.outerHTML='"+i+"";G[G.length]=b.id;l=p(b.id)}else{h=e.createElement(s);h.setAttribute("type",C);for(var m in b)b[m]!=Object.prototype[m]&&(m.toLowerCase()=="styleclass"?h.setAttribute("class",b[m]):m.toLowerCase()!="classid"&&h.setAttribute(m,b[m]));for(d in c)c[d]!=Object.prototype[d]&&d.toLowerCase()!= 34 | "movie"&&(b=h,i=d,m=c[d],a=e.createElement("param"),a.setAttribute("name",i),a.setAttribute("value",m),b.appendChild(a));g.parentNode.replaceChild(h,g);l=h}}return l}function O(b){var c=p(b);if(c&&c.nodeName=="OBJECT")f.ie&&f.win?(c.style.display="none",function(){if(c.readyState==4){var a=p(b);if(a){for(var e in a)typeof a[e]=="function"&&(a[e]=null);a.parentNode.removeChild(a)}}else setTimeout(arguments.callee,10)}()):c.parentNode.removeChild(c)}function p(b){var c=null;try{c=e.getElementById(b)}catch(a){}return c} 35 | function T(b,c,a){b.attachEvent(c,a);y[y.length]=[b,c,a]}function D(b){var a=f.pv;b=b.split(".");b[0]=parseInt(b[0],10);b[1]=parseInt(b[1],10)||0;b[2]=parseInt(b[2],10)||0;return a[0]>b[0]||a[0]==b[0]&&a[1]>b[1]||a[0]==b[0]&&a[1]==b[1]&&a[2]>=b[2]?!0:!1}function P(b,a,j,d){if(!f.ie||!f.mac){var g=e.getElementsByTagName("head")[0];if(g){j=j&&typeof j=="string"?j:"screen";d&&(L=q=null);if(!q||L!=j)d=e.createElement("style"),d.setAttribute("type","text/css"),d.setAttribute("media",j),q=g.appendChild(d), 36 | f.ie&&f.win&&typeof e.styleSheets!=k&&e.styleSheets.length>0&&(q=e.styleSheets[e.styleSheets.length-1]),L=j;f.ie&&f.win?q&&typeof q.addRule==s&&q.addRule(b,a):q&&typeof e.createTextNode!=k&&q.appendChild(e.createTextNode(b+" {"+a+"}"))}}}function x(b,a){if(Q){var e=a?"visible":"hidden";w&&p(b)?p(b).style.visibility=e:P("#"+b,"visibility:"+e)}}function R(b){return/[\\\"<>\.;]/.exec(b)!=null&&typeof encodeURIComponent!=k?encodeURIComponent(b):b}var k="undefined",s="object",C="application/x-shockwave-flash", 37 | N="SWFObjectExprInst",n=window,e=document,v=navigator,S=!1,B=[function(){S?t():o()}],u=[],G=[],y=[],A,F,I,M,w=!1,E=!1,q,L,Q=!0,f=function(){var b=typeof e.getElementById!=k&&typeof e.getElementsByTagName!=k&&typeof e.createElement!=k,a=v.userAgent.toLowerCase(),j=v.platform.toLowerCase(),f=j?/win/.test(j):/win/.test(a);j=j?/mac/.test(j):/mac/.test(a);a=/webkit/.test(a)?parseFloat(a.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):!1;var g=!1,d=[0,0,0],i=null;if(typeof v.plugins!=k&&typeof v.plugins["Shockwave Flash"]== 38 | s){if((i=v.plugins["Shockwave Flash"].description)&&!(typeof v.mimeTypes!=k&&v.mimeTypes[C]&&!v.mimeTypes[C].enabledPlugin))S=!0,g=!1,i=i.replace(/^.*\s+(\S+\s+\S+$)/,"$1"),d[0]=parseInt(i.replace(/^(.*)\..*$/,"$1"),10),d[1]=parseInt(i.replace(/^.*\.(.*)\s.*$/,"$1"),10),d[2]=/[a-zA-Z]/.test(i)?parseInt(i.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}else if(typeof n.ActiveXObject!=k)try{var h=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");if(h&&(i=h.GetVariable("$version")))g=!0,i=i.split(" ")[1].split(","), 39 | d=[parseInt(i[0],10),parseInt(i[1],10),parseInt(i[2],10)]}catch(m){}return{w3:b,pv:d,wk:a,ie:g,win:f,mac:j}}();(function(){f.w3&&((typeof e.readyState!=k&&e.readyState=="complete"||typeof e.readyState==k&&(e.getElementsByTagName("body")[0]||e.body))&&h(),w||(typeof e.addEventListener!=k&&e.addEventListener("DOMContentLoaded",h,!1),f.ie&&f.win&&(e.attachEvent("onreadystatechange",function(){e.readyState=="complete"&&(e.detachEvent("onreadystatechange",arguments.callee),h())}),n==top&&function(){if(!w){try{e.documentElement.doScroll("left")}catch(b){setTimeout(arguments.callee, 40 | 0);return}h()}}()),f.wk&&function(){w||(/loaded|complete/.test(e.readyState)?h():setTimeout(arguments.callee,0))}(),d(h)))})();(function(){f.ie&&f.win&&window.attachEvent("onunload",function(){for(var b=y.length,a=0;a=10?h.error("Flash Player >= 10.0.0 is required."):(location.protocol=="file:"&&h.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://..."),WebSocket=function(a,d,h,o,z){var r=this;r.__id=WebSocket.__nextId++;WebSocket.__instances[r.__id]=r; 45 | r.readyState=WebSocket.CONNECTING;r.bufferedAmount=0;r.__events={};d?typeof d=="string"&&(d=[d]):d=[];setTimeout(function(){WebSocket.__addTask(function(){WebSocket.__flash.create(r.__id,a,d,h||null,o||0,z||null)})},0)},WebSocket.prototype.send=function(a){if(this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";a=WebSocket.__flash.send(this.__id,encodeURIComponent(a));return a<0?!0:(this.bufferedAmount+=a,!1)},WebSocket.prototype.close=function(){if(!(this.readyState== 46 | WebSocket.CLOSED||this.readyState==WebSocket.CLOSING))this.readyState=WebSocket.CLOSING,WebSocket.__flash.close(this.__id)},WebSocket.prototype.addEventListener=function(a,d){a in this.__events||(this.__events[a]=[]);this.__events[a].push(d)},WebSocket.prototype.removeEventListener=function(a,d){if(a in this.__events)for(var h=this.__events[a],o=h.length-1;o>=0;--o)if(h[o]===d){h.splice(o,1);break}},WebSocket.prototype.dispatchEvent=function(a){for(var d=this.__events[a.type]||[],h=0;h 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | * 9 | * This library contains code with the following licences: 10 | * 11 | * web_socket.js: 12 | * 13 | * Copyright: Hiroshi Ichikawa 14 | * License: New BSD License 15 | * Reference: http://dev.w3.org/html5/websockets/ 16 | * Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol 17 | * 18 | * swfobject.js: 19 | * 20 | * SWFObject v2.2 21 | * is released under the MIT License 22 | * 23 | * FABridge.js: 24 | * 25 | * Copyright 2006 Adobe Systems Incorporated 26 | * 27 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 28 | * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 29 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 30 | * 31 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 32 | */ 33 | 34 | var swfobject=function(){function c(){if(!D){try{var a=l.getElementsByTagName("body")[0].appendChild(l.createElement("span"));a.parentNode.removeChild(a)}catch(d){return}D=true;a=K.length;for(var f=0;f0)for(var d= 36 | 0;d0){var n=v(f);if(n)if(M(z[d].swfVersion)&&!(j.wk&&j.wk<312)){E(f,true);if(h){i.success=true;i.ref=o(f);h(i)}}else if(z[d].expressInstall&&t()){i={};i.data=z[d].expressInstall;i.width=n.getAttribute("width")||"0";i.height=n.getAttribute("height")||"0";if(n.getAttribute("class"))i.styleclass=n.getAttribute("class");if(n.getAttribute("align"))i.align=n.getAttribute("align");var m={};n=n.getElementsByTagName("param");for(var q= 37 | n.length,r=0;r';i.outerHTML='"+m+"";P[P.length]=a.id;h=v(a.id)}else{q=l.createElement(w);q.setAttribute("type",L);for(var r in a)if(a[r]!=Object.prototype[r])if(r.toLowerCase()=="styleclass")q.setAttribute("class", 42 | a[r]);else r.toLowerCase()!="classid"&&q.setAttribute(r,a[r]);for(n in d)if(d[n]!=Object.prototype[n]&&n.toLowerCase()!="movie"){a=q;m=n;r=d[n];f=l.createElement("param");f.setAttribute("name",m);f.setAttribute("value",r);a.appendChild(f)}i.parentNode.replaceChild(q,i);h=q}}return h}function X(a){var d=v(a);if(d&&d.nodeName=="OBJECT")if(j.ie&&j.win){d.style.display="none";(function(){if(d.readyState==4){var f=v(a);if(f){for(var h in f)if(typeof f[h]=="function")f[h]=null;f.parentNode.removeChild(f)}}else setTimeout(arguments.callee, 43 | 10)})()}else d.parentNode.removeChild(d)}function v(a){var d=null;try{d=l.getElementById(a)}catch(f){}return d}function ba(a,d,f){a.attachEvent(d,f);H[H.length]=[a,d,f]}function M(a){var d=j.pv;a=a.split(".");a[0]=parseInt(a[0],10);a[1]=parseInt(a[1],10)||0;a[2]=parseInt(a[2],10)||0;return d[0]>a[0]||d[0]==a[0]&&d[1]>a[1]||d[0]==a[0]&&d[1]==a[1]&&d[2]>=a[2]?true:false}function Y(a,d,f,h){if(!(j.ie&&j.mac)){var i=l.getElementsByTagName("head")[0];if(i){f=f&&typeof f=="string"?f:"screen";if(h)U=x=null; 44 | if(!x||U!=f){h=l.createElement("style");h.setAttribute("type","text/css");h.setAttribute("media",f);x=i.appendChild(h);if(j.ie&&j.win&&typeof l.styleSheets!=p&&l.styleSheets.length>0)x=l.styleSheets[l.styleSheets.length-1];U=f}if(j.ie&&j.win)x&&typeof x.addRule==w&&x.addRule(a,d);else x&&typeof l.createTextNode!=p&&x.appendChild(l.createTextNode(a+" {"+d+"}"))}}}function E(a,d){if(Z){var f=d?"visible":"hidden";if(D&&v(a))v(a).style.visibility=f;else Y("#"+a,"visibility:"+f)}}function $(a){return/[\\\"<>\.;]/.exec(a)!= 45 | null&&typeof encodeURIComponent!=p?encodeURIComponent(a):a}var p="undefined",w="object",L="application/x-shockwave-flash",W="SWFObjectExprInst",u=window,l=document,B=navigator,aa=false,K=[function(){aa?g():k()}],z=[],P=[],H=[],I,O,T,V,D=false,N=false,x,U,Z=true,j=function(){var a=typeof l.getElementById!=p&&typeof l.getElementsByTagName!=p&&typeof l.createElement!=p,d=B.userAgent.toLowerCase(),f=B.platform.toLowerCase(),h=f?/win/.test(f):/win/.test(d);f=f?/mac/.test(f):/mac/.test(d);d=/webkit/.test(d)? 46 | parseFloat(d.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false;var i=!+"\u000b1",n=[0,0,0],m=null;if(typeof B.plugins!=p&&typeof B.plugins["Shockwave Flash"]==w){if((m=B.plugins["Shockwave Flash"].description)&&!(typeof B.mimeTypes!=p&&B.mimeTypes[L]&&!B.mimeTypes[L].enabledPlugin)){aa=true;i=false;m=m.replace(/^.*\s+(\S+\s+\S+$)/,"$1");n[0]=parseInt(m.replace(/^(.*)\..*$/,"$1"),10);n[1]=parseInt(m.replace(/^.*\.(.*)\s.*$/,"$1"),10);n[2]=/[a-zA-Z]/.test(m)?parseInt(m.replace(/^.*[a-zA-Z]+(.*)$/, 47 | "$1"),10):0}}else if(typeof u.ActiveXObject!=p)try{var q=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");if(q)if(m=q.GetVariable("$version")){i=true;m=m.split(" ")[1].split(",");n=[parseInt(m[0],10),parseInt(m[1],10),parseInt(m[2],10)]}}catch(r){}return{w3:a,pv:n,wk:d,ie:i,win:h,mac:f}}();(function(){if(j.w3){if(typeof l.readyState!=p&&l.readyState=="complete"||typeof l.readyState==p&&(l.getElementsByTagName("body")[0]||l.body))c();if(!D){typeof l.addEventListener!=p&&l.addEventListener("DOMContentLoaded", 48 | c,false);if(j.ie&&j.win){l.attachEvent("onreadystatechange",function(){if(l.readyState=="complete"){l.detachEvent("onreadystatechange",arguments.callee);c()}});u==top&&function(){if(!D){try{l.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,0);return}c()}}()}j.wk&&function(){D||(/loaded|complete/.test(l.readyState)?c():setTimeout(arguments.callee,0))}();b(c)}}})();(function(){j.ie&&j.win&&window.attachEvent("onunload",function(){for(var a=H.length,d=0;d0)for(var k=0;k0)for(var o=0;o1)for(var s= 56 | 0;s=0){FABridge.attachBridge(g[s],c);t=true;break}}if(t)break}if(!t&&b>1)for(g=0;g=0){FABridge.attachBridge(e[g],c);break}}return true}FABridge.nextBridgeID=0;FABridge.instances={};FABridge.idMap={};FABridge.refCount=0; 57 | FABridge.extractBridgeFromID=function(c){return FABridge.idMap[c>>16]};FABridge.attachBridge=function(c,e){var b=new FABridge(c,e);FABridge[e]=b;var g=FABridge.initCallbacks[e];if(g!=null){for(var k=0;k0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); 59 | else{FABridge.refCount++;retVal=this.target.getPropFromAS(c,e);retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},setPropertyInAS:function(c,e,b){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");else{FABridge.refCount++;retVal=this.target.setPropInAS(c,e,this.serialize(b));retVal=this.handleError(retVal);FABridge.refCount--;return retVal}}, 60 | callASFunction:function(c,e){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");else{FABridge.refCount++;retVal=this.target.invokeASFunction(c,this.serialize(e));retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},callASMethod:function(c,e,b){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); 61 | else{FABridge.refCount++;b=this.serialize(b);retVal=this.target.invokeASMethod(c,e,b);retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},invokeLocalFunction:function(c,e){var b,g=this.localFunctionCache[c];if(g!=undefined)b=this.serialize(g.apply(null,this.deserialize(e)));return b},getTypeFromName:function(c){return this.remoteTypeCache[c]},createProxy:function(c,e){var b=this.getTypeFromName(e);instanceFactory.prototype=b;b=new instanceFactory(c);return this.remoteInstanceCache[c]= 62 | b},getProxy:function(c){return this.remoteInstanceCache[c]},addTypeDataToCache:function(c){for(var e=new ASProxy(this,c.name),b=c.accessors,g=0;g="a"&&b<="z"){g="get"+b.toUpperCase()+e.substr(1);b="set"+b.toUpperCase()+e.substr(1)}else{g="get"+e;b="set"+ 63 | e}c[b]=function(k){this.bridge.setPropertyInAS(this.fb_instance_id,e,k)};c[g]=function(){return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id,e))}},addMethodToType:function(c,e){c[e]=function(){return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id,e,FABridge.argsToArray(arguments)))}},getFunctionProxy:function(c){var e=this;if(this.remoteFunctionCache[c]==null)this.remoteFunctionCache[c]=function(){e.callASFunction(c,FABridge.argsToArray(arguments))}; 64 | return this.remoteFunctionCache[c]},getFunctionID:function(c){if(c.__bridge_id__==undefined){c.__bridge_id__=this.makeID(this.nextLocalFuncID++);this.localFunctionCache[c.__bridge_id__]=c}return c.__bridge_id__},serialize:function(c){var e={},b=typeof c;if(b=="number"||b=="string"||b=="boolean"||b==null||b==undefined)e=c;else if(c instanceof Array){e=[];for(b=0;b0&&FABridge.refCount--;throw Error(c[1]);}return c}}; 67 | ASProxy=function(c,e){this.bridge=c;this.typeName=e;return this};ASProxy.prototype={get:function(c){return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id,c))},set:function(c,e){this.bridge.setPropertyInAS(this.fb_instance_id,c,e)},call:function(c,e){this.bridge.callASMethod(this.fb_instance_id,c,e)},addRef:function(){this.bridge.addRef(this)},release:function(){this.bridge.release(this)}}; 68 | (function(){function c(){}if(!window.WebSocket){var e=window.console;if(!e||!e.log||!e.error)e={log:function(){},error:function(){}};if(swfobject.hasFlashPlayerVersion("9.0.0")){location.protocol=="file:"&&e.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://...");WebSocket=function(b,g,k,o,t){var s=this;s.readyState=WebSocket.CONNECTING;s.bufferedAmount=0;setTimeout(function(){WebSocket.__addTask(function(){s.__createFlash(b, 69 | g,k,o,t)})},0)};WebSocket.prototype.__createFlash=function(b,g,k,o,t){var s=this;s.__flash=WebSocket.__flash.create(b,g,k||null,o||0,t||null);s.__flash.addEventListener("event",function(){setTimeout(function(){s.__handleEvents()},0)})};WebSocket.prototype.send=function(b){if(!this.__flash||this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";b=this.__flash.send(encodeURIComponent(b));if(b<0)return true;else{this.bufferedAmount+=b;return false}}; 70 | WebSocket.prototype.close=function(){if(this.__flash)if(!(this.readyState==WebSocket.CLOSED||this.readyState==WebSocket.CLOSING)){this.__flash.close();this.readyState=WebSocket.CLOSED;this.__timer&&clearInterval(this.__timer);this.onclose&&setTimeout(this.onclose,0)}};WebSocket.prototype.addEventListener=function(b,g){if(!("__events"in this))this.__events={};if(!(b in this.__events)){this.__events[b]=[];if("function"==typeof this["on"+b]){this.__events[b].defaultHandler=this["on"+b];this["on"+b]= 71 | this.__createEventHandler(this,b)}}this.__events[b].push(g)};WebSocket.prototype.removeEventListener=function(b,g){if(!("__events"in this))this.__events={};if(b in this.__events)for(var k=this.__events.length;k>-1;--k)if(g===this.__events[b][k]){this.__events[b].splice(k,1);break}};WebSocket.prototype.dispatchEvent=function(b){if(!("__events"in this))throw"UNSPECIFIED_EVENT_TYPE_ERR";if(!(b.type in this.__events))throw"UNSPECIFIED_EVENT_TYPE_ERR";for(var g=0,k=this.__events[b.type].length;g 6 | * @licence The MIT licence. 7 | * @source http://github.com/socky/socky-js 8 | * 9 | * This library contains code with the following licences: 10 | * 11 | * web_socket.js: 12 | * 13 | * Copyright: Hiroshi Ichikawa 14 | * License: New BSD License 15 | * Reference: http://dev.w3.org/html5/websockets/ 16 | * Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol 17 | * 18 | * swfobject.js: 19 | * 20 | * SWFObject v2.2 21 | * is released under the MIT License 22 | * 23 | * FABridge.js: 24 | * 25 | * Copyright 2006 Adobe Systems Incorporated 26 | * 27 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 28 | * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 29 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 30 | * 31 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 32 | */ 33 | 34 | var swfobject=function(){function c(){if(!D){try{var a=l.getElementsByTagName("body")[0].appendChild(l.createElement("span"));a.parentNode.removeChild(a)}catch(d){return}D=true;a=K.length;for(var f=0;f0)for(var d= 36 | 0;d0){var n=v(f);if(n)if(M(z[d].swfVersion)&&!(j.wk&&j.wk<312)){E(f,true);if(h){i.success=true;i.ref=o(f);h(i)}}else if(z[d].expressInstall&&t()){i={};i.data=z[d].expressInstall;i.width=n.getAttribute("width")||"0";i.height=n.getAttribute("height")||"0";if(n.getAttribute("class"))i.styleclass=n.getAttribute("class");if(n.getAttribute("align"))i.align=n.getAttribute("align");var m={};n=n.getElementsByTagName("param");for(var q= 37 | n.length,r=0;r';i.outerHTML='"+m+"";P[P.length]=a.id;h=v(a.id)}else{q=l.createElement(w);q.setAttribute("type",L);for(var r in a)if(a[r]!=Object.prototype[r])if(r.toLowerCase()=="styleclass")q.setAttribute("class", 42 | a[r]);else r.toLowerCase()!="classid"&&q.setAttribute(r,a[r]);for(n in d)if(d[n]!=Object.prototype[n]&&n.toLowerCase()!="movie"){a=q;m=n;r=d[n];f=l.createElement("param");f.setAttribute("name",m);f.setAttribute("value",r);a.appendChild(f)}i.parentNode.replaceChild(q,i);h=q}}return h}function X(a){var d=v(a);if(d&&d.nodeName=="OBJECT")if(j.ie&&j.win){d.style.display="none";(function(){if(d.readyState==4){var f=v(a);if(f){for(var h in f)if(typeof f[h]=="function")f[h]=null;f.parentNode.removeChild(f)}}else setTimeout(arguments.callee, 43 | 10)})()}else d.parentNode.removeChild(d)}function v(a){var d=null;try{d=l.getElementById(a)}catch(f){}return d}function ba(a,d,f){a.attachEvent(d,f);H[H.length]=[a,d,f]}function M(a){var d=j.pv;a=a.split(".");a[0]=parseInt(a[0],10);a[1]=parseInt(a[1],10)||0;a[2]=parseInt(a[2],10)||0;return d[0]>a[0]||d[0]==a[0]&&d[1]>a[1]||d[0]==a[0]&&d[1]==a[1]&&d[2]>=a[2]?true:false}function Y(a,d,f,h){if(!(j.ie&&j.mac)){var i=l.getElementsByTagName("head")[0];if(i){f=f&&typeof f=="string"?f:"screen";if(h)U=x=null; 44 | if(!x||U!=f){h=l.createElement("style");h.setAttribute("type","text/css");h.setAttribute("media",f);x=i.appendChild(h);if(j.ie&&j.win&&typeof l.styleSheets!=p&&l.styleSheets.length>0)x=l.styleSheets[l.styleSheets.length-1];U=f}if(j.ie&&j.win)x&&typeof x.addRule==w&&x.addRule(a,d);else x&&typeof l.createTextNode!=p&&x.appendChild(l.createTextNode(a+" {"+d+"}"))}}}function E(a,d){if(Z){var f=d?"visible":"hidden";if(D&&v(a))v(a).style.visibility=f;else Y("#"+a,"visibility:"+f)}}function $(a){return/[\\\"<>\.;]/.exec(a)!= 45 | null&&typeof encodeURIComponent!=p?encodeURIComponent(a):a}var p="undefined",w="object",L="application/x-shockwave-flash",W="SWFObjectExprInst",u=window,l=document,B=navigator,aa=false,K=[function(){aa?g():k()}],z=[],P=[],H=[],I,O,T,V,D=false,N=false,x,U,Z=true,j=function(){var a=typeof l.getElementById!=p&&typeof l.getElementsByTagName!=p&&typeof l.createElement!=p,d=B.userAgent.toLowerCase(),f=B.platform.toLowerCase(),h=f?/win/.test(f):/win/.test(d);f=f?/mac/.test(f):/mac/.test(d);d=/webkit/.test(d)? 46 | parseFloat(d.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false;var i=!+"\u000b1",n=[0,0,0],m=null;if(typeof B.plugins!=p&&typeof B.plugins["Shockwave Flash"]==w){if((m=B.plugins["Shockwave Flash"].description)&&!(typeof B.mimeTypes!=p&&B.mimeTypes[L]&&!B.mimeTypes[L].enabledPlugin)){aa=true;i=false;m=m.replace(/^.*\s+(\S+\s+\S+$)/,"$1");n[0]=parseInt(m.replace(/^(.*)\..*$/,"$1"),10);n[1]=parseInt(m.replace(/^.*\.(.*)\s.*$/,"$1"),10);n[2]=/[a-zA-Z]/.test(m)?parseInt(m.replace(/^.*[a-zA-Z]+(.*)$/, 47 | "$1"),10):0}}else if(typeof u.ActiveXObject!=p)try{var q=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");if(q)if(m=q.GetVariable("$version")){i=true;m=m.split(" ")[1].split(",");n=[parseInt(m[0],10),parseInt(m[1],10),parseInt(m[2],10)]}}catch(r){}return{w3:a,pv:n,wk:d,ie:i,win:h,mac:f}}();(function(){if(j.w3){if(typeof l.readyState!=p&&l.readyState=="complete"||typeof l.readyState==p&&(l.getElementsByTagName("body")[0]||l.body))c();if(!D){typeof l.addEventListener!=p&&l.addEventListener("DOMContentLoaded", 48 | c,false);if(j.ie&&j.win){l.attachEvent("onreadystatechange",function(){if(l.readyState=="complete"){l.detachEvent("onreadystatechange",arguments.callee);c()}});u==top&&function(){if(!D){try{l.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,0);return}c()}}()}j.wk&&function(){D||(/loaded|complete/.test(l.readyState)?c():setTimeout(arguments.callee,0))}();b(c)}}})();(function(){j.ie&&j.win&&window.attachEvent("onunload",function(){for(var a=H.length,d=0;d0)for(var k=0;k0)for(var o=0;o1)for(var s= 56 | 0;s=0){FABridge.attachBridge(g[s],c);t=true;break}}if(t)break}if(!t&&b>1)for(g=0;g=0){FABridge.attachBridge(e[g],c);break}}return true}FABridge.nextBridgeID=0;FABridge.instances={};FABridge.idMap={};FABridge.refCount=0; 57 | FABridge.extractBridgeFromID=function(c){return FABridge.idMap[c>>16]};FABridge.attachBridge=function(c,e){var b=new FABridge(c,e);FABridge[e]=b;var g=FABridge.initCallbacks[e];if(g!=null){for(var k=0;k0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); 59 | else{FABridge.refCount++;retVal=this.target.getPropFromAS(c,e);retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},setPropertyInAS:function(c,e,b){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");else{FABridge.refCount++;retVal=this.target.setPropInAS(c,e,this.serialize(b));retVal=this.handleError(retVal);FABridge.refCount--;return retVal}}, 60 | callASFunction:function(c,e){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");else{FABridge.refCount++;retVal=this.target.invokeASFunction(c,this.serialize(e));retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},callASMethod:function(c,e,b){if(FABridge.refCount>0)throw Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); 61 | else{FABridge.refCount++;b=this.serialize(b);retVal=this.target.invokeASMethod(c,e,b);retVal=this.handleError(retVal);FABridge.refCount--;return retVal}},invokeLocalFunction:function(c,e){var b,g=this.localFunctionCache[c];if(g!=undefined)b=this.serialize(g.apply(null,this.deserialize(e)));return b},getTypeFromName:function(c){return this.remoteTypeCache[c]},createProxy:function(c,e){var b=this.getTypeFromName(e);instanceFactory.prototype=b;b=new instanceFactory(c);return this.remoteInstanceCache[c]= 62 | b},getProxy:function(c){return this.remoteInstanceCache[c]},addTypeDataToCache:function(c){for(var e=new ASProxy(this,c.name),b=c.accessors,g=0;g="a"&&b<="z"){g="get"+b.toUpperCase()+e.substr(1);b="set"+b.toUpperCase()+e.substr(1)}else{g="get"+e;b="set"+ 63 | e}c[b]=function(k){this.bridge.setPropertyInAS(this.fb_instance_id,e,k)};c[g]=function(){return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id,e))}},addMethodToType:function(c,e){c[e]=function(){return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id,e,FABridge.argsToArray(arguments)))}},getFunctionProxy:function(c){var e=this;if(this.remoteFunctionCache[c]==null)this.remoteFunctionCache[c]=function(){e.callASFunction(c,FABridge.argsToArray(arguments))}; 64 | return this.remoteFunctionCache[c]},getFunctionID:function(c){if(c.__bridge_id__==undefined){c.__bridge_id__=this.makeID(this.nextLocalFuncID++);this.localFunctionCache[c.__bridge_id__]=c}return c.__bridge_id__},serialize:function(c){var e={},b=typeof c;if(b=="number"||b=="string"||b=="boolean"||b==null||b==undefined)e=c;else if(c instanceof Array){e=[];for(b=0;b0&&FABridge.refCount--;throw Error(c[1]);}return c}}; 67 | ASProxy=function(c,e){this.bridge=c;this.typeName=e;return this};ASProxy.prototype={get:function(c){return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id,c))},set:function(c,e){this.bridge.setPropertyInAS(this.fb_instance_id,c,e)},call:function(c,e){this.bridge.callASMethod(this.fb_instance_id,c,e)},addRef:function(){this.bridge.addRef(this)},release:function(){this.bridge.release(this)}}; 68 | (function(){function c(){}if(!window.WebSocket){var e=window.console;if(!e||!e.log||!e.error)e={log:function(){},error:function(){}};if(swfobject.hasFlashPlayerVersion("9.0.0")){location.protocol=="file:"&&e.error("WARNING: web-socket-js doesn't work in file:///... URL unless you set Flash Security Settings properly. Open the page via Web server i.e. http://...");WebSocket=function(b,g,k,o,t){var s=this;s.readyState=WebSocket.CONNECTING;s.bufferedAmount=0;setTimeout(function(){WebSocket.__addTask(function(){s.__createFlash(b, 69 | g,k,o,t)})},0)};WebSocket.prototype.__createFlash=function(b,g,k,o,t){var s=this;s.__flash=WebSocket.__flash.create(b,g,k||null,o||0,t||null);s.__flash.addEventListener("event",function(){setTimeout(function(){s.__handleEvents()},0)})};WebSocket.prototype.send=function(b){if(!this.__flash||this.readyState==WebSocket.CONNECTING)throw"INVALID_STATE_ERR: Web Socket connection has not been established";b=this.__flash.send(encodeURIComponent(b));if(b<0)return true;else{this.bufferedAmount+=b;return false}}; 70 | WebSocket.prototype.close=function(){if(this.__flash)if(!(this.readyState==WebSocket.CLOSED||this.readyState==WebSocket.CLOSING)){this.__flash.close();this.readyState=WebSocket.CLOSED;this.__timer&&clearInterval(this.__timer);this.onclose&&setTimeout(this.onclose,0)}};WebSocket.prototype.addEventListener=function(b,g){if(!("__events"in this))this.__events={};if(!(b in this.__events)){this.__events[b]=[];if("function"==typeof this["on"+b]){this.__events[b].defaultHandler=this["on"+b];this["on"+b]= 71 | this.__createEventHandler(this,b)}}this.__events[b].push(g)};WebSocket.prototype.removeEventListener=function(b,g){if(!("__events"in this))this.__events={};if(b in this.__events)for(var k=this.__events.length;k>-1;--k)if(g===this.__events[b][k]){this.__events[b].splice(k,1);break}};WebSocket.prototype.dispatchEvent=function(b){if(!("__events"in this))throw"UNSPECIFIED_EVENT_TYPE_ERR";if(!(b.type in this.__events))throw"UNSPECIFIED_EVENT_TYPE_ERR";for(var g=0,k=this.__events[b.type].length;g