antimony

drive firefox from node.js
git clone https://wehaveforgeathome.hates.computer/antimony.git
Log | Files | Refs | Submodules | LICENSE

commit f814d0ce84ec21dcd9ed995cbc487f4bf5764f98
Author: Ryan Wolf <rwolf@borderstylo.com>
Date:   Thu,  9 Dec 2010 15:32:18 -0800

need to hack socket.io

Diffstat:
Aaddon/LICENSE | 19+++++++++++++++++++
Aaddon/Makefile | 11+++++++++++
Aaddon/README.md | 29+++++++++++++++++++++++++++++
Aaddon/antimony.xpi | 0
Aaddon/chrome.manifest | 6++++++
Aaddon/chrome/content/about.xul | 17+++++++++++++++++
Aaddon/chrome/content/browser.xul | 15+++++++++++++++
Aaddon/chrome/content/content.js | 13+++++++++++++
Aaddon/chrome/content/socket.io.js | 2155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aaddon/chrome/modules/module.js | 7+++++++
Aaddon/chrome/skin/images/.gitignore | 0
Aaddon/chrome/skin/stylesheets/stylesheet.css | 0
Aaddon/defaults/preferences/.gitignore | 0
Aaddon/install.rdf | 21+++++++++++++++++++++
Aaddon/locale/en-US/stringbundle.dtd | 7+++++++
Atest.js | 21+++++++++++++++++++++
16 files changed, 2321 insertions(+), 0 deletions(-)

diff --git a/addon/LICENSE b/addon/LICENSE @@ -0,0 +1,19 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2009, 2010 Min Huang <min.huang@alumni.usc.edu> + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. diff --git a/addon/Makefile b/addon/Makefile @@ -0,0 +1,11 @@ +package : clean + zip -r antimony.xpi chrome/ defaults/ locale/ chrome.manifest install.rdf + +clone : clean + cp -R . ${DIR}/${NAME} && \ + find ${DIR}/${NAME}/ -not -regex '^\./\.git/.*' -type f | \ + xargs sed -i 's/antimony/${NAME}/g' + +clean : + rm -f antimony.xpi + diff --git a/addon/README.md b/addon/README.md @@ -0,0 +1,29 @@ +antimony - a Barebones Extension For Firefox, Ya'll +============ + +A basic Firefox extension with a menu item, for copying and pasting into new projects. + +For Development +============ + +Like they say in the [good book](https://developer.mozilla.org/en/Setting_up_extension_development_environment#Firefox_extension_proxy_file), navigate to: + + ~/.mozilla/firefox/$PROFILE_NAME/extensions + +...and create a file named: + + antimony@thebigbad.github.com + +Inside that file, write the path of this project (making sure it ends in slash). + +For Sharing +=========== + + make + +... and open antimony.xpi in Firefox + +Credit +=========== + +* it's all [retiman](http://github.com/retiman) and his wonderful [browser science](http://github.com/retiman/browser-science) diff --git a/addon/antimony.xpi b/addon/antimony.xpi Binary files differ. diff --git a/addon/chrome.manifest b/addon/chrome.manifest @@ -0,0 +1,6 @@ +content antimony chrome/content/ +content antimony chrome/content/ contentaccessible=yes +locale antimony en-US locale/en-US/ +skin antimony classic/1.0 chrome/skin/ +resource antimony chrome/modules/ +overlay chrome://browser/content/browser.xul chrome://antimony/content/browser.xul diff --git a/addon/chrome/content/about.xul b/addon/chrome/content/about.xul @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<!DOCTYPE overlay SYSTEM "chrome://antimony/locale/stringbundle.dtd"> +<window class="dialog" title="&antimony.about;" orient="vertical" + onload="sizeToContent();" autostretch="always" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <groupbox align="center" orient="horizontal"> + <vbox style="font-weight: bold; font-size: x-large;"> + <text value="&antimony.about;" /> + </vbox> + <spring flex="1"/> + </groupbox> + <hbox> + <spacer flex="1"/> + <button label="&antimony.about.close;" oncommand="window.close();"/> + </hbox> +</window> diff --git a/addon/chrome/content/browser.xul b/addon/chrome/content/browser.xul @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet type="text/css" + href="chrome://antimony/skin/stylesheets/stylesheet.css" ?> +<!DOCTYPE overlay SYSTEM "chrome://antimony/locale/stringbundle.dtd"> +<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="text/javascript" src="chrome://antimony/content/socket.io.js" /> + <script type="text/javascript" src="chrome://antimony/content/content.js" /> + <menubar id="main-menubar"> + <menu label="&antimony.menu.title;" insertbefore="tools-menu"> + <menupopup> + <menuitem label="&antimony.menu.item;" oncommand="alert('Hello World!');"/> + </menupopup> + </menu> + </menubar> +</overlay> diff --git a/addon/chrome/content/content.js b/addon/chrome/content/content.js @@ -0,0 +1,13 @@ +var socket = new io.Socket( + 'http://localhost:1234/', + { rememberTransport: false } +); +socket.on('connect', function () { + alert('connect'); +}); +socket.on('message', function () { + alert('message'); +}); +socket.on('disconnect', function () { + alert('disconnect'); +}); diff --git a/addon/chrome/content/socket.io.js b/addon/chrome/content/socket.io.js @@ -0,0 +1,2155 @@ +/** Socket.IO 0.7pre - Built with build.js */ +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +this.io = { + version: '0.7pre', + + setPath: function(path){ + if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf'); + this.path = /\/$/.test(path) ? path : path + '/'; + WEB_SOCKET_SWF_LOCATION = path + 'lib/vendor/web-socket-js/WebSocketMain.swf'; + } +}; + +if ('jQuery' in this) jQuery.io = this.io; + +if (typeof window != 'undefined'){ + // WEB_SOCKET_SWF_LOCATION = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//cdn.socket.io/' + this.io.version + '/WebSocketMain.swf'; + WEB_SOCKET_SWF_LOCATION = '/socket.io/lib/vendor/web-socket-js/WebSocketMain.swf'; +} + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var _pageLoaded = false; + + io.util = { + + ios: false, + + load: function(fn){ + if (document.readyState == 'complete' || _pageLoaded) return fn(); + if ('attachEvent' in window){ + window.attachEvent('onload', fn); + } else { + window.addEventListener('load', fn, false); + } + }, + + inherit: function(ctor, superCtor){ + // no support for `instanceof` for now + for (var i in superCtor.prototype){ + ctor.prototype[i] = superCtor.prototype[i]; + } + }, + + indexOf: function(arr, item, from){ + for (var l = arr.length, i = (from < 0) ? Math.max(0, l + from) : from || 0; i < l; i++){ + if (arr[i] === item) return i; + } + return -1; + }, + + isArray: function(obj){ + return Object.prototype.toString.call(obj) === '[object Array]'; + }, + + merge: function(target, additional){ + for (var i in additional) + if (additional.hasOwnProperty(i)) + target[i] = additional[i]; + } + + }; + + io.util.ios = /iphone|ipad/i.test(navigator.userAgent); + io.util.android = /android/i.test(navigator.userAgent); + io.util.opera = /opera/i.test(navigator.userAgent); + + io.util.load(function(){ + _pageLoaded = true; + }); + +})(); +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +io.data = {}; + +/** + * Data decoder class + * + * @api public + */ + +io.data.Decoder = function(){ + this.reset(); + this.buffer = ''; + this.events = {}; +}; + +io.data.Decoder.prototype = { + + /** + * Add data to the buffer for parsing + * + * @param {String} data + * @api public + */ + add: function(data){ + this.buffer += data; + this.parse(); + }, + + /** + * Parse the current buffer + * + * @api private + */ + parse: function(){ + for (var l = this.buffer.length; this.i < l; this.i++){ + var chr = this.buffer[this.i]; + if (this.type === undefined){ + if (chr == ':') return this.error('Data type not specified'); + this.type = '' + chr; + continue; + } + if (this.length === undefined && chr == ':'){ + this.length = ''; + continue; + } + if (this.data === undefined){ + if (chr != ':'){ + this.length += chr; + } else { + if (this.length.length === 0) + return this.error('Data length not specified'); + this.length = Number(this.length); + this.data = ''; + } + continue; + } + if (this.data.length === this.length){ + if (chr == ','){ + this.emit('data', this.type, this.data); + this.buffer = this.buffer.substr(this.i + 1); + this.reset(); + return this.parse(); + } else { + return this.error('Termination character "," expected'); + } + } else { + this.data += chr; + } + } + }, + + /** + * Reset the parser state + * + * @api private + */ + + reset: function(){ + this.i = 0; + this.type = this.data = this.length = undefined; + }, + + /** + * Error handling functions + * + * @param {String} reason to report + * @api private + */ + + error: function(reason){ + this.reset(); + this.emit('error', reason); + }, + + /** + * Emits an event + * + * @param {String} ev name + * @api public + */ + + emit: function(ev){ + if (!(ev in this.events)) + return this; + for (var i = 0, l = this.events[ev].length; i < l; i++) + if (this.events[ev][i]) + this.events[ev][i].apply(this, Array.prototype.slice.call(arguments).slice(1)); + return this; + }, + + /** + * Adds an event listener + * + * @param {String} ev name + * @param {Function} callback + * @api public + */ + + on: function(ev, fn){ + if (!(ev in this.events)) + this.events[ev] = []; + this.events[ev].push(fn); + return this; + }, + + /** + * Removes an event listener + * + * @param {String} ev name + * @param {Function} callback + * @api public + */ + + removeListener: function(ev, fn){ + if (!(ev in this.events)) + return this; + for (var i = 0, l = this.events[ev].length; i < l; i++) + if (this.events[ev][i] == fn) + this.events[ev].splice(i, 1); + return this; + } + +}; + +/** + * Encode function + * + * Examples: + * encode([3, 'Message of type 3']); + * encode([[1, 'Message of type 1], [2, 'Message of type 2]]); + * + * @param {Array} list of messages + * @api public + */ + +io.data.encode = function(messages){ + messages = io.util.isArray(messages[0]) ? messages : [messages]; + var ret = ''; + for (var i = 0, str; i < messages.length; i++){ + str = String(messages[i][1]); + if (str === undefined || str === null) str = ''; + ret += messages[i][0] + ':' + str.length + ':' + str + ','; + } + return ret; +}; + +/** + * Encode message function + * + * @param {String} message + * @param {Object} annotations + * @api public + */ + +io.data.encodeMessage = function(msg, annotations){ + var data = '' + , anns = annotations || {}; + for (var k in anns){ + v = anns[k]; + data += k + (v !== null && v !== undefined ? ':' + v : '') + "\n"; + } + data += ':' + (msg === undefined || msg === null ? '' : msg); + return data; +}; + +/** + * Decode message function + * + * @param {String} message + * @api public + */ + +io.data.decodeMessage = function(msg){ + var anns = {} + , data; + for (var i = 0, chr, key, value, l = msg.length; i < l; i++){ + chr = msg[i]; + if (i === 0 && chr === ':'){ + data = msg.substr(1); + break; + } + if (key == null && value == null && chr == ':'){ + data = msg.substr(i + 1); + break; + } + if (chr === "\n"){ + anns[key] = value; + key = value = undefined; + continue; + } + if (key === undefined){ + key = chr; + continue; + } + if (value === undefined && chr == ':'){ + value = ''; + continue; + } + if (value !== undefined) + value += chr; + else + key += chr; + } + return [data, anns]; +}; + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +// abstract + +(function(){ + + Transport = io.Transport = function(base, options){ + var self = this; + this.base = base; + this.options = { + timeout: 15000 // based on heartbeat interval default + }; + io.util.merge(this.options, options); + this._decoder = new io.data.Decoder(); + this._decoder.on('data', function(type, message){ + self._onMessage(type, message); + }); + }; + + Transport.prototype.write = function(){ + throw new Error('Missing write() implementation'); + }; + + Transport.prototype.connect = function(){ + throw new Error('Missing connect() implementation'); + }; + + Transport.prototype.disconnect = function(){ + throw new Error('Missing disconnect() implementation'); + }; + + Transport.prototype._onData = function(data){ + this._setTimeout(); + this._decoder.add(data); + }; + + Transport.prototype._setTimeout = function(){ + var self = this; + if (this._timeout) clearTimeout(this._timeout); + this._timeout = setTimeout(function(){ + self._onTimeout(); + }, this.options.timeout); + }; + + Transport.prototype._onTimeout = function(){ + this._onDisconnect(); + }; + + Transport.prototype._onMessage = function(type, message){ + switch (type){ + case '0': + this.disconnect(); + break; + + case '1': + var msg = io.data.decodeMessage(message); + // handle json decoding + if ('j' in msg[1]){ + if (!window.JSON || !JSON.parse) + alert('`JSON.parse` is not available, but Socket.IO is trying to parse' + + 'JSON. Please include json2.js in your <head>'); + msg[0] = JSON.parse(msg[0]); + } + this.base._onMessage(msg[0], msg[1]); + break; + + case '2': + this._onHeartbeat(message); + break; + + case '3': + this.sessionid = message; + this._onConnect(); + break; + } + }, + + Transport.prototype._onHeartbeat = function(heartbeat){ + this.write('2', heartbeat); // echo + }; + + Transport.prototype._onConnect = function(){ + this.connected = true; + this.connecting = false; + this.base._onConnect(); + this._setTimeout(); + }; + + Transport.prototype._onDisconnect = function(){ + this.connecting = false; + this.connected = false; + this.sessionid = null; + this.base._onDisconnect(); + }; + + Transport.prototype._prepareUrl = function(){ + return (this.base.options.secure ? 'https' : 'http') + + '://' + this.base.host + + ':' + this.base.options.port + + '/' + this.base.options.resource + + '/' + this.type + + (this.sessionid ? ('/' + this.sessionid) : '/'); + }; + +})(); + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var empty = new Function, + + XMLHttpRequestCORS = (function(){ + if (!('XMLHttpRequest' in window)) return false; + // CORS feature detection + var a = new XMLHttpRequest(); + return a.withCredentials != undefined; + })(), + + request = function(xdomain){ + if ('XDomainRequest' in window && xdomain) return new XDomainRequest(); + if ('XMLHttpRequest' in window && (!xdomain || XMLHttpRequestCORS)) return new XMLHttpRequest(); + if (!xdomain){ + try { + var a = new ActiveXObject('MSXML2.XMLHTTP'); + return a; + } catch(e){} + + try { + var b = new ActiveXObject('Microsoft.XMLHTTP'); + return b; + } catch(e){} + } + return false; + }, + + XHR = io.Transport.XHR = function(){ + io.Transport.apply(this, arguments); + this._sendBuffer = []; + }; + + io.util.inherit(XHR, io.Transport); + + XHR.prototype.connect = function(){ + this._get(); + return this; + }; + + XHR.prototype._checkSend = function(){ + if (!this._posting && this._sendBuffer.length){ + var encoded = io.data.encode(this._sendBuffer); + this._sendBuffer = []; + this._send(encoded); + } + }; + + XHR.prototype.write = function(type, data){ + if (io.util.isArray(type)) + this._sendBuffer.push.apply(this._sendBuffer, type); + else + this._sendBuffer.push([type, data]); + this._checkSend(); + return this; + }; + + XHR.prototype._send = function(data){ + var self = this; + this._posting = true; + this._sendXhr = this._request('send', 'POST'); + this._sendXhr.onreadystatechange = function(){ + var status; + if (self._sendXhr.readyState == 4){ + self._sendXhr.onreadystatechange = empty; + try { status = self._sendXhr.status; } catch(e){} + self._posting = false; + if (status == 200){ + self._checkSend(); + } else { + self._onDisconnect(); + } + } + }; + this._sendXhr.send('data=' + encodeURIComponent(data)); + }; + + XHR.prototype.disconnect = function(){ + // send disconnection signal + this._onDisconnect(); + return this; + }; + + XHR.prototype._onDisconnect = function(){ + if (this._xhr){ + this._xhr.onreadystatechange = this._xhr.onload = empty; + this._xhr.abort(); + this._xhr = null; + } + if (this._sendXhr){ + this._sendXhr.onreadystatechange = this._sendXhr.onload = empty; + this._sendXhr.abort(); + this._sendXhr = null; + } + this._sendBuffer = []; + io.Transport.prototype._onDisconnect.call(this); + }; + + XHR.prototype._request = function(url, method, multipart){ + var req = request(this.base._isXDomain()); + if (multipart) req.multipart = true; + req.open(method || 'GET', this._prepareUrl() + (url ? '/' + url : '')); + if (method == 'POST' && 'setRequestHeader' in req){ + req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=utf-8'); + } + return req; + }; + + XHR.check = function(xdomain){ + try { + if (request(xdomain)) return true; + } catch(e){} + return false; + }; + + XHR.xdomainCheck = function(){ + return XHR.check(true); + }; + + XHR.request = request; + +})(); + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var WS = io.Transport.websocket = function(){ + io.Transport.apply(this, arguments); + }; + + io.util.inherit(WS, io.Transport); + + WS.prototype.type = 'websocket'; + + WS.prototype.connect = function(){ + var self = this; + this.socket = new WebSocket(this._prepareUrl()); + this.socket.onmessage = function(ev){ self._onData(ev.data); }; + this.socket.onclose = function(ev){ self._onClose(); }; + return this; + }; + + WS.prototype.write = function(type, data){ + if (this.socket) + this.socket.send(io.data.encode(io.util.isArray(type) ? type : [type, data])); + return this; + }; + + WS.prototype.disconnect = function(){ + if (this.socket) this.socket.close(); + this._onDisconnect(); + return this; + }; + + WS.prototype._onClose = function(){ + this._onDisconnect(); + return this; + }; + + WS.prototype._prepareUrl = function(){ + return (this.base.options.secure ? 'wss' : 'ws') + + '://' + this.base.host + + ':' + this.base.options.port + + '/' + this.base.options.resource + + '/' + this.type + + (this.sessionid ? ('/' + this.sessionid) : ''); + }; + + WS.check = function(){ + // we make sure WebSocket is not confounded with a previously loaded flash WebSocket + return 'WebSocket' in window && WebSocket.prototype && ( WebSocket.prototype.send && !!WebSocket.prototype.send.toString().match(/native/i)) && typeof WebSocket !== "undefined"; + }; + + WS.xdomainCheck = function(){ + return true; + }; + +})(); + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var Flashsocket = io.Transport.flashsocket = function(){ + io.Transport.websocket.apply(this, arguments); + }; + + io.util.inherit(Flashsocket, io.Transport.websocket); + + Flashsocket.prototype.type = 'flashsocket'; + + Flashsocket.prototype.connect = function(){ + var self = this, args = arguments; + WebSocket.__addTask(function(){ + io.Transport.websocket.prototype.connect.apply(self, args); + }); + return this; + }; + + Flashsocket.prototype.send = function(){ + var self = this, args = arguments; + WebSocket.__addTask(function(){ + io.Transport.websocket.prototype.send.apply(self, args); + }); + return this; + }; + + Flashsocket.check = function(){ + if (typeof WebSocket == 'undefined' || !('__addTask' in WebSocket)) return false; + if (io.util.opera) return false; // opera is buggy with this transport + if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']){ + return !!navigator.plugins['Shockwave Flash'].description; + } + if ('ActiveXObject' in window) { + try { + return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + } catch (e) {} + } + return false; + }; + + Flashsocket.xdomainCheck = function(){ + return true; + }; + +})(); +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var HTMLFile = io.Transport.htmlfile = function(){ + io.Transport.XHR.apply(this, arguments); + }; + + io.util.inherit(HTMLFile, io.Transport.XHR); + + HTMLFile.prototype.type = 'htmlfile'; + + HTMLFile.prototype._get = function(){ + var self = this; + this._open(); + window.attachEvent('onunload', function(){ self._destroy(); }); + }; + + HTMLFile.prototype._open = function(){ + this._doc = new ActiveXObject('htmlfile'); + this._doc.open(); + this._doc.write('<html></html>'); + this._doc.parentWindow.s = this; + this._doc.close(); + + var _iframeC = this._doc.createElement('div'); + this._doc.body.appendChild(_iframeC); + this._iframe = this._doc.createElement('iframe'); + _iframeC.appendChild(this._iframe); + this._iframe.src = this._prepareUrl() + '/' + (+ new Date); + }; + + HTMLFile.prototype._ = function(data, doc){ + this._onData(data); + var script = doc.getElementsByTagName('script')[0]; + script.parentNode.removeChild(script); + }; + + HTMLFile.prototype._destroy = function(){ + if (this._iframe){ + this._iframe.src = 'about:blank'; + this._doc = null; + CollectGarbage(); + } + }; + + HTMLFile.prototype.disconnect = function(){ + this._destroy(); + return io.Transport.XHR.prototype.disconnect.call(this); + }; + + HTMLFile.check = function(){ + if ('ActiveXObject' in window){ + try { + var a = new ActiveXObject('htmlfile'); + return a && io.Transport.XHR.check(); + } catch(e){} + } + return false; + }; + + HTMLFile.xdomainCheck = function(){ + // we can probably do handling for sub-domains, we should test that it's cross domain but a subdomain here + return false; + }; + +})(); +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var XHRMultipart = io.Transport['xhr-multipart'] = function(){ + io.Transport.XHR.apply(this, arguments); + }; + + io.util.inherit(XHRMultipart, io.Transport.XHR); + + XHRMultipart.prototype.type = 'xhr-multipart'; + + XHRMultipart.prototype._get = function(){ + var self = this; + this._xhr = this._request('', 'GET', true); + this._xhr.onreadystatechange = function(){ + if (self._xhr.readyState == 3) self._onData(self._xhr.responseText); + }; + this._xhr.send(); + }; + + XHRMultipart.check = function(){ + return 'XMLHttpRequest' in window && 'prototype' in XMLHttpRequest && 'multipart' in XMLHttpRequest.prototype; + }; + + XHRMultipart.xdomainCheck = function(){ + return true; + }; + +})(); +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var empty = new Function(), + + XHRPolling = io.Transport['xhr-polling'] = function(){ + io.Transport.XHR.apply(this, arguments); + }; + + io.util.inherit(XHRPolling, io.Transport.XHR); + + XHRPolling.prototype.type = 'xhr-polling'; + + XHRPolling.prototype.connect = function(){ + if (io.util.ios || io.util.android){ + var self = this; + io.util.load(function(){ + setTimeout(function(){ + io.Transport.XHR.prototype.connect.call(self); + }, 10); + }); + } else { + io.Transport.XHR.prototype.connect.call(this); + } + }; + + XHRPolling.prototype._get = function(){ + var self = this; + this._xhr = this._request(+ new Date, 'GET'); + if ('onload' in this._xhr){ + this._xhr.onload = function(){ + self._onData(this.responseText); + self._get(); + }; + } else { + this._xhr.onreadystatechange = function(){ + var status; + if (self._xhr.readyState == 4){ + self._xhr.onreadystatechange = empty; + try { status = self._xhr.status; } catch(e){} + if (status == 200){ + self._onData(self._xhr.responseText); + self._get(); + } else { + self._onDisconnect(); + } + } + }; + } + this._xhr.send(); + }; + + XHRPolling.check = function(){ + return io.Transport.XHR.check(); + }; + + XHRPolling.xdomainCheck = function(){ + return io.Transport.XHR.xdomainCheck(); + }; + +})(); +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +io.JSONP = []; + +JSONPPolling = io.Transport['jsonp-polling'] = function(){ + io.Transport.XHR.apply(this, arguments); + this._insertAt = document.getElementsByTagName('script')[0]; + this._index = io.JSONP.length; + io.JSONP.push(this); +}; + +io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); + +JSONPPolling.prototype.type = 'jsonp-polling'; + +JSONPPolling.prototype._send = function(data){ + var self = this; + if (!('_form' in this)){ + var form = document.createElement('FORM'), + area = document.createElement('TEXTAREA'), + id = this._iframeId = 'socket_io_iframe_' + this._index, + iframe; + + form.style.position = 'absolute'; + form.style.top = '-1000px'; + form.style.left = '-1000px'; + form.target = id; + form.method = 'POST'; + form.action = this._prepareUrl() + '/' + (+new Date) + '/' + this._index; + area.name = 'data'; + form.appendChild(area); + this._insertAt.parentNode.insertBefore(form, this._insertAt); + document.body.appendChild(form); + + this._form = form; + this._area = area; + } + + function complete(){ + initIframe(); + self._posting = false; + self._checkSend(); + }; + + function initIframe(){ + if (self._iframe){ + self._form.removeChild(self._iframe); + } + + try { + // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) + iframe = document.createElement('<iframe name="'+ self._iframeId +'">'); + } catch(e){ + iframe = document.createElement('iframe'); + iframe.name = self._iframeId; + } + + iframe.id = self._iframeId; + + self._form.appendChild(iframe); + self._iframe = iframe; + }; + + initIframe(); + + this._posting = true; + this._area.value = data; + + try { + this._form.submit(); + } catch(e){} + + if (this._iframe.attachEvent){ + iframe.onreadystatechange = function(){ + if (self._iframe.readyState == 'complete') complete(); + }; + } else { + this._iframe.onload = complete; + } +}; + +JSONPPolling.prototype._get = function(){ + var self = this, + script = document.createElement('SCRIPT'); + if (this._script){ + this._script.parentNode.removeChild(this._script); + this._script = null; + } + script.async = true; + script.src = this._prepareUrl() + '/' + (+new Date) + '/' + this._index; + script.onerror = function(){ + self._onDisconnect(); + }; + this._insertAt.parentNode.insertBefore(script, this._insertAt); + this._script = script; +}; + +JSONPPolling.prototype.disconnect = function(){ + if (this._script){ + this._script.parentNode.removeChild(this._script); + this._script = null; + } + io.Transport['xhr-polling'].prototype.disconnect.call(this); + return this; +}; + +JSONPPolling.prototype._ = function(){ + this._onData.apply(this, arguments); + this._get(); + return this; +}; + +JSONPPolling.check = function(){ + return true; +}; + +JSONPPolling.xdomainCheck = function(){ + return true; +}; + +/** + * Socket.IO client + * + * @author Guillermo Rauch <guillermo@learnboost.com> + * @license The MIT license. + * @copyright Copyright (c) 2010 LearnBoost <dev@learnboost.com> + */ + +(function(){ + + var Socket = io.Socket = function(host, options){ + this.host = host || document.domain; + this.options = { + secure: false, + document: document, + port: document.location.port || 80, + resource: 'socket.io', + transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'], + transportOptions: { + 'xhr-polling': { + timeout: 25000 // based on polling duration default + }, + 'jsonp-polling': { + timeout: 25000 + } + }, + connectTimeout: 5000, + tryTransportsOnConnectTimeout: true, + rememberTransport: true + }; + io.util.merge(this.options, options); + this.connected = false; + this.connecting = false; + this._events = {}; + this.transport = this.getTransport(); + if (!this.transport && 'console' in window) console.error('No transport available'); + }; + + Socket.prototype.getTransport = function(override){ + var transports = override || this.options.transports, match; + if (this.options.rememberTransport && !override){ + match = this.options.document.cookie.match('(?:^|;)\\s*socketio=([^;]*)'); + if (match){ + this._rememberedTransport = true; + transports = [decodeURIComponent(match[1])]; + } + } + for (var i = 0, transport; transport = transports[i]; i++){ + if (io.Transport[transport] + && io.Transport[transport].check() + && (!this._isXDomain() || io.Transport[transport].xdomainCheck())){ + return new io.Transport[transport](this, this.options.transportOptions[transport] || {}); + } + } + return null; + }; + + Socket.prototype.connect = function(){ + if (this.transport && !this.connected){ + if (this.connecting) this.disconnect(); + this.connecting = true; + this.transport.connect(); + if (this.options.connectTimeout){ + var self = this; + setTimeout(function(){ + if (!self.connected){ + self.disconnect(); + if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){ + var remainingTransports = [], transports = self.options.transports; + for (var i = 0, transport; transport = transports[i]; i++){ + if (transport != self.transport.type) remainingTransports.push(transport); + } + if (remainingTransports.length){ + self.transport = self.getTransport(remainingTransports); + self.connect(); + } + } + } + }, this.options.connectTimeout); + } + } + return this; + }; + + Socket.prototype.write = function(message, atts){ + if (!this.transport || !this.transport.connected) return this._queue(message, atts); + this.transport.write(message, atts); + return this; + }; + + Socket.prototype.send = function(message, atts){ + atts = atts || {}; + if (typeof message == 'object'){ + atts['j'] = null; + message = JSON.stringify(message); + } + this.write('1', io.data.encodeMessage(message, atts)); + return this; + }; + + Socket.prototype.json = function(obj, atts){ + atts = atts || {}; + atts['j'] = null + return this.send(JSON.stringify(obj), atts); + } + + Socket.prototype.disconnect = function(){ + this.transport.disconnect(); + return this; + }; + + Socket.prototype.on = function(name, fn){ + if (!(name in this._events)) this._events[name] = []; + this._events[name].push(fn); + return this; + }; + + Socket.prototype.emit = function(name, args){ + if (name in this._events){ + for (var i = 0, ii = this._events[name].length; i < ii; i++) + this._events[name][i].apply(this, args === undefined ? [] : args); + } + return this; + }; + + Socket.prototype.removeEvent = function(name, fn){ + if (name in this._events){ + for (var a = 0, l = this._events[name].length; a < l; a++) + if (this._events[name][a] == fn) this._events[name].splice(a, 1); + } + return this; + }; + + Socket.prototype._queue = function(message, atts){ + if (!('_queueStack' in this)) this._queueStack = []; + this._queueStack.push([message, atts]); + return this; + }; + + Socket.prototype._doQueue = function(){ + if (!('_queueStack' in this) || !this._queueStack.length) return this; + this.transport.write(this._queueStack); + this._queueStack = []; + return this; + }; + + Socket.prototype._isXDomain = function(){ + return this.host !== document.domain; + }; + + Socket.prototype._onConnect = function(){ + this.connected = true; + this.connecting = false; + this._doQueue(); + if (this.options.rememberTransport) this.options.document.cookie = 'socketio=' + encodeURIComponent(this.transport.type); + this.emit('connect'); + }; + + Socket.prototype._onMessage = function(data){ + this.emit('message', [data]); + }; + + Socket.prototype._onDisconnect = function(){ + var wasConnected = this.connected; + this.connected = false; + this.connecting = false; + this._queueStack = []; + if (wasConnected) this.emit('disconnect'); + }; + + Socket.prototype.addListener = Socket.prototype.addEvent = Socket.prototype.addEventListener = Socket.prototype.on; + + Socket.prototype.fire = Socket.prototype.emit; + +})(); + +/* SWFObject v2.2 <http://code.google.com/p/swfobject/> + is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> +*/ +var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}(); +/* +/* +Copyright 2006 Adobe Systems Incorporated + +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: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + +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. + +*/ + + +/* + * The Bridge class, responsible for navigating AS instances + */ +function FABridge(target,bridgeName) +{ + this.target = target; + this.remoteTypeCache = {}; + this.remoteInstanceCache = {}; + this.remoteFunctionCache = {}; + this.localFunctionCache = {}; + this.bridgeID = FABridge.nextBridgeID++; + this.name = bridgeName; + this.nextLocalFuncID = 0; + FABridge.instances[this.name] = this; + FABridge.idMap[this.bridgeID] = this; + + return this; +} + +// type codes for packed values +FABridge.TYPE_ASINSTANCE = 1; +FABridge.TYPE_ASFUNCTION = 2; + +FABridge.TYPE_JSFUNCTION = 3; +FABridge.TYPE_ANONYMOUS = 4; + +FABridge.initCallbacks = {}; +FABridge.userTypes = {}; + +FABridge.addToUserTypes = function() +{ + for (var i = 0; i < arguments.length; i++) + { + FABridge.userTypes[arguments[i]] = { + 'typeName': arguments[i], + 'enriched': false + }; + } +} + +FABridge.argsToArray = function(args) +{ + var result = []; + for (var i = 0; i < args.length; i++) + { + result[i] = args[i]; + } + return result; +} + +function instanceFactory(objID) +{ + this.fb_instance_id = objID; + return this; +} + +function FABridge__invokeJSFunction(args) +{ + var funcID = args[0]; + var throughArgs = args.concat();//FABridge.argsToArray(arguments); + throughArgs.shift(); + + var bridge = FABridge.extractBridgeFromID(funcID); + return bridge.invokeLocalFunction(funcID, throughArgs); +} + +FABridge.addInitializationCallback = function(bridgeName, callback) +{ + var inst = FABridge.instances[bridgeName]; + if (inst != undefined) + { + callback.call(inst); + return; + } + + var callbackList = FABridge.initCallbacks[bridgeName]; + if(callbackList == null) + { + FABridge.initCallbacks[bridgeName] = callbackList = []; + } + + callbackList.push(callback); +} + +// updated for changes to SWFObject2 +function FABridge__bridgeInitialized(bridgeName) { + var objects = document.getElementsByTagName("object"); + var ol = objects.length; + var activeObjects = []; + if (ol > 0) { + for (var i = 0; i < ol; i++) { + if (typeof objects[i].SetVariable != "undefined") { + activeObjects[activeObjects.length] = objects[i]; + } + } + } + var embeds = document.getElementsByTagName("embed"); + var el = embeds.length; + var activeEmbeds = []; + if (el > 0) { + for (var j = 0; j < el; j++) { + if (typeof embeds[j].SetVariable != "undefined") { + activeEmbeds[activeEmbeds.length] = embeds[j]; + } + } + } + var aol = activeObjects.length; + var ael = activeEmbeds.length; + var searchStr = "bridgeName="+ bridgeName; + if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) { + FABridge.attachBridge(activeObjects[0], bridgeName); + } + else if (ael == 1 && !aol) { + FABridge.attachBridge(activeEmbeds[0], bridgeName); + } + else { + var flash_found = false; + if (aol > 1) { + for (var k = 0; k < aol; k++) { + var params = activeObjects[k].childNodes; + for (var l = 0; l < params.length; l++) { + var param = params[l]; + if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) { + FABridge.attachBridge(activeObjects[k], bridgeName); + flash_found = true; + break; + } + } + if (flash_found) { + break; + } + } + } + if (!flash_found && ael > 1) { + for (var m = 0; m < ael; m++) { + var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue; + if (flashVars.indexOf(searchStr) >= 0) { + FABridge.attachBridge(activeEmbeds[m], bridgeName); + break; + } + } + } + } + return true; +} + +// used to track multiple bridge instances, since callbacks from AS are global across the page. + +FABridge.nextBridgeID = 0; +FABridge.instances = {}; +FABridge.idMap = {}; +FABridge.refCount = 0; + +FABridge.extractBridgeFromID = function(id) +{ + var bridgeID = (id >> 16); + return FABridge.idMap[bridgeID]; +} + +FABridge.attachBridge = function(instance, bridgeName) +{ + var newBridgeInstance = new FABridge(instance, bridgeName); + + FABridge[bridgeName] = newBridgeInstance; + +/* FABridge[bridgeName] = function() { + return newBridgeInstance.root(); + } +*/ + var callbacks = FABridge.initCallbacks[bridgeName]; + if (callbacks == null) + { + return; + } + for (var i = 0; i < callbacks.length; i++) + { + callbacks[i].call(newBridgeInstance); + } + delete FABridge.initCallbacks[bridgeName] +} + +// some methods can't be proxied. You can use the explicit get,set, and call methods if necessary. + +FABridge.blockedMethods = +{ + toString: true, + get: true, + set: true, + call: true +}; + +FABridge.prototype = +{ + + +// bootstrapping + + root: function() + { + return this.deserialize(this.target.getRoot()); + }, +//clears all of the AS objects in the cache maps + releaseASObjects: function() + { + return this.target.releaseASObjects(); + }, +//clears a specific object in AS from the type maps + releaseNamedASObject: function(value) + { + if(typeof(value) != "object") + { + return false; + } + else + { + var ret = this.target.releaseNamedASObject(value.fb_instance_id); + return ret; + } + }, +//create a new AS Object + create: function(className) + { + return this.deserialize(this.target.create(className)); + }, + + + // utilities + + makeID: function(token) + { + return (this.bridgeID << 16) + token; + }, + + + // low level access to the flash object + +//get a named property from an AS object + getPropertyFromAS: function(objRef, propName) + { + if (FABridge.refCount > 0) + { + throw new 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.getPropFromAS(objRef, propName); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, +//set a named property on an AS object + setPropertyInAS: function(objRef,propName, value) + { + if (FABridge.refCount > 0) + { + throw new 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(objRef,propName, this.serialize(value)); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, + +//call an AS function + callASFunction: function(funcID, args) + { + if (FABridge.refCount > 0) + { + throw new 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(funcID, this.serialize(args)); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, +//call a method on an AS object + callASMethod: function(objID, funcName, args) + { + if (FABridge.refCount > 0) + { + throw new 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++; + args = this.serialize(args); + retVal = this.target.invokeASMethod(objID, funcName, args); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, + + // responders to remote calls from flash + + //callback from flash that executes a local JS function + //used mostly when setting js functions as callbacks on events + invokeLocalFunction: function(funcID, args) + { + var result; + var func = this.localFunctionCache[funcID]; + + if(func != undefined) + { + result = this.serialize(func.apply(null, this.deserialize(args))); + } + + return result; + }, + + // Object Types and Proxies + + // accepts an object reference, returns a type object matching the obj reference. + getTypeFromName: function(objTypeName) + { + return this.remoteTypeCache[objTypeName]; + }, + //create an AS proxy for the given object ID and type + createProxy: function(objID, typeName) + { + var objType = this.getTypeFromName(typeName); + instanceFactory.prototype = objType; + var instance = new instanceFactory(objID); + this.remoteInstanceCache[objID] = instance; + return instance; + }, + //return the proxy associated with the given object ID + getProxy: function(objID) + { + return this.remoteInstanceCache[objID]; + }, + + // accepts a type structure, returns a constructed type + addTypeDataToCache: function(typeData) + { + var newType = new ASProxy(this, typeData.name); + var accessors = typeData.accessors; + for (var i = 0; i < accessors.length; i++) + { + this.addPropertyToType(newType, accessors[i]); + } + + var methods = typeData.methods; + for (var i = 0; i < methods.length; i++) + { + if (FABridge.blockedMethods[methods[i]] == undefined) + { + this.addMethodToType(newType, methods[i]); + } + } + + + this.remoteTypeCache[newType.typeName] = newType; + return newType; + }, + + //add a property to a typename; used to define the properties that can be called on an AS proxied object + addPropertyToType: function(ty, propName) + { + var c = propName.charAt(0); + var setterName; + var getterName; + if(c >= "a" && c <= "z") + { + getterName = "get" + c.toUpperCase() + propName.substr(1); + setterName = "set" + c.toUpperCase() + propName.substr(1); + } + else + { + getterName = "get" + propName; + setterName = "set" + propName; + } + ty[setterName] = function(val) + { + this.bridge.setPropertyInAS(this.fb_instance_id, propName, val); + } + ty[getterName] = function() + { + return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); + } + }, + + //add a method to a typename; used to define the methods that can be callefd on an AS proxied object + addMethodToType: function(ty, methodName) + { + ty[methodName] = function() + { + return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments))); + } + }, + + // Function Proxies + + //returns the AS proxy for the specified function ID + getFunctionProxy: function(funcID) + { + var bridge = this; + if (this.remoteFunctionCache[funcID] == null) + { + this.remoteFunctionCache[funcID] = function() + { + bridge.callASFunction(funcID, FABridge.argsToArray(arguments)); + } + } + return this.remoteFunctionCache[funcID]; + }, + + //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache + getFunctionID: function(func) + { + if (func.__bridge_id__ == undefined) + { + func.__bridge_id__ = this.makeID(this.nextLocalFuncID++); + this.localFunctionCache[func.__bridge_id__] = func; + } + return func.__bridge_id__; + }, + + // serialization / deserialization + + serialize: function(value) + { + var result = {}; + + var t = typeof(value); + //primitives are kept as such + if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined) + { + result = value; + } + else if (value instanceof Array) + { + //arrays are serializesd recursively + result = []; + for (var i = 0; i < value.length; i++) + { + result[i] = this.serialize(value[i]); + } + } + else if (t == "function") + { + //js functions are assigned an ID and stored in the local cache + result.type = FABridge.TYPE_JSFUNCTION; + result.value = this.getFunctionID(value); + } + else if (value instanceof ASProxy) + { + result.type = FABridge.TYPE_ASINSTANCE; + result.value = value.fb_instance_id; + } + else + { + result.type = FABridge.TYPE_ANONYMOUS; + result.value = value; + } + + return result; + }, + + //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors + // the unpacking is done by returning the value on each pachet for objects/arrays + deserialize: function(packedValue) + { + + var result; + + var t = typeof(packedValue); + if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined) + { + result = this.handleError(packedValue); + } + else if (packedValue instanceof Array) + { + result = []; + for (var i = 0; i < packedValue.length; i++) + { + result[i] = this.deserialize(packedValue[i]); + } + } + else if (t == "object") + { + for(var i = 0; i < packedValue.newTypes.length; i++) + { + this.addTypeDataToCache(packedValue.newTypes[i]); + } + for (var aRefID in packedValue.newRefs) + { + this.createProxy(aRefID, packedValue.newRefs[aRefID]); + } + if (packedValue.type == FABridge.TYPE_PRIMITIVE) + { + result = packedValue.value; + } + else if (packedValue.type == FABridge.TYPE_ASFUNCTION) + { + result = this.getFunctionProxy(packedValue.value); + } + else if (packedValue.type == FABridge.TYPE_ASINSTANCE) + { + result = this.getProxy(packedValue.value); + } + else if (packedValue.type == FABridge.TYPE_ANONYMOUS) + { + result = packedValue.value; + } + } + return result; + }, + //increases the reference count for the given object + addRef: function(obj) + { + this.target.incRef(obj.fb_instance_id); + }, + //decrease the reference count for the given object and release it if needed + release:function(obj) + { + this.target.releaseRef(obj.fb_instance_id); + }, + + // check the given value for the components of the hard-coded error code : __FLASHERROR + // used to marshall NPE's into flash + + handleError: function(value) + { + if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0) + { + var myErrorMessage = value.split("||"); + if(FABridge.refCount > 0 ) + { + FABridge.refCount--; + } + throw new Error(myErrorMessage[1]); + return value; + } + else + { + return value; + } + } +}; + +// The root ASProxy class that facades a flash object + +ASProxy = function(bridge, typeName) +{ + this.bridge = bridge; + this.typeName = typeName; + return this; +}; +//methods available on each ASProxy object +ASProxy.prototype = +{ + get: function(propName) + { + return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); + }, + + set: function(propName, value) + { + this.bridge.setPropertyInAS(this.fb_instance_id, propName, value); + }, + + call: function(funcName, args) + { + this.bridge.callASMethod(this.fb_instance_id, funcName, args); + }, + + addRef: function() { + this.bridge.addRef(this); + }, + + release: function() { + this.bridge.release(this); + } +}; + +// Copyright: Hiroshi Ichikawa <http://gimite.net/en/> +// License: New BSD License +// Reference: http://dev.w3.org/html5/websockets/ +// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol + +(function() { + + if (window.WebSocket) return; + + var console = window.console; + if (!console) console = {log: function(){ }, error: function(){ }}; + + if (!swfobject.hasFlashPlayerVersion("9.0.0")) { + console.error("Flash Player is not installed."); + return; + } + if (location.protocol == "file:") { + console.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(url, protocol, proxyHost, proxyPort, headers) { + var self = this; + self.readyState = WebSocket.CONNECTING; + self.bufferedAmount = 0; + // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc. + // Otherwise, when onopen fires immediately, onopen is called before it is set. + setTimeout(function() { + WebSocket.__addTask(function() { + self.__createFlash(url, protocol, proxyHost, proxyPort, headers); + }); + }, 1); + } + + WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) { + var self = this; + self.__flash = + WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null); + + self.__flash.addEventListener("open", function(fe) { + try { + self.readyState = self.__flash.getReadyState(); + if (self.__timer) clearInterval(self.__timer); + if (window.opera) { + // Workaround for weird behavior of Opera which sometimes drops events. + self.__timer = setInterval(function () { + self.__handleMessages(); + }, 500); + } + if (self.onopen) self.onopen(); + } catch (e) { + console.error(e.toString()); + } + }); + + self.__flash.addEventListener("close", function(fe) { + try { + self.readyState = self.__flash.getReadyState(); + if (self.__timer) clearInterval(self.__timer); + if (self.onclose) self.onclose(); + } catch (e) { + console.error(e.toString()); + } + }); + + self.__flash.addEventListener("message", function() { + try { + self.__handleMessages(); + } catch (e) { + console.error(e.toString()); + } + }); + + self.__flash.addEventListener("error", function(fe) { + try { + if (self.__timer) clearInterval(self.__timer); + if (self.onerror) self.onerror(); + } catch (e) { + console.error(e.toString()); + } + }); + + self.__flash.addEventListener("stateChange", function(fe) { + try { + self.readyState = self.__flash.getReadyState(); + self.bufferedAmount = fe.getBufferedAmount(); + } catch (e) { + console.error(e.toString()); + } + }); + + //console.log("[WebSocket] Flash object is ready"); + }; + + WebSocket.prototype.send = function(data) { + if (this.__flash) { + this.readyState = this.__flash.getReadyState(); + } + if (!this.__flash || this.readyState == WebSocket.CONNECTING) { + throw "INVALID_STATE_ERR: Web Socket connection has not been established"; + } + // We use encodeURIComponent() here, because FABridge doesn't work if + // the argument includes some characters. We don't use escape() here + // because of this: + // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions + // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't + // preserve all Unicode characters either e.g. "\uffff" in Firefox. + var result = this.__flash.send(encodeURIComponent(data)); + if (result < 0) { // success + return true; + } else { + this.bufferedAmount = result; + return false; + } + }; + + WebSocket.prototype.close = function() { + var self = this; + if (!self.__flash) return; + self.readyState = self.__flash.getReadyState(); + if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return; + self.__flash.close(); + // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events + // which causes weird error: + // > You are trying to call recursively into the Flash Player which is not allowed. + self.readyState = WebSocket.CLOSED; + if (self.__timer) clearInterval(self.__timer); + if (self.onclose) { + // Make it asynchronous so that it looks more like an actual + // close event + setTimeout(self.onclose, 1); + } + }; + + /** + * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture !NB Not implemented yet + * @return void + */ + WebSocket.prototype.addEventListener = function(type, listener, useCapture) { + if (!('__events' in this)) { + this.__events = {}; + } + if (!(type in this.__events)) { + this.__events[type] = []; + if ('function' == typeof this['on' + type]) { + this.__events[type].defaultHandler = this['on' + type]; + this['on' + type] = this.__createEventHandler(this, type); + } + } + this.__events[type].push(listener); + }; + + /** + * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>} + * + * @param {string} type + * @param {function} listener + * @param {boolean} useCapture NB! Not implemented yet + * @return void + */ + WebSocket.prototype.removeEventListener = function(type, listener, useCapture) { + if (!('__events' in this)) { + this.__events = {}; + } + if (!(type in this.__events)) return; + for (var i = this.__events.length; i > -1; --i) { + if (listener === this.__events[type][i]) { + this.__events[type].splice(i, 1); + break; + } + } + }; + + /** + * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>} + * + * @param {WebSocketEvent} event + * @return void + */ + WebSocket.prototype.dispatchEvent = function(event) { + if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR'; + if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR'; + + for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) { + this.__events[event.type][i](event); + if (event.cancelBubble) break; + } + + if (false !== event.returnValue && + 'function' == typeof this.__events[event.type].defaultHandler) + { + this.__events[event.type].defaultHandler(event); + } + }; + + WebSocket.prototype.__handleMessages = function() { + // Gets data using readSocketData() instead of getting it from event object + // of Flash event. This is to make sure to keep message order. + // It seems sometimes Flash events don't arrive in the same order as they are sent. + var arr = this.__flash.readSocketData(); + for (var i = 0; i < arr.length; i++) { + var data = decodeURIComponent(arr[i]); + try { + if (this.onmessage) { + var e; + if (window.MessageEvent) { + e = document.createEvent("MessageEvent"); + e.initMessageEvent("message", false, false, data, null, null, window, null); + } else { // IE + e = {data: data}; + } + this.onmessage(e); + } + } catch (e) { + console.error(e.toString()); + } + } + }; + + /** + * @param {object} object + * @param {string} type + */ + WebSocket.prototype.__createEventHandler = function(object, type) { + return function(data) { + var event = new WebSocketEvent(); + event.initEvent(type, true, true); + event.target = event.currentTarget = object; + for (var key in data) { + event[key] = data[key]; + } + object.dispatchEvent(event, arguments); + }; + } + + /** + * Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>} + * + * @class + * @constructor + */ + function WebSocketEvent(){} + + /** + * + * @type boolean + */ + WebSocketEvent.prototype.cancelable = true; + + /** + * + * @type boolean + */ + WebSocketEvent.prototype.cancelBubble = false; + + /** + * + * @return void + */ + WebSocketEvent.prototype.preventDefault = function() { + if (this.cancelable) { + this.returnValue = false; + } + }; + + /** + * + * @return void + */ + WebSocketEvent.prototype.stopPropagation = function() { + this.cancelBubble = true; + }; + + /** + * + * @param {string} eventTypeArg + * @param {boolean} canBubbleArg + * @param {boolean} cancelableArg + * @return void + */ + WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) { + this.type = eventTypeArg; + this.cancelable = cancelableArg; + this.timeStamp = new Date(); + }; + + + WebSocket.CONNECTING = 0; + WebSocket.OPEN = 1; + WebSocket.CLOSING = 2; + WebSocket.CLOSED = 3; + + WebSocket.__tasks = []; + + WebSocket.__initialize = function() { + if (WebSocket.__swfLocation) { + // For backword compatibility. + window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation; + } + if (!window.WEB_SOCKET_SWF_LOCATION) { + console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf"); + return; + } + var container = document.createElement("div"); + container.id = "webSocketContainer"; + // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents + // Flash from loading at least in IE. So we move it out of the screen at (-100, -100). + // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash + // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is + // the best we can do as far as we know now. + container.style.position = "absolute"; + if (WebSocket.__isFlashLite()) { + container.style.left = "0px"; + container.style.top = "0px"; + } else { + container.style.left = "-100px"; + container.style.top = "-100px"; + } + var holder = document.createElement("div"); + holder.id = "webSocketFlash"; + container.appendChild(holder); + document.body.appendChild(container); + // See this article for hasPriority: + // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html + swfobject.embedSWF( + WEB_SOCKET_SWF_LOCATION, "webSocketFlash", + "1" /* width */, "1" /* height */, "9.0.0" /* SWF version */, + null, {bridgeName: "webSocket"}, {hasPriority: true, allowScriptAccess: "always"}, null, + function(e) { + if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed"); + } + ); + FABridge.addInitializationCallback("webSocket", function() { + try { + //console.log("[WebSocket] FABridge initializad"); + WebSocket.__flash = FABridge.webSocket.root(); + WebSocket.__flash.setCallerUrl(location.href); + WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG); + for (var i = 0; i < WebSocket.__tasks.length; ++i) { + WebSocket.__tasks[i](); + } + WebSocket.__tasks = []; + } catch (e) { + console.error("[WebSocket] " + e.toString()); + } + }); + }; + + WebSocket.__addTask = function(task) { + if (WebSocket.__flash) { + task(); + } else { + WebSocket.__tasks.push(task); + } + }; + + WebSocket.__isFlashLite = function() { + if (!window.navigator || !window.navigator.mimeTypes) return false; + var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"]; + if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) return false; + return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false; + }; + + // called from Flash + window.webSocketLog = function(message) { + console.log(decodeURIComponent(message)); + }; + + // called from Flash + window.webSocketError = function(message) { + console.error(decodeURIComponent(message)); + }; + + if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) { + if (window.addEventListener) { + window.addEventListener("load", WebSocket.__initialize, false); + } else { + window.attachEvent("onload", WebSocket.__initialize); + } + } + +})(); + diff --git a/addon/chrome/modules/module.js b/addon/chrome/modules/module.js @@ -0,0 +1,7 @@ +var EXPORTED_SYMBOLS = ["state"]; + +var state = { + foo: 0, + bar: 1, + baz: 2 +}; diff --git a/addon/chrome/skin/images/.gitignore b/addon/chrome/skin/images/.gitignore diff --git a/addon/chrome/skin/stylesheets/stylesheet.css b/addon/chrome/skin/stylesheets/stylesheet.css diff --git a/addon/defaults/preferences/.gitignore b/addon/defaults/preferences/.gitignore diff --git a/addon/install.rdf b/addon/install.rdf @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#" + xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <Description about="urn:mozilla:install-manifest"> + <em:id>antimony@borderstylo.com</em:id> + <em:name>antimony</em:name> + <em:version>1.0.0</em:version> + <em:type>2</em:type> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>1.5</em:minVersion> + <em:maxVersion>3.6.*</em:maxVersion> + </Description> + </em:targetApplication> + <em:aboutURL>chrome://antimony/content/about.xul</em:aboutURL> + <em:creator>Ryan Wolf</em:creator> + <em:description>Barebones Extension For Firefox, Ya'll</em:description> + <em:homepageURL>http://github.com/thebigbad/antimony</em:homepageURL> + </Description> +</RDF> diff --git a/addon/locale/en-US/stringbundle.dtd b/addon/locale/en-US/stringbundle.dtd @@ -0,0 +1,7 @@ +<!-- See: https://developer.mozilla.org/en/Localizing_an_extension --> +<!ENTITY antimony.menu.title "antimony"> +<!ENTITY antimony.menu.item "Say Hi"> + +<!ENTITY antimony.about "antimony"> +<!ENTITY antimony.about.close "close"> + diff --git a/test.js b/test.js @@ -0,0 +1,21 @@ +var http = require('http'), + io = require('socket.io'), // for npm, otherwise use require('./path/to/socket.io') +server = http.createServer(function(req, res){ + // your normal server code + res.writeHead(200, {'Content-Type': 'text/html'}); + res.end('<h1>Hello world</h1>'); +}); +server.listen(1234); + +// socket.io +var socket = io.listen(server); +socket.on('connection', function (client) { + console.log('connection'); + // new client is here! + client.on('message', function () { + console.log('message'); + }) + client.on('disconnect', function () { + console.log('disconnect'); + }) +});