PageRenderTime 1224ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/public/socket-io/socket.io.js

https://bitbucket.org/tomekcejner/node-sandbox
JavaScript | 3707 lines | 2790 code | 323 blank | 594 comment | 213 complexity | bb2c9d9640264cf9c0cb9db40605b740 MD5 | raw file
  1. /*! Socket.IO.js build:0.8.4, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */
  2. /**
  3. * socket.io
  4. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  5. * MIT Licensed
  6. */
  7. (function (exports) {
  8. /**
  9. * IO namespace.
  10. *
  11. * @namespace
  12. */
  13. var io = exports;
  14. /**
  15. * Socket.IO version
  16. *
  17. * @api public
  18. */
  19. io.version = '0.8.4';
  20. /**
  21. * Protocol implemented.
  22. *
  23. * @api public
  24. */
  25. io.protocol = 1;
  26. /**
  27. * Available transports, these will be populated with the available transports
  28. *
  29. * @api public
  30. */
  31. io.transports = [];
  32. /**
  33. * Keep track of jsonp callbacks.
  34. *
  35. * @api private
  36. */
  37. io.j = [];
  38. /**
  39. * Keep track of our io.Sockets
  40. *
  41. * @api private
  42. */
  43. io.sockets = {};
  44. /**
  45. * Manages connections to hosts.
  46. *
  47. * @param {String} uri
  48. * @Param {Boolean} force creation of new socket (defaults to false)
  49. * @api public
  50. */
  51. io.connect = function (host, details) {
  52. var uri = io.util.parseUri(host)
  53. , uuri
  54. , socket;
  55. if ('undefined' != typeof document) {
  56. uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
  57. uri.host = uri.host || document.domain;
  58. uri.port = uri.port || document.location.port;
  59. }
  60. uuri = io.util.uniqueUri(uri);
  61. var options = {
  62. host: uri.host
  63. , secure: 'https' == uri.protocol
  64. , port: uri.port || ('https' == uri.protocol ? 443 : 80)
  65. , query: uri.query || ''
  66. };
  67. io.util.merge(options, details);
  68. if (options['force new connection'] || !io.sockets[uuri]) {
  69. socket = new io.Socket(options);
  70. }
  71. if (!options['force new connection'] && socket) {
  72. io.sockets[uuri] = socket;
  73. }
  74. socket = socket || io.sockets[uuri];
  75. // if path is different from '' or /
  76. return socket.of(uri.path.length > 1 ? uri.path : '');
  77. };
  78. })('object' === typeof module ? module.exports : (window.io = {}));
  79. /**
  80. * socket.io
  81. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  82. * MIT Licensed
  83. */
  84. (function (exports, global) {
  85. /**
  86. * Utilities namespace.
  87. *
  88. * @namespace
  89. */
  90. var util = exports.util = {};
  91. /**
  92. * Parses an URI
  93. *
  94. * @author Steven Levithan <stevenlevithan.com> (MIT license)
  95. * @api public
  96. */
  97. var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
  98. var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
  99. 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
  100. 'anchor'];
  101. util.parseUri = function (str) {
  102. var m = re.exec(str || '')
  103. , uri = {}
  104. , i = 14;
  105. while (i--) {
  106. uri[parts[i]] = m[i] || '';
  107. }
  108. return uri;
  109. };
  110. /**
  111. * Produces a unique url that identifies a Socket.IO connection.
  112. *
  113. * @param {Object} uri
  114. * @api public
  115. */
  116. util.uniqueUri = function (uri) {
  117. var protocol = uri.protocol
  118. , host = uri.host
  119. , port = uri.port;
  120. if ('document' in global) {
  121. host = host || document.domain;
  122. port = port || (protocol == 'https'
  123. && document.location.protocol !== 'https:' ? 443 : document.location.port);
  124. } else {
  125. host = host || 'localhost';
  126. if (!port && protocol == 'https') {
  127. port = 443;
  128. }
  129. }
  130. return (protocol || 'http') + '://' + host + ':' + (port || 80);
  131. };
  132. /**
  133. * Mergest 2 query strings in to once unique query string
  134. *
  135. * @param {String} base
  136. * @param {String} addition
  137. * @api public
  138. */
  139. util.query = function (base, addition) {
  140. var query = util.chunkQuery(base || '')
  141. , components = [];
  142. util.merge(query, util.chunkQuery(addition || ''));
  143. for (var part in query) {
  144. if (query.hasOwnProperty(part)) {
  145. components.push(part + '=' + query[part]);
  146. }
  147. }
  148. return components.length ? '?' + components.join('&') : '';
  149. };
  150. /**
  151. * Transforms a querystring in to an object
  152. *
  153. * @param {String} qs
  154. * @api public
  155. */
  156. util.chunkQuery = function (qs) {
  157. var query = {}
  158. , params = qs.split('&')
  159. , i = 0
  160. , l = params.length
  161. , kv;
  162. for (; i < l; ++i) {
  163. kv = params[i].split('=');
  164. if (kv[0]) {
  165. query[kv[0]] = decodeURIComponent(kv[1]);
  166. }
  167. }
  168. return query;
  169. };
  170. /**
  171. * Executes the given function when the page is loaded.
  172. *
  173. * io.util.load(function () { console.log('page loaded'); });
  174. *
  175. * @param {Function} fn
  176. * @api public
  177. */
  178. var pageLoaded = false;
  179. util.load = function (fn) {
  180. if ('document' in global && document.readyState === 'complete' || pageLoaded) {
  181. return fn();
  182. }
  183. util.on(global, 'load', fn, false);
  184. };
  185. /**
  186. * Adds an event.
  187. *
  188. * @api private
  189. */
  190. util.on = function (element, event, fn, capture) {
  191. if (element.attachEvent) {
  192. element.attachEvent('on' + event, fn);
  193. } else if (element.addEventListener) {
  194. element.addEventListener(event, fn, capture);
  195. }
  196. };
  197. /**
  198. * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
  199. *
  200. * @param {Boolean} [xdomain] Create a request that can be used cross domain.
  201. * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
  202. * @api private
  203. */
  204. util.request = function (xdomain) {
  205. if ('undefined' != typeof window) {
  206. if (xdomain && window.XDomainRequest) {
  207. return new XDomainRequest();
  208. }
  209. if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
  210. return new XMLHttpRequest();
  211. }
  212. if (!xdomain) {
  213. try {
  214. return new window.ActiveXObject('Microsoft.XMLHTTP');
  215. } catch(e) { }
  216. }
  217. }
  218. return null;
  219. };
  220. /**
  221. * XHR based transport constructor.
  222. *
  223. * @constructor
  224. * @api public
  225. */
  226. /**
  227. * Change the internal pageLoaded value.
  228. */
  229. if ('undefined' != typeof window) {
  230. util.load(function () {
  231. pageLoaded = true;
  232. });
  233. }
  234. /**
  235. * Defers a function to ensure a spinner is not displayed by the browser
  236. *
  237. * @param {Function} fn
  238. * @api public
  239. */
  240. util.defer = function (fn) {
  241. if (!util.ua.webkit) {
  242. return fn();
  243. }
  244. util.load(function () {
  245. setTimeout(fn, 100);
  246. });
  247. };
  248. /**
  249. * Merges two objects.
  250. *
  251. * @api public
  252. */
  253. util.merge = function merge (target, additional, deep, lastseen) {
  254. var seen = lastseen || []
  255. , depth = typeof deep == 'undefined' ? 2 : deep
  256. , prop;
  257. for (prop in additional) {
  258. if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
  259. if (typeof target[prop] !== 'object' || !depth) {
  260. target[prop] = additional[prop];
  261. seen.push(additional[prop]);
  262. } else {
  263. util.merge(target[prop], additional[prop], depth - 1, seen);
  264. }
  265. }
  266. }
  267. return target;
  268. };
  269. /**
  270. * Merges prototypes from objects
  271. *
  272. * @api public
  273. */
  274. util.mixin = function (ctor, ctor2) {
  275. util.merge(ctor.prototype, ctor2.prototype);
  276. };
  277. /**
  278. * Shortcut for prototypical and static inheritance.
  279. *
  280. * @api private
  281. */
  282. util.inherit = function (ctor, ctor2) {
  283. function f() {};
  284. f.prototype = ctor2.prototype;
  285. ctor.prototype = new f;
  286. };
  287. /**
  288. * Checks if the given object is an Array.
  289. *
  290. * io.util.isArray([]); // true
  291. * io.util.isArray({}); // false
  292. *
  293. * @param Object obj
  294. * @api public
  295. */
  296. util.isArray = Array.isArray || function (obj) {
  297. return Object.prototype.toString.call(obj) === '[object Array]';
  298. };
  299. /**
  300. * Intersects values of two arrays into a third
  301. *
  302. * @api public
  303. */
  304. util.intersect = function (arr, arr2) {
  305. var ret = []
  306. , longest = arr.length > arr2.length ? arr : arr2
  307. , shortest = arr.length > arr2.length ? arr2 : arr;
  308. for (var i = 0, l = shortest.length; i < l; i++) {
  309. if (~util.indexOf(longest, shortest[i]))
  310. ret.push(shortest[i]);
  311. }
  312. return ret;
  313. }
  314. /**
  315. * Array indexOf compatibility.
  316. *
  317. * @see bit.ly/a5Dxa2
  318. * @api public
  319. */
  320. util.indexOf = function (arr, o, i) {
  321. if (Array.prototype.indexOf) {
  322. return Array.prototype.indexOf.call(arr, o, i);
  323. }
  324. for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
  325. i < j && arr[i] !== o; i++);
  326. return j <= i ? -1 : i;
  327. };
  328. /**
  329. * Converts enumerables to array.
  330. *
  331. * @api public
  332. */
  333. util.toArray = function (enu) {
  334. var arr = [];
  335. for (var i = 0, l = enu.length; i < l; i++)
  336. arr.push(enu[i]);
  337. return arr;
  338. };
  339. /**
  340. * UA / engines detection namespace.
  341. *
  342. * @namespace
  343. */
  344. util.ua = {};
  345. /**
  346. * Whether the UA supports CORS for XHR.
  347. *
  348. * @api public
  349. */
  350. util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
  351. (function () {
  352. try {
  353. var a = new XMLHttpRequest();
  354. } catch (e) {
  355. return false;
  356. }
  357. return a.withCredentials != undefined;
  358. })();
  359. /**
  360. * Detect webkit.
  361. *
  362. * @api public
  363. */
  364. util.ua.webkit = 'undefined' != typeof navigator
  365. && /webkit/i.test(navigator.userAgent);
  366. })(
  367. 'undefined' != typeof window ? io : module.exports
  368. , this
  369. );
  370. /**
  371. * socket.io
  372. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  373. * MIT Licensed
  374. */
  375. (function (exports, io) {
  376. /**
  377. * Expose constructor.
  378. */
  379. exports.EventEmitter = EventEmitter;
  380. /**
  381. * Event emitter constructor.
  382. *
  383. * @api public.
  384. */
  385. function EventEmitter () {};
  386. /**
  387. * Adds a listener
  388. *
  389. * @api public
  390. */
  391. EventEmitter.prototype.on = function (name, fn) {
  392. if (!this.$events) {
  393. this.$events = {};
  394. }
  395. if (!this.$events[name]) {
  396. this.$events[name] = fn;
  397. } else if (io.util.isArray(this.$events[name])) {
  398. this.$events[name].push(fn);
  399. } else {
  400. this.$events[name] = [this.$events[name], fn];
  401. }
  402. return this;
  403. };
  404. EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  405. /**
  406. * Adds a volatile listener.
  407. *
  408. * @api public
  409. */
  410. EventEmitter.prototype.once = function (name, fn) {
  411. var self = this;
  412. function on () {
  413. self.removeListener(name, on);
  414. fn.apply(this, arguments);
  415. };
  416. on.listener = fn;
  417. this.on(name, on);
  418. return this;
  419. };
  420. /**
  421. * Removes a listener.
  422. *
  423. * @api public
  424. */
  425. EventEmitter.prototype.removeListener = function (name, fn) {
  426. if (this.$events && this.$events[name]) {
  427. var list = this.$events[name];
  428. if (io.util.isArray(list)) {
  429. var pos = -1;
  430. for (var i = 0, l = list.length; i < l; i++) {
  431. if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
  432. pos = i;
  433. break;
  434. }
  435. }
  436. if (pos < 0) {
  437. return this;
  438. }
  439. list.splice(pos, 1);
  440. if (!list.length) {
  441. delete this.$events[name];
  442. }
  443. } else if (list === fn || (list.listener && list.listener === fn)) {
  444. delete this.$events[name];
  445. }
  446. }
  447. return this;
  448. };
  449. /**
  450. * Removes all listeners for an event.
  451. *
  452. * @api public
  453. */
  454. EventEmitter.prototype.removeAllListeners = function (name) {
  455. // TODO: enable this when node 0.5 is stable
  456. //if (name === undefined) {
  457. //this.$events = {};
  458. //return this;
  459. //}
  460. if (this.$events && this.$events[name]) {
  461. this.$events[name] = null;
  462. }
  463. return this;
  464. };
  465. /**
  466. * Gets all listeners for a certain event.
  467. *
  468. * @api publci
  469. */
  470. EventEmitter.prototype.listeners = function (name) {
  471. if (!this.$events) {
  472. this.$events = {};
  473. }
  474. if (!this.$events[name]) {
  475. this.$events[name] = [];
  476. }
  477. if (!io.util.isArray(this.$events[name])) {
  478. this.$events[name] = [this.$events[name]];
  479. }
  480. return this.$events[name];
  481. };
  482. /**
  483. * Emits an event.
  484. *
  485. * @api public
  486. */
  487. EventEmitter.prototype.emit = function (name) {
  488. if (!this.$events) {
  489. return false;
  490. }
  491. var handler = this.$events[name];
  492. if (!handler) {
  493. return false;
  494. }
  495. var args = Array.prototype.slice.call(arguments, 1);
  496. if ('function' == typeof handler) {
  497. handler.apply(this, args);
  498. } else if (io.util.isArray(handler)) {
  499. var listeners = handler.slice();
  500. for (var i = 0, l = listeners.length; i < l; i++) {
  501. listeners[i].apply(this, args);
  502. }
  503. } else {
  504. return false;
  505. }
  506. return true;
  507. };
  508. })(
  509. 'undefined' != typeof io ? io : module.exports
  510. , 'undefined' != typeof io ? io : module.parent.exports
  511. );
  512. /**
  513. * socket.io
  514. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  515. * MIT Licensed
  516. */
  517. /**
  518. * Based on JSON2 (http://www.JSON.org/js.html).
  519. */
  520. (function (exports, nativeJSON) {
  521. "use strict";
  522. // use native JSON if it's available
  523. if (nativeJSON && nativeJSON.parse){
  524. return exports.JSON = {
  525. parse: nativeJSON.parse
  526. , stringify: nativeJSON.stringify
  527. }
  528. }
  529. var JSON = exports.JSON = {};
  530. function f(n) {
  531. // Format integers to have at least two digits.
  532. return n < 10 ? '0' + n : n;
  533. }
  534. function date(d, key) {
  535. return isFinite(d.valueOf()) ?
  536. d.getUTCFullYear() + '-' +
  537. f(d.getUTCMonth() + 1) + '-' +
  538. f(d.getUTCDate()) + 'T' +
  539. f(d.getUTCHours()) + ':' +
  540. f(d.getUTCMinutes()) + ':' +
  541. f(d.getUTCSeconds()) + 'Z' : null;
  542. };
  543. var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  544. escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  545. gap,
  546. indent,
  547. meta = { // table of character substitutions
  548. '\b': '\\b',
  549. '\t': '\\t',
  550. '\n': '\\n',
  551. '\f': '\\f',
  552. '\r': '\\r',
  553. '"' : '\\"',
  554. '\\': '\\\\'
  555. },
  556. rep;
  557. function quote(string) {
  558. // If the string contains no control characters, no quote characters, and no
  559. // backslash characters, then we can safely slap some quotes around it.
  560. // Otherwise we must also replace the offending characters with safe escape
  561. // sequences.
  562. escapable.lastIndex = 0;
  563. return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
  564. var c = meta[a];
  565. return typeof c === 'string' ? c :
  566. '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  567. }) + '"' : '"' + string + '"';
  568. }
  569. function str(key, holder) {
  570. // Produce a string from holder[key].
  571. var i, // The loop counter.
  572. k, // The member key.
  573. v, // The member value.
  574. length,
  575. mind = gap,
  576. partial,
  577. value = holder[key];
  578. // If the value has a toJSON method, call it to obtain a replacement value.
  579. if (value instanceof Date) {
  580. value = date(key);
  581. }
  582. // If we were called with a replacer function, then call the replacer to
  583. // obtain a replacement value.
  584. if (typeof rep === 'function') {
  585. value = rep.call(holder, key, value);
  586. }
  587. // What happens next depends on the value's type.
  588. switch (typeof value) {
  589. case 'string':
  590. return quote(value);
  591. case 'number':
  592. // JSON numbers must be finite. Encode non-finite numbers as null.
  593. return isFinite(value) ? String(value) : 'null';
  594. case 'boolean':
  595. case 'null':
  596. // If the value is a boolean or null, convert it to a string. Note:
  597. // typeof null does not produce 'null'. The case is included here in
  598. // the remote chance that this gets fixed someday.
  599. return String(value);
  600. // If the type is 'object', we might be dealing with an object or an array or
  601. // null.
  602. case 'object':
  603. // Due to a specification blunder in ECMAScript, typeof null is 'object',
  604. // so watch out for that case.
  605. if (!value) {
  606. return 'null';
  607. }
  608. // Make an array to hold the partial results of stringifying this object value.
  609. gap += indent;
  610. partial = [];
  611. // Is the value an array?
  612. if (Object.prototype.toString.apply(value) === '[object Array]') {
  613. // The value is an array. Stringify every element. Use null as a placeholder
  614. // for non-JSON values.
  615. length = value.length;
  616. for (i = 0; i < length; i += 1) {
  617. partial[i] = str(i, value) || 'null';
  618. }
  619. // Join all of the elements together, separated with commas, and wrap them in
  620. // brackets.
  621. v = partial.length === 0 ? '[]' : gap ?
  622. '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
  623. '[' + partial.join(',') + ']';
  624. gap = mind;
  625. return v;
  626. }
  627. // If the replacer is an array, use it to select the members to be stringified.
  628. if (rep && typeof rep === 'object') {
  629. length = rep.length;
  630. for (i = 0; i < length; i += 1) {
  631. if (typeof rep[i] === 'string') {
  632. k = rep[i];
  633. v = str(k, value);
  634. if (v) {
  635. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  636. }
  637. }
  638. }
  639. } else {
  640. // Otherwise, iterate through all of the keys in the object.
  641. for (k in value) {
  642. if (Object.prototype.hasOwnProperty.call(value, k)) {
  643. v = str(k, value);
  644. if (v) {
  645. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  646. }
  647. }
  648. }
  649. }
  650. // Join all of the member texts together, separated with commas,
  651. // and wrap them in braces.
  652. v = partial.length === 0 ? '{}' : gap ?
  653. '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
  654. '{' + partial.join(',') + '}';
  655. gap = mind;
  656. return v;
  657. }
  658. }
  659. // If the JSON object does not yet have a stringify method, give it one.
  660. JSON.stringify = function (value, replacer, space) {
  661. // The stringify method takes a value and an optional replacer, and an optional
  662. // space parameter, and returns a JSON text. The replacer can be a function
  663. // that can replace values, or an array of strings that will select the keys.
  664. // A default replacer method can be provided. Use of the space parameter can
  665. // produce text that is more easily readable.
  666. var i;
  667. gap = '';
  668. indent = '';
  669. // If the space parameter is a number, make an indent string containing that
  670. // many spaces.
  671. if (typeof space === 'number') {
  672. for (i = 0; i < space; i += 1) {
  673. indent += ' ';
  674. }
  675. // If the space parameter is a string, it will be used as the indent string.
  676. } else if (typeof space === 'string') {
  677. indent = space;
  678. }
  679. // If there is a replacer, it must be a function or an array.
  680. // Otherwise, throw an error.
  681. rep = replacer;
  682. if (replacer && typeof replacer !== 'function' &&
  683. (typeof replacer !== 'object' ||
  684. typeof replacer.length !== 'number')) {
  685. throw new Error('JSON.stringify');
  686. }
  687. // Make a fake root object containing our value under the key of ''.
  688. // Return the result of stringifying the value.
  689. return str('', {'': value});
  690. };
  691. // If the JSON object does not yet have a parse method, give it one.
  692. JSON.parse = function (text, reviver) {
  693. // The parse method takes a text and an optional reviver function, and returns
  694. // a JavaScript value if the text is a valid JSON text.
  695. var j;
  696. function walk(holder, key) {
  697. // The walk method is used to recursively walk the resulting structure so
  698. // that modifications can be made.
  699. var k, v, value = holder[key];
  700. if (value && typeof value === 'object') {
  701. for (k in value) {
  702. if (Object.prototype.hasOwnProperty.call(value, k)) {
  703. v = walk(value, k);
  704. if (v !== undefined) {
  705. value[k] = v;
  706. } else {
  707. delete value[k];
  708. }
  709. }
  710. }
  711. }
  712. return reviver.call(holder, key, value);
  713. }
  714. // Parsing happens in four stages. In the first stage, we replace certain
  715. // Unicode characters with escape sequences. JavaScript handles many characters
  716. // incorrectly, either silently deleting them, or treating them as line endings.
  717. text = String(text);
  718. cx.lastIndex = 0;
  719. if (cx.test(text)) {
  720. text = text.replace(cx, function (a) {
  721. return '\\u' +
  722. ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  723. });
  724. }
  725. // In the second stage, we run the text against regular expressions that look
  726. // for non-JSON patterns. We are especially concerned with '()' and 'new'
  727. // because they can cause invocation, and '=' because it can cause mutation.
  728. // But just to be safe, we want to reject all unexpected forms.
  729. // We split the second stage into 4 regexp operations in order to work around
  730. // crippling inefficiencies in IE's and Safari's regexp engines. First we
  731. // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  732. // replace all simple value tokens with ']' characters. Third, we delete all
  733. // open brackets that follow a colon or comma or that begin the text. Finally,
  734. // we look to see that the remaining characters are only whitespace or ']' or
  735. // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  736. if (/^[\],:{}\s]*$/
  737. .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  738. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  739. .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  740. // In the third stage we use the eval function to compile the text into a
  741. // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  742. // in JavaScript: it can begin a block or an object literal. We wrap the text
  743. // in parens to eliminate the ambiguity.
  744. j = eval('(' + text + ')');
  745. // In the optional fourth stage, we recursively walk the new structure, passing
  746. // each name/value pair to a reviver function for possible transformation.
  747. return typeof reviver === 'function' ?
  748. walk({'': j}, '') : j;
  749. }
  750. // If the text is not JSON parseable, then a SyntaxError is thrown.
  751. throw new SyntaxError('JSON.parse');
  752. };
  753. })(
  754. 'undefined' != typeof io ? io : module.exports
  755. , typeof JSON !== 'undefined' ? JSON : undefined
  756. );
  757. /**
  758. * socket.io
  759. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  760. * MIT Licensed
  761. */
  762. (function (exports, io) {
  763. /**
  764. * Parser namespace.
  765. *
  766. * @namespace
  767. */
  768. var parser = exports.parser = {};
  769. /**
  770. * Packet types.
  771. */
  772. var packets = parser.packets = [
  773. 'disconnect'
  774. , 'connect'
  775. , 'heartbeat'
  776. , 'message'
  777. , 'json'
  778. , 'event'
  779. , 'ack'
  780. , 'error'
  781. , 'noop'
  782. ];
  783. /**
  784. * Errors reasons.
  785. */
  786. var reasons = parser.reasons = [
  787. 'transport not supported'
  788. , 'client not handshaken'
  789. , 'unauthorized'
  790. ];
  791. /**
  792. * Errors advice.
  793. */
  794. var advice = parser.advice = [
  795. 'reconnect'
  796. ];
  797. /**
  798. * Shortcuts.
  799. */
  800. var JSON = io.JSON
  801. , indexOf = io.util.indexOf;
  802. /**
  803. * Encodes a packet.
  804. *
  805. * @api private
  806. */
  807. parser.encodePacket = function (packet) {
  808. var type = indexOf(packets, packet.type)
  809. , id = packet.id || ''
  810. , endpoint = packet.endpoint || ''
  811. , ack = packet.ack
  812. , data = null;
  813. switch (packet.type) {
  814. case 'error':
  815. var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
  816. , adv = packet.advice ? indexOf(advice, packet.advice) : '';
  817. if (reason !== '' || adv !== '')
  818. data = reason + (adv !== '' ? ('+' + adv) : '');
  819. break;
  820. case 'message':
  821. if (packet.data !== '')
  822. data = packet.data;
  823. break;
  824. case 'event':
  825. var ev = { name: packet.name };
  826. if (packet.args && packet.args.length) {
  827. ev.args = packet.args;
  828. }
  829. data = JSON.stringify(ev);
  830. break;
  831. case 'json':
  832. data = JSON.stringify(packet.data);
  833. break;
  834. case 'connect':
  835. if (packet.qs)
  836. data = packet.qs;
  837. break;
  838. case 'ack':
  839. data = packet.ackId
  840. + (packet.args && packet.args.length
  841. ? '+' + JSON.stringify(packet.args) : '');
  842. break;
  843. }
  844. // construct packet with required fragments
  845. var encoded = [
  846. type
  847. , id + (ack == 'data' ? '+' : '')
  848. , endpoint
  849. ];
  850. // data fragment is optional
  851. if (data !== null && data !== undefined)
  852. encoded.push(data);
  853. return encoded.join(':');
  854. };
  855. /**
  856. * Encodes multiple messages (payload).
  857. *
  858. * @param {Array} messages
  859. * @api private
  860. */
  861. parser.encodePayload = function (packets) {
  862. var decoded = '';
  863. if (packets.length == 1)
  864. return packets[0];
  865. for (var i = 0, l = packets.length; i < l; i++) {
  866. var packet = packets[i];
  867. decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
  868. }
  869. return decoded;
  870. };
  871. /**
  872. * Decodes a packet
  873. *
  874. * @api private
  875. */
  876. var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
  877. parser.decodePacket = function (data) {
  878. var pieces = data.match(regexp);
  879. if (!pieces) return {};
  880. var id = pieces[2] || ''
  881. , data = pieces[5] || ''
  882. , packet = {
  883. type: packets[pieces[1]]
  884. , endpoint: pieces[4] || ''
  885. };
  886. // whether we need to acknowledge the packet
  887. if (id) {
  888. packet.id = id;
  889. if (pieces[3])
  890. packet.ack = 'data';
  891. else
  892. packet.ack = true;
  893. }
  894. // handle different packet types
  895. switch (packet.type) {
  896. case 'error':
  897. var pieces = data.split('+');
  898. packet.reason = reasons[pieces[0]] || '';
  899. packet.advice = advice[pieces[1]] || '';
  900. break;
  901. case 'message':
  902. packet.data = data || '';
  903. break;
  904. case 'event':
  905. try {
  906. var opts = JSON.parse(data);
  907. packet.name = opts.name;
  908. packet.args = opts.args;
  909. } catch (e) { }
  910. packet.args = packet.args || [];
  911. break;
  912. case 'json':
  913. try {
  914. packet.data = JSON.parse(data);
  915. } catch (e) { }
  916. break;
  917. case 'connect':
  918. packet.qs = data || '';
  919. break;
  920. case 'ack':
  921. var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
  922. if (pieces) {
  923. packet.ackId = pieces[1];
  924. packet.args = [];
  925. if (pieces[3]) {
  926. try {
  927. packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
  928. } catch (e) { }
  929. }
  930. }
  931. break;
  932. case 'disconnect':
  933. case 'heartbeat':
  934. break;
  935. };
  936. return packet;
  937. };
  938. /**
  939. * Decodes data payload. Detects multiple messages
  940. *
  941. * @return {Array} messages
  942. * @api public
  943. */
  944. parser.decodePayload = function (data) {
  945. // IE doesn't like data[i] for unicode chars, charAt works fine
  946. if (data.charAt(0) == '\ufffd') {
  947. var ret = [];
  948. for (var i = 1, length = ''; i < data.length; i++) {
  949. if (data.charAt(i) == '\ufffd') {
  950. ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
  951. i += Number(length) + 1;
  952. length = '';
  953. } else {
  954. length += data.charAt(i);
  955. }
  956. }
  957. return ret;
  958. } else {
  959. return [parser.decodePacket(data)];
  960. }
  961. };
  962. })(
  963. 'undefined' != typeof io ? io : module.exports
  964. , 'undefined' != typeof io ? io : module.parent.exports
  965. );
  966. /**
  967. * socket.io
  968. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  969. * MIT Licensed
  970. */
  971. (function (exports, io) {
  972. /**
  973. * Expose constructor.
  974. */
  975. exports.Transport = Transport;
  976. /**
  977. * This is the transport template for all supported transport methods.
  978. *
  979. * @constructor
  980. * @api public
  981. */
  982. function Transport (socket, sessid) {
  983. this.socket = socket;
  984. this.sessid = sessid;
  985. };
  986. /**
  987. * Apply EventEmitter mixin.
  988. */
  989. io.util.mixin(Transport, io.EventEmitter);
  990. /**
  991. * Handles the response from the server. When a new response is received
  992. * it will automatically update the timeout, decode the message and
  993. * forwards the response to the onMessage function for further processing.
  994. *
  995. * @param {String} data Response from the server.
  996. * @api private
  997. */
  998. Transport.prototype.onData = function (data) {
  999. this.clearCloseTimeout();
  1000. this.setCloseTimeout();
  1001. if (data !== '') {
  1002. // todo: we should only do decodePayload for xhr transports
  1003. var msgs = io.parser.decodePayload(data);
  1004. if (msgs && msgs.length) {
  1005. for (var i = 0, l = msgs.length; i < l; i++) {
  1006. this.onPacket(msgs[i]);
  1007. }
  1008. }
  1009. }
  1010. return this;
  1011. };
  1012. /**
  1013. * Handles packets.
  1014. *
  1015. * @api private
  1016. */
  1017. Transport.prototype.onPacket = function (packet) {
  1018. if (packet.type == 'heartbeat') {
  1019. return this.onHeartbeat();
  1020. }
  1021. if (packet.type == 'connect' && packet.endpoint == '') {
  1022. this.onConnect();
  1023. }
  1024. this.socket.onPacket(packet);
  1025. return this;
  1026. };
  1027. /**
  1028. * Sets close timeout
  1029. *
  1030. * @api private
  1031. */
  1032. Transport.prototype.setCloseTimeout = function () {
  1033. if (!this.closeTimeout) {
  1034. var self = this;
  1035. this.closeTimeout = setTimeout(function () {
  1036. self.onDisconnect();
  1037. }, this.socket.closeTimeout);
  1038. }
  1039. };
  1040. /**
  1041. * Called when transport disconnects.
  1042. *
  1043. * @api private
  1044. */
  1045. Transport.prototype.onDisconnect = function () {
  1046. if (this.close) this.close();
  1047. this.clearTimeouts();
  1048. this.socket.onDisconnect();
  1049. return this;
  1050. };
  1051. /**
  1052. * Called when transport connects
  1053. *
  1054. * @api private
  1055. */
  1056. Transport.prototype.onConnect = function () {
  1057. this.socket.onConnect();
  1058. return this;
  1059. }
  1060. /**
  1061. * Clears close timeout
  1062. *
  1063. * @api private
  1064. */
  1065. Transport.prototype.clearCloseTimeout = function () {
  1066. if (this.closeTimeout) {
  1067. clearTimeout(this.closeTimeout);
  1068. this.closeTimeout = null;
  1069. }
  1070. };
  1071. /**
  1072. * Clear timeouts
  1073. *
  1074. * @api private
  1075. */
  1076. Transport.prototype.clearTimeouts = function () {
  1077. this.clearCloseTimeout();
  1078. if (this.reopenTimeout) {
  1079. clearTimeout(this.reopenTimeout);
  1080. }
  1081. };
  1082. /**
  1083. * Sends a packet
  1084. *
  1085. * @param {Object} packet object.
  1086. * @api private
  1087. */
  1088. Transport.prototype.packet = function (packet) {
  1089. this.send(io.parser.encodePacket(packet));
  1090. };
  1091. /**
  1092. * Send the received heartbeat message back to server. So the server
  1093. * knows we are still connected.
  1094. *
  1095. * @param {String} heartbeat Heartbeat response from the server.
  1096. * @api private
  1097. */
  1098. Transport.prototype.onHeartbeat = function (heartbeat) {
  1099. this.packet({ type: 'heartbeat' });
  1100. };
  1101. /**
  1102. * Called when the transport opens.
  1103. *
  1104. * @api private
  1105. */
  1106. Transport.prototype.onOpen = function () {
  1107. this.open = true;
  1108. this.clearCloseTimeout();
  1109. this.socket.onOpen();
  1110. };
  1111. /**
  1112. * Notifies the base when the connection with the Socket.IO server
  1113. * has been disconnected.
  1114. *
  1115. * @api private
  1116. */
  1117. Transport.prototype.onClose = function () {
  1118. var self = this;
  1119. /* FIXME: reopen delay causing a infinit loop
  1120. this.reopenTimeout = setTimeout(function () {
  1121. self.open();
  1122. }, this.socket.options['reopen delay']);*/
  1123. this.open = false;
  1124. this.setCloseTimeout();
  1125. this.socket.onClose();
  1126. };
  1127. /**
  1128. * Generates a connection url based on the Socket.IO URL Protocol.
  1129. * See <https://github.com/learnboost/socket.io-node/> for more details.
  1130. *
  1131. * @returns {String} Connection url
  1132. * @api private
  1133. */
  1134. Transport.prototype.prepareUrl = function () {
  1135. var options = this.socket.options;
  1136. return this.scheme() + '://'
  1137. + options.host + ':' + options.port + '/'
  1138. + options.resource + '/' + io.protocol
  1139. + '/' + this.name + '/' + this.sessid;
  1140. };
  1141. /**
  1142. * Checks if the transport is ready to start a connection.
  1143. *
  1144. * @param {Socket} socket The socket instance that needs a transport
  1145. * @param {Function} fn The callback
  1146. * @api private
  1147. */
  1148. Transport.prototype.ready = function (socket, fn) {
  1149. fn.call(this);
  1150. };
  1151. })(
  1152. 'undefined' != typeof io ? io : module.exports
  1153. , 'undefined' != typeof io ? io : module.parent.exports
  1154. );
  1155. /**
  1156. * socket.io
  1157. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1158. * MIT Licensed
  1159. */
  1160. (function (exports, io, global) {
  1161. /**
  1162. * Expose constructor.
  1163. */
  1164. exports.Socket = Socket;
  1165. /**
  1166. * Create a new `Socket.IO client` which can establish a persistent
  1167. * connection with a Socket.IO enabled server.
  1168. *
  1169. * @api public
  1170. */
  1171. function Socket (options) {
  1172. this.options = {
  1173. port: 80
  1174. , secure: false
  1175. , document: 'document' in global ? document : false
  1176. , resource: 'socket.io'
  1177. , transports: io.transports
  1178. , 'connect timeout': 10000
  1179. , 'try multiple transports': true
  1180. , 'reconnect': true
  1181. , 'reconnection delay': 500
  1182. , 'reconnection limit': Infinity
  1183. , 'reopen delay': 3000
  1184. , 'max reconnection attempts': 10
  1185. , 'sync disconnect on unload': true
  1186. , 'auto connect': true
  1187. , 'flash policy port': 10843
  1188. };
  1189. io.util.merge(this.options, options);
  1190. this.connected = false;
  1191. this.open = false;
  1192. this.connecting = false;
  1193. this.reconnecting = false;
  1194. this.namespaces = {};
  1195. this.buffer = [];
  1196. this.doBuffer = false;
  1197. if (this.options['sync disconnect on unload'] &&
  1198. (!this.isXDomain() || io.util.ua.hasCORS)) {
  1199. var self = this;
  1200. io.util.on(global, 'beforeunload', function () {
  1201. self.disconnectSync();
  1202. }, false);
  1203. }
  1204. if (this.options['auto connect']) {
  1205. this.connect();
  1206. }
  1207. };
  1208. /**
  1209. * Apply EventEmitter mixin.
  1210. */
  1211. io.util.mixin(Socket, io.EventEmitter);
  1212. /**
  1213. * Returns a namespace listener/emitter for this socket
  1214. *
  1215. * @api public
  1216. */
  1217. Socket.prototype.of = function (name) {
  1218. if (!this.namespaces[name]) {
  1219. this.namespaces[name] = new io.SocketNamespace(this, name);
  1220. if (name !== '') {
  1221. this.namespaces[name].packet({ type: 'connect' });
  1222. }
  1223. }
  1224. return this.namespaces[name];
  1225. };
  1226. /**
  1227. * Emits the given event to the Socket and all namespaces
  1228. *
  1229. * @api private
  1230. */
  1231. Socket.prototype.publish = function () {
  1232. this.emit.apply(this, arguments);
  1233. var nsp;
  1234. for (var i in this.namespaces) {
  1235. if (this.namespaces.hasOwnProperty(i)) {
  1236. nsp = this.of(i);
  1237. nsp.$emit.apply(nsp, arguments);
  1238. }
  1239. }
  1240. };
  1241. /**
  1242. * Performs the handshake
  1243. *
  1244. * @api private
  1245. */
  1246. function empty () { };
  1247. Socket.prototype.handshake = function (fn) {
  1248. var self = this
  1249. , options = this.options;
  1250. function complete (data) {
  1251. if (data instanceof Error) {
  1252. self.onError(data.message);
  1253. } else {
  1254. fn.apply(null, data.split(':'));
  1255. }
  1256. };
  1257. var url = [
  1258. 'http' + (options.secure ? 's' : '') + ':/'
  1259. , options.host + ':' + options.port
  1260. , this.options.resource
  1261. , io.protocol
  1262. , io.util.query(this.options.query, 't=' + +new Date)
  1263. ].join('/');
  1264. if (this.isXDomain()) {
  1265. var insertAt = document.getElementsByTagName('script')[0]
  1266. , script = document.createElement('script');
  1267. script.src = url + '&jsonp=' + io.j.length;
  1268. insertAt.parentNode.insertBefore(script, insertAt);
  1269. io.j.push(function (data) {
  1270. complete(data);
  1271. script.parentNode.removeChild(script);
  1272. });
  1273. } else {
  1274. var xhr = io.util.request();
  1275. xhr.open('GET', url, true);
  1276. xhr.onreadystatechange = function () {
  1277. if (xhr.readyState == 4) {
  1278. xhr.onreadystatechange = empty;
  1279. if (xhr.status == 200) {
  1280. complete(xhr.responseText);
  1281. } else {
  1282. !self.reconnecting && self.onError(xhr.responseText);
  1283. }
  1284. }
  1285. };
  1286. xhr.send(null);
  1287. }
  1288. };
  1289. /**
  1290. * Find an available transport based on the options supplied in the constructor.
  1291. *
  1292. * @api private
  1293. */
  1294. Socket.prototype.getTransport = function (override) {
  1295. var transports = override || this.transports, match;
  1296. for (var i = 0, transport; transport = transports[i]; i++) {
  1297. if (io.Transport[transport]
  1298. && io.Transport[transport].check(this)
  1299. && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
  1300. return new io.Transport[transport](this, this.sessionid);
  1301. }
  1302. }
  1303. return null;
  1304. };
  1305. /**
  1306. * Connects to the server.
  1307. *
  1308. * @param {Function} [fn] Callback.
  1309. * @returns {io.Socket}
  1310. * @api public
  1311. */
  1312. Socket.prototype.connect = function (fn) {
  1313. if (this.connecting) {
  1314. return this;
  1315. }
  1316. var self = this;
  1317. this.handshake(function (sid, heartbeat, close, transports) {
  1318. self.sessionid = sid;
  1319. self.closeTimeout = close * 1000;
  1320. self.heartbeatTimeout = heartbeat * 1000;
  1321. self.transports = io.util.intersect(
  1322. transports.split(',')
  1323. , self.options.transports
  1324. );
  1325. function connect (transports){
  1326. if (self.transport) self.transport.clearTimeouts();
  1327. self.transport = self.getTransport(transports);
  1328. if (!self.transport) return self.publish('connect_failed');
  1329. // once the transport is ready
  1330. self.transport.ready(self, function () {
  1331. self.connecting = true;
  1332. self.publish('connecting', self.transport.name);
  1333. self.transport.open();
  1334. if (self.options['connect timeout']) {
  1335. self.connectTimeoutTimer = setTimeout(function () {
  1336. if (!self.connected) {
  1337. self.connecting = false;
  1338. if (self.options['try multiple transports']) {
  1339. if (!self.remainingTransports) {
  1340. self.remainingTransports = self.transports.slice(0);
  1341. }
  1342. var remaining = self.remainingTransports;
  1343. while (remaining.length > 0 && remaining.splice(0,1)[0] !=
  1344. self.transport.name) {}
  1345. if (remaining.length){
  1346. connect(remaining);
  1347. } else {
  1348. self.publish('connect_failed');
  1349. }
  1350. }
  1351. }
  1352. }, self.options['connect timeout']);
  1353. }
  1354. });
  1355. }
  1356. connect();
  1357. self.once('connect', function (){
  1358. clearTimeout(self.connectTimeoutTimer);
  1359. fn && typeof fn == 'function' && fn();
  1360. });
  1361. });
  1362. return this;
  1363. };
  1364. /**
  1365. * Sends a message.
  1366. *
  1367. * @param {Object} data packet.
  1368. * @returns {io.Socket}
  1369. * @api public
  1370. */
  1371. Socket.prototype.packet = function (data) {
  1372. if (this.connected && !this.doBuffer) {
  1373. this.transport.packet(data);
  1374. } else {
  1375. this.buffer.push(data);
  1376. }
  1377. return this;
  1378. };
  1379. /**
  1380. * Sets buffer state
  1381. *
  1382. * @api private
  1383. */
  1384. Socket.prototype.setBuffer = function (v) {
  1385. this.doBuffer = v;
  1386. if (!v && this.connected && this.buffer.length) {
  1387. this.transport.payload(this.buffer);
  1388. this.buffer = [];
  1389. }
  1390. };
  1391. /**
  1392. * Disconnect the established connect.
  1393. *
  1394. * @returns {io.Socket}
  1395. * @api public
  1396. */
  1397. Socket.prototype.disconnect = function () {
  1398. if (this.connected) {
  1399. if (this.open) {
  1400. this.of('').packet({ type: 'disconnect' });
  1401. }
  1402. // handle disconnection immediately
  1403. this.onDisconnect('booted');
  1404. }
  1405. return this;
  1406. };
  1407. /**
  1408. * Disconnects the socket with a sync XHR.
  1409. *
  1410. * @api private
  1411. */
  1412. Socket.prototype.disconnectSync = function () {
  1413. // ensure disconnection
  1414. var xhr = io.util.request()
  1415. , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
  1416. xhr.open('GET', uri, true);
  1417. // handle disconnection immediately
  1418. this.onDisconnect('booted');
  1419. };
  1420. /**
  1421. * Check if we need to use cross domain enabled transports. Cross domain would
  1422. * be a different port or different domain name.
  1423. *
  1424. * @returns {Boolean}
  1425. * @api private
  1426. */
  1427. Socket.prototype.isXDomain = function () {
  1428. var port = window.location.port ||
  1429. ('https:' == window.location.protocol ? 443 : 80);
  1430. return this.options.host !== document.domain || this.options.port != port;
  1431. };
  1432. /**
  1433. * Called upon handshake.
  1434. *
  1435. * @api private
  1436. */
  1437. Socket.prototype.onConnect = function () {
  1438. if (!this.connected) {
  1439. this.connected = true;
  1440. this.connecting = false;
  1441. if (!this.doBuffer) {
  1442. // make sure to flush the buffer
  1443. this.setBuffer(false);
  1444. }
  1445. this.emit('connect');
  1446. }
  1447. };
  1448. /**
  1449. * Called when the transport opens
  1450. *
  1451. * @api private
  1452. */
  1453. Socket.prototype.onOpen = function () {
  1454. this.open = true;
  1455. };
  1456. /**
  1457. * Called when the transport closes.
  1458. *
  1459. * @api private
  1460. */
  1461. Socket.prototype.onClose = function () {
  1462. this.open = false;
  1463. };
  1464. /**
  1465. * Called when the transport first opens a connection
  1466. *
  1467. * @param text
  1468. */
  1469. Socket.prototype.onPacket = function (packet) {
  1470. this.of(packet.endpoint).onPacket(packet);
  1471. };
  1472. /**
  1473. * Handles an error.
  1474. *
  1475. * @api private
  1476. */
  1477. Socket.prototype.onError = function (err) {
  1478. if (err && err.advice) {
  1479. if (err.advice === 'reconnect' && this.connected) {
  1480. this.disconnect();
  1481. this.reconnect();
  1482. }
  1483. }
  1484. this.publish('error', err && err.reason ? err.reason : err);
  1485. };
  1486. /**
  1487. * Called when the transport disconnects.
  1488. *
  1489. * @api private
  1490. */
  1491. Socket.prototype.onDisconnect = function (reason) {
  1492. var wasConnected = this.connected;
  1493. this.connected = false;
  1494. this.connecting = false;
  1495. this.open = false;
  1496. if (wasConnected) {
  1497. this.transport.close();
  1498. this.transport.clearTimeouts();
  1499. this.publish('disconnect', reason);
  1500. if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
  1501. this.reconnect();
  1502. }
  1503. }
  1504. };
  1505. /**
  1506. * Called upon reconnection.
  1507. *
  1508. * @api private
  1509. */
  1510. Socket.prototype.reconnect = function () {
  1511. this.reconnecting = true;
  1512. this.reconnectionAttempts = 0;
  1513. this.reconnectionDelay = this.options['reconnection delay'];
  1514. var self = this
  1515. , maxAttempts = this.options['max reconnection attempts']
  1516. , tryMultiple = this.options['try multiple transports']
  1517. , limit = this.options['reconnection limit'];
  1518. function reset () {
  1519. if (self.connected) {
  1520. for (var i in self.namespaces) {
  1521. if (self.namespaces.hasOwnProperty(i) && '' !== i) {
  1522. self.namespaces[i].packet({ type: 'connect' });
  1523. }
  1524. }
  1525. self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
  1526. }
  1527. self.removeListener('connect_failed', maybeReconnect);
  1528. self.removeListener('connect', maybeReconnect);
  1529. self.reconnecting = false;
  1530. delete self.reconnectionAttempts;
  1531. delete self.reconnectionDelay;
  1532. delete self.reconnectionTimer;
  1533. delete self.redoTransports;
  1534. self.options['try multiple transports'] = tryMultiple;
  1535. };
  1536. function maybeReconnect () {
  1537. if (!self.reconnecting) {
  1538. return;
  1539. }
  1540. if (self.connected) {
  1541. return reset();
  1542. };
  1543. if (self.connecting && self.reconnecting) {
  1544. return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
  1545. }
  1546. if (self.reconnectionAttempts++ >= maxAttempts) {
  1547. if (!self.redoTransports) {
  1548. self.on('connect_failed', maybeReconnect);
  1549. self.options['try multiple transports'] = true;
  1550. self.transport = self.getTransport();
  1551. self.redoTransports = true;
  1552. self.connect();
  1553. } else {
  1554. self.publish('reconnect_failed');
  1555. reset();
  1556. }
  1557. } else {
  1558. if (self.reconnectionDelay < limit) {
  1559. self.reconnectionDelay *= 2; // exponential back off
  1560. }
  1561. self.connect();
  1562. self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
  1563. self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
  1564. }
  1565. };
  1566. this.options['try multiple transports'] = false;
  1567. this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
  1568. this.on('connect', maybeReconnect);
  1569. };
  1570. })(
  1571. 'undefined' != typeof io ? io : module.exports
  1572. , 'undefined' != typeof io ? io : module.parent.exports
  1573. , this
  1574. );
  1575. /**
  1576. * socket.io
  1577. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1578. * MIT Licensed
  1579. */
  1580. (function (exports, io) {
  1581. /**
  1582. * Expose constructor.
  1583. */
  1584. exports.SocketNamespace = SocketNamespace;
  1585. /**
  1586. * Socket namespace constructor.
  1587. *
  1588. * @constructor
  1589. * @api public
  1590. */
  1591. function SocketNamespace (socket, name) {
  1592. this.socket = socket;
  1593. this.name = name || '';
  1594. this.flags = {};
  1595. this.json = new Flag(this, 'json');
  1596. this.ackPackets = 0;
  1597. this.acks = {};
  1598. };
  1599. /**
  1600. * Apply EventEmitter mixin.
  1601. */
  1602. io.util.mixin(SocketNamespace, io.EventEmitter);
  1603. /**
  1604. * Copies emit since we override it
  1605. *
  1606. * @api private
  1607. */
  1608. SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
  1609. /**
  1610. * Creates a new namespace, by proxying the request to the socket. This
  1611. * allows us to use the synax as we do on the server.
  1612. *
  1613. * @api public
  1614. */
  1615. SocketNamespace.prototype.of = function () {
  1616. return this.socket.of.apply(this.socket, arguments);
  1617. };
  1618. /**
  1619. * Sends a packet.
  1620. *
  1621. * @api private
  1622. */
  1623. SocketNamespace.prototype.packet = function (packet) {
  1624. packet.endpoint = this.name;
  1625. this.socket.packet(packet);
  1626. this.flags = {};
  1627. return this;
  1628. };
  1629. /**
  1630. * Sends a message
  1631. *
  1632. * @api public
  1633. */
  1634. SocketNamespace.prototype.send = function (data, fn) {
  1635. var packet = {
  1636. type: this.flags.json ? 'json' : 'message'
  1637. , data: data
  1638. };
  1639. if ('function' == typeof fn) {
  1640. packet.id = ++this.ackPackets;
  1641. packet.ack = true;
  1642. this.acks[packet.id] = fn;
  1643. }
  1644. return this.packet(packet);
  1645. };
  1646. /**
  1647. * Emits an event
  1648. *
  1649. * @api public
  1650. */
  1651. SocketNamespace.prototype.emit = function (name) {
  1652. var args = Array.prototype.slice.call(arguments, 1)
  1653. , lastArg = args[args.length - 1]
  1654. , packet = {
  1655. type: 'event'
  1656. , name: name
  1657. };
  1658. if ('function' == typeof lastArg) {
  1659. packet.id = ++this.ackPackets;
  1660. packet.ack = 'data';
  1661. this.acks[packet.id] = lastArg;
  1662. args = args.slice(0, args.length - 1);
  1663. }
  1664. packet.args = args;
  1665. return this.packet(packet);
  1666. };
  1667. /**
  1668. * Disconnects the namespace
  1669. *
  1670. * @api private
  1671. */
  1672. SocketNamespace.prototype.disconnect = function () {
  1673. if (this.name === '') {
  1674. this.socket.disconnect();
  1675. } else {
  1676. this.packet({ type: 'disconnect' });
  1677. this.$emit('disconnect');
  1678. }
  1679. return this;
  1680. };
  1681. /**
  1682. * Handles a packet
  1683. *
  1684. * @api private
  1685. */
  1686. SocketNamespace.prototype.onPacket = function (packet) {
  1687. var self = this;
  1688. function ack () {
  1689. self.packet({
  1690. type: 'ack'
  1691. , args: io.util.toArray(arguments)
  1692. , ackId: packet.id
  1693. });
  1694. };
  1695. switch (packet.type) {
  1696. case 'connect':
  1697. this.$emit('connect');
  1698. break;
  1699. case 'disconnect':
  1700. if (this.name === '') {
  1701. this.socket.onDisconnect(packet.reason || 'booted');
  1702. } else {
  1703. this.$emit('disconnect', packet.reason);
  1704. }
  1705. break;
  1706. case 'message':
  1707. case 'json':
  1708. var params = ['message', packet.data];
  1709. if (packet.ack == 'data') {
  1710. params.push(ack);
  1711. } else if (packet.ack) {
  1712. this.packet({ type: 'ack', ackId: packet.id });
  1713. }
  1714. this.$emit.apply(this, params);
  1715. break;
  1716. case 'event':
  1717. var params = [packet.name].concat(packet.args);
  1718. if (packet.ack == 'data')
  1719. params.push(ack);
  1720. this.$emit.apply(this, params);
  1721. break;
  1722. case 'ack':
  1723. if (this.acks[packet.ackId]) {
  1724. this.acks[packet.ackId].apply(this, packet.args);
  1725. delete this.acks[packet.ackId];
  1726. }
  1727. break;
  1728. case 'error':
  1729. if (packet.advice){
  1730. this.socket.onError(packet);
  1731. } else {
  1732. if (packet.reason == 'unauthorized') {
  1733. this.$emit('connect_failed', packet.reason);
  1734. } else {
  1735. this.$emit('error', packet.reason);
  1736. }
  1737. }
  1738. break;
  1739. }
  1740. };
  1741. /**
  1742. * Flag interface.
  1743. *
  1744. * @api private
  1745. */
  1746. function Flag (nsp, name) {
  1747. this.namespace = nsp;
  1748. this.name = name;
  1749. };
  1750. /**
  1751. * Send a message
  1752. *
  1753. * @api public
  1754. */
  1755. Flag.prototype.send = function () {
  1756. this.namespace.flags[this.name] = true;
  1757. this.namespace.send.apply(this.namespace, arguments);
  1758. };
  1759. /**
  1760. * Emit an event
  1761. *
  1762. * @api public
  1763. */
  1764. Flag.prototype.emit = function () {
  1765. this.namespace.flags[this.name] = true;
  1766. this.namespace.emit.apply(this.namespace, arguments);
  1767. };
  1768. })(
  1769. 'undefined' != typeof io ? io : module.exports
  1770. , 'undefined' != typeof io ? io : module.parent.exports
  1771. );
  1772. /**
  1773. * socket.io
  1774. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1775. * MIT Licensed
  1776. */
  1777. (function (exports, io) {
  1778. /**
  1779. * Expose constructor.
  1780. */
  1781. exports.websocket = WS;
  1782. /**
  1783. * The WebSocket transport uses the HTML5 WebSocket API to establish an
  1784. * persistent connection with the Socket.IO server. This transport will also
  1785. * be inherited by the FlashSocket fallback as it provides a API compatible
  1786. * polyfill for the WebSockets.
  1787. *
  1788. * @constructor
  1789. * @extends {io.Transport}
  1790. * @api public
  1791. */
  1792. function WS (socket) {
  1793. io.Transport.apply(this, arguments);
  1794. };
  1795. /**
  1796. * Inherits from Transport.
  1797. */
  1798. io.util.inherit(WS, io.Transport);
  1799. /**
  1800. * Transport name
  1801. *
  1802. * @api public
  1803. */
  1804. WS.prototype.name = 'websocket';
  1805. /**
  1806. * Initializes a new `WebSocket` connection with the Socket.IO server. We attach
  1807. * all the appropriate listeners to handle the responses from the server.
  1808. *
  1809. * @returns {Transport}
  1810. * @api public
  1811. */
  1812. WS.prototype.open = function () {
  1813. var query = io.util.query(this.socket.options.query)
  1814. , self = this
  1815. , Socket
  1816. if (!Socket) {
  1817. Socket = window.MozWebSocket || window.WebSocket;
  1818. }
  1819. this.websocket = new Socket(this.prepareUrl() + query);
  1820. this.websocket.onopen = function () {
  1821. self.onOpen();
  1822. self.socket.setBuffer(false);
  1823. };
  1824. this.websocket.onmessage = function (ev) {
  1825. self.onData(ev.data);
  1826. };
  1827. this.websocket.onclose = function () {
  1828. self.onClose();
  1829. self.socket.setBuffer(true);
  1830. };
  1831. this.websocket.onerror = function (e) {
  1832. self.onError(e);
  1833. };
  1834. return this;
  1835. };
  1836. /**
  1837. * Send a message to the Socket.IO server. The message will automatically be
  1838. * encoded in the correct message format.
  1839. *
  1840. * @returns {Transport}
  1841. * @api public
  1842. */
  1843. WS.prototype.send = function (data) {
  1844. this.websocket.send(data);
  1845. return this;
  1846. };
  1847. /**
  1848. * Payload
  1849. *
  1850. * @api private
  1851. */
  1852. WS.prototype.payload = function (arr) {
  1853. for (var i = 0, l = arr.length; i < l; i++) {
  1854. this.packet(arr[i]);
  1855. }
  1856. return this;
  1857. };
  1858. /**
  1859. * Disconnect the established `WebSocket` connection.
  1860. *
  1861. * @returns {Transport}
  1862. * @api public
  1863. */
  1864. WS.prototype.close = function () {
  1865. this.websocket.close();
  1866. return this;
  1867. };
  1868. /**
  1869. * Handle the errors that `WebSocket` might be giving when we
  1870. * are attempting to connect or send messages.
  1871. *
  1872. * @param {Error} e The error.
  1873. * @api private
  1874. */
  1875. WS.prototype.onError = function (e) {
  1876. this.socket.onError(e);
  1877. };
  1878. /**
  1879. * Returns the appropriate scheme for the URI generation.
  1880. *
  1881. * @api private
  1882. */
  1883. WS.prototype.scheme = function () {
  1884. return this.socket.options.secure ? 'wss' : 'ws';
  1885. };
  1886. /**
  1887. * Checks if the browser has support for native `WebSockets` and that
  1888. * it's not the polyfill created for the FlashSocket transport.
  1889. *
  1890. * @return {Boolean}
  1891. * @api public
  1892. */
  1893. WS.check = function () {
  1894. return ('WebSocket' in window && !('__addTask' in WebSocket))
  1895. || 'MozWebSocket' in window;
  1896. };
  1897. /**
  1898. * Check if the `WebSocket` transport support cross domain communications.
  1899. *
  1900. * @returns {Boolean}
  1901. * @api public
  1902. */
  1903. WS.xdomainCheck = function () {
  1904. return true;
  1905. };
  1906. /**
  1907. * Add the transport to your public io.transports array.
  1908. *
  1909. * @api private
  1910. */
  1911. io.transports.push('websocket');
  1912. })(
  1913. 'undefined' != typeof io ? io.Transport : module.exports
  1914. , 'undefined' != typeof io ? io : module.parent.exports
  1915. );
  1916. /**
  1917. * socket.io
  1918. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  1919. * MIT Licensed
  1920. */
  1921. (function (exports, io) {
  1922. /**
  1923. * Expose constructor.
  1924. */
  1925. exports.flashsocket = Flashsocket;
  1926. /**
  1927. * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket
  1928. * specification. It uses a .swf file to communicate with the server. If you want
  1929. * to serve the .swf file from a other server than where the Socket.IO script is
  1930. * coming from you need to use the insecure version of the .swf. More information
  1931. * about this can be found on the github page.
  1932. *
  1933. * @constructor
  1934. * @extends {io.Transport.websocket}
  1935. * @api public
  1936. */
  1937. function Flashsocket () {
  1938. io.Transport.websocket.apply(this, arguments);
  1939. };
  1940. /**
  1941. * Inherits from Transport.
  1942. */
  1943. io.util.inherit(Flashsocket, io.Transport.websocket);
  1944. /**
  1945. * Transport name
  1946. *
  1947. * @api public
  1948. */
  1949. Flashsocket.prototype.name = 'flashsocket';
  1950. /**
  1951. * Disconnect the established `FlashSocket` connection. This is done by adding a
  1952. * new task to the FlashSocket. The rest will be handled off by the `WebSocket`
  1953. * transport.
  1954. *
  1955. * @returns {Transport}
  1956. * @api public
  1957. */
  1958. Flashsocket.prototype.open = function () {
  1959. var self = this
  1960. , args = arguments;
  1961. WebSocket.__addTask(function () {
  1962. io.Transport.websocket.prototype.open.apply(self, args);
  1963. });
  1964. return this;
  1965. };
  1966. /**
  1967. * Sends a message to the Socket.IO server. This is done by adding a new
  1968. * task to the FlashSocket. The rest will be handled off by the `WebSocket`
  1969. * transport.
  1970. *
  1971. * @returns {Transport}
  1972. * @api public
  1973. */
  1974. Flashsocket.prototype.send = function () {
  1975. var self = this, args = arguments;
  1976. WebSocket.__addTask(function () {
  1977. io.Transport.websocket.prototype.send.apply(self, args);
  1978. });
  1979. return this;
  1980. };
  1981. /**
  1982. * Disconnects the established `FlashSocket` connection.
  1983. *
  1984. * @returns {Transport}
  1985. * @api public
  1986. */
  1987. Flashsocket.prototype.close = function () {
  1988. WebSocket.__tasks.length = 0;
  1989. io.Transport.websocket.prototype.close.call(this);
  1990. return this;
  1991. };
  1992. /**
  1993. * The WebSocket fall back needs to append the flash container to the body
  1994. * element, so we need to make sure we have access to it. Or defer the call
  1995. * until we are sure there is a body element.
  1996. *
  1997. * @param {Socket} socket The socket instance that needs a transport
  1998. * @param {Function} fn The callback
  1999. * @api private
  2000. */
  2001. Flashsocket.prototype.ready = function (socket, fn) {
  2002. function init () {
  2003. var options = socket.options
  2004. , port = options['flash policy port']
  2005. , path = [
  2006. 'http' + (options.secure ? 's' : '') + ':/'
  2007. , options.host + ':' + options.port
  2008. , options.resource
  2009. , 'static/flashsocket'
  2010. , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'
  2011. ];
  2012. // Only start downloading the swf file when the checked that this browser
  2013. // actually supports it
  2014. if (!Flashsocket.loaded) {
  2015. if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {
  2016. // Set the correct file based on the XDomain settings
  2017. WEB_SOCKET_SWF_LOCATION = path.join('/');
  2018. }
  2019. if (port !== 843) {
  2020. WebSocket.loadFlashPolicyFile('xmlsocket://' + options.host + ':' + port);
  2021. }
  2022. WebSocket.__initialize();
  2023. Flashsocket.loaded = true;
  2024. }
  2025. fn.call(self);
  2026. }
  2027. var self = this;
  2028. if (document.body) return init();
  2029. io.util.load(init);
  2030. };
  2031. /**
  2032. * Check if the FlashSocket transport is supported as it requires that the Adobe
  2033. * Flash Player plug-in version `10.0.0` or greater is installed. And also check if
  2034. * the polyfill is correctly loaded.
  2035. *
  2036. * @returns {Boolean}
  2037. * @api public
  2038. */
  2039. Flashsocket.check = function () {
  2040. if (
  2041. typeof WebSocket == 'undefined'
  2042. || !('__initialize' in WebSocket) || !swfobject
  2043. ) return false;
  2044. return swfobject.getFlashPlayerVersion().major >= 10;
  2045. };
  2046. /**
  2047. * Check if the FlashSocket transport can be used as cross domain / cross origin
  2048. * transport. Because we can't see which type (secure or insecure) of .swf is used
  2049. * we will just return true.
  2050. *
  2051. * @returns {Boolean}
  2052. * @api public
  2053. */
  2054. Flashsocket.xdomainCheck = function () {
  2055. return true;
  2056. };
  2057. /**
  2058. * Disable AUTO_INITIALIZATION
  2059. */
  2060. if (typeof window != 'undefined') {
  2061. WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;
  2062. }
  2063. /**
  2064. * Add the transport to your public io.transports array.
  2065. *
  2066. * @api private
  2067. */
  2068. io.transports.push('flashsocket');
  2069. })(
  2070. 'undefined' != typeof io ? io.Transport : module.exports
  2071. , 'undefined' != typeof io ? io : module.parent.exports
  2072. );
  2073. /* SWFObject v2.2 <http://code.google.com/p/swfobject/>
  2074. is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
  2075. */
  2076. 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: Hiroshi Ichikawa <http://gimite.net/en/>
  2077. // License: New BSD License
  2078. // Reference: http://dev.w3.org/html5/websockets/
  2079. // Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
  2080. (function() {
  2081. if (window.WebSocket) return;
  2082. var console = window.console;
  2083. if (!console || !console.log || !console.error) {
  2084. console = {log: function(){ }, error: function(){ }};
  2085. }
  2086. if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
  2087. console.error("Flash Player >= 10.0.0 is required.");
  2088. return;
  2089. }
  2090. if (location.protocol == "file:") {
  2091. console.error(
  2092. "WARNING: web-socket-js doesn't work in file:///... URL " +
  2093. "unless you set Flash Security Settings properly. " +
  2094. "Open the page via Web server i.e. http://...");
  2095. }
  2096. /**
  2097. * This class represents a faux web socket.
  2098. * @param {string} url
  2099. * @param {array or string} protocols
  2100. * @param {string} proxyHost
  2101. * @param {int} proxyPort
  2102. * @param {string} headers
  2103. */
  2104. WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
  2105. var self = this;
  2106. self.__id = WebSocket.__nextId++;
  2107. WebSocket.__instances[self.__id] = self;
  2108. self.readyState = WebSocket.CONNECTING;
  2109. self.bufferedAmount = 0;
  2110. self.__events = {};
  2111. if (!protocols) {
  2112. protocols = [];
  2113. } else if (typeof protocols == "string") {
  2114. protocols = [protocols];
  2115. }
  2116. // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
  2117. // Otherwise, when onopen fires immediately, onopen is called before it is set.
  2118. setTimeout(function() {
  2119. WebSocket.__addTask(function() {
  2120. WebSocket.__flash.create(
  2121. self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
  2122. });
  2123. }, 0);
  2124. };
  2125. /**
  2126. * Send data to the web socket.
  2127. * @param {string} data The data to send to the socket.
  2128. * @return {boolean} True for success, false for failure.
  2129. */
  2130. WebSocket.prototype.send = function(data) {
  2131. if (this.readyState == WebSocket.CONNECTING) {
  2132. throw "INVALID_STATE_ERR: Web Socket connection has not been established";
  2133. }
  2134. // We use encodeURIComponent() here, because FABridge doesn't work if
  2135. // the argument includes some characters. We don't use escape() here
  2136. // because of this:
  2137. // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
  2138. // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
  2139. // preserve all Unicode characters either e.g. "\uffff" in Firefox.
  2140. // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
  2141. // additional testing.
  2142. var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
  2143. if (result < 0) { // success
  2144. return true;
  2145. } else {
  2146. this.bufferedAmount += result;
  2147. return false;
  2148. }
  2149. };
  2150. /**
  2151. * Close this web socket gracefully.
  2152. */
  2153. WebSocket.prototype.close = function() {
  2154. if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
  2155. return;
  2156. }
  2157. this.readyState = WebSocket.CLOSING;
  2158. WebSocket.__flash.close(this.__id);
  2159. };
  2160. /**
  2161. * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
  2162. *
  2163. * @param {string} type
  2164. * @param {function} listener
  2165. * @param {boolean} useCapture
  2166. * @return void
  2167. */
  2168. WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
  2169. if (!(type in this.__events)) {
  2170. this.__events[type] = [];
  2171. }
  2172. this.__events[type].push(listener);
  2173. };
  2174. /**
  2175. * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
  2176. *
  2177. * @param {string} type
  2178. * @param {function} listener
  2179. * @param {boolean} useCapture
  2180. * @return void
  2181. */
  2182. WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
  2183. if (!(type in this.__events)) return;
  2184. var events = this.__events[type];
  2185. for (var i = events.length - 1; i >= 0; --i) {
  2186. if (events[i] === listener) {
  2187. events.splice(i, 1);
  2188. break;
  2189. }
  2190. }
  2191. };
  2192. /**
  2193. * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
  2194. *
  2195. * @param {Event} event
  2196. * @return void
  2197. */
  2198. WebSocket.prototype.dispatchEvent = function(event) {
  2199. var events = this.__events[event.type] || [];
  2200. for (var i = 0; i < events.length; ++i) {
  2201. events[i](event);
  2202. }
  2203. var handler = this["on" + event.type];
  2204. if (handler) handler(event);
  2205. };
  2206. /**
  2207. * Handles an event from Flash.
  2208. * @param {Object} flashEvent
  2209. */
  2210. WebSocket.prototype.__handleEvent = function(flashEvent) {
  2211. if ("readyState" in flashEvent) {
  2212. this.readyState = flashEvent.readyState;
  2213. }
  2214. if ("protocol" in flashEvent) {
  2215. this.protocol = flashEvent.protocol;
  2216. }
  2217. var jsEvent;
  2218. if (flashEvent.type == "open" || flashEvent.type == "error") {
  2219. jsEvent = this.__createSimpleEvent(flashEvent.type);
  2220. } else if (flashEvent.type == "close") {
  2221. // TODO implement jsEvent.wasClean
  2222. jsEvent = this.__createSimpleEvent("close");
  2223. } else if (flashEvent.type == "message") {
  2224. var data = decodeURIComponent(flashEvent.message);
  2225. jsEvent = this.__createMessageEvent("message", data);
  2226. } else {
  2227. throw "unknown event type: " + flashEvent.type;
  2228. }
  2229. this.dispatchEvent(jsEvent);
  2230. };
  2231. WebSocket.prototype.__createSimpleEvent = function(type) {
  2232. if (document.createEvent && window.Event) {
  2233. var event = document.createEvent("Event");
  2234. event.initEvent(type, false, false);
  2235. return event;
  2236. } else {
  2237. return {type: type, bubbles: false, cancelable: false};
  2238. }
  2239. };
  2240. WebSocket.prototype.__createMessageEvent = function(type, data) {
  2241. if (document.createEvent && window.MessageEvent && !window.opera) {
  2242. var event = document.createEvent("MessageEvent");
  2243. event.initMessageEvent("message", false, false, data, null, null, window, null);
  2244. return event;
  2245. } else {
  2246. // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
  2247. return {type: type, data: data, bubbles: false, cancelable: false};
  2248. }
  2249. };
  2250. /**
  2251. * Define the WebSocket readyState enumeration.
  2252. */
  2253. WebSocket.CONNECTING = 0;
  2254. WebSocket.OPEN = 1;
  2255. WebSocket.CLOSING = 2;
  2256. WebSocket.CLOSED = 3;
  2257. WebSocket.__flash = null;
  2258. WebSocket.__instances = {};
  2259. WebSocket.__tasks = [];
  2260. WebSocket.__nextId = 0;
  2261. /**
  2262. * Load a new flash security policy file.
  2263. * @param {string} url
  2264. */
  2265. WebSocket.loadFlashPolicyFile = function(url){
  2266. WebSocket.__addTask(function() {
  2267. WebSocket.__flash.loadManualPolicyFile(url);
  2268. });
  2269. };
  2270. /**
  2271. * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
  2272. */
  2273. WebSocket.__initialize = function() {
  2274. if (WebSocket.__flash) return;
  2275. if (WebSocket.__swfLocation) {
  2276. // For backword compatibility.
  2277. window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
  2278. }
  2279. if (!window.WEB_SOCKET_SWF_LOCATION) {
  2280. console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
  2281. return;
  2282. }
  2283. var container = document.createElement("div");
  2284. container.id = "webSocketContainer";
  2285. // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
  2286. // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
  2287. // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
  2288. // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
  2289. // the best we can do as far as we know now.
  2290. container.style.position = "absolute";
  2291. if (WebSocket.__isFlashLite()) {
  2292. container.style.left = "0px";
  2293. container.style.top = "0px";
  2294. } else {
  2295. container.style.left = "-100px";
  2296. container.style.top = "-100px";
  2297. }
  2298. var holder = document.createElement("div");
  2299. holder.id = "webSocketFlash";
  2300. container.appendChild(holder);
  2301. document.body.appendChild(container);
  2302. // See this article for hasPriority:
  2303. // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
  2304. swfobject.embedSWF(
  2305. WEB_SOCKET_SWF_LOCATION,
  2306. "webSocketFlash",
  2307. "1" /* width */,
  2308. "1" /* height */,
  2309. "10.0.0" /* SWF version */,
  2310. null,
  2311. null,
  2312. {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
  2313. null,
  2314. function(e) {
  2315. if (!e.success) {
  2316. console.error("[WebSocket] swfobject.embedSWF failed");
  2317. }
  2318. });
  2319. };
  2320. /**
  2321. * Called by Flash to notify JS that it's fully loaded and ready
  2322. * for communication.
  2323. */
  2324. WebSocket.__onFlashInitialized = function() {
  2325. // We need to set a timeout here to avoid round-trip calls
  2326. // to flash during the initialization process.
  2327. setTimeout(function() {
  2328. WebSocket.__flash = document.getElementById("webSocketFlash");
  2329. WebSocket.__flash.setCallerUrl(location.href);
  2330. WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
  2331. for (var i = 0; i < WebSocket.__tasks.length; ++i) {
  2332. WebSocket.__tasks[i]();
  2333. }
  2334. WebSocket.__tasks = [];
  2335. }, 0);
  2336. };
  2337. /**
  2338. * Called by Flash to notify WebSockets events are fired.
  2339. */
  2340. WebSocket.__onFlashEvent = function() {
  2341. setTimeout(function() {
  2342. try {
  2343. // Gets events using receiveEvents() instead of getting it from event object
  2344. // of Flash event. This is to make sure to keep message order.
  2345. // It seems sometimes Flash events don't arrive in the same order as they are sent.
  2346. var events = WebSocket.__flash.receiveEvents();
  2347. for (var i = 0; i < events.length; ++i) {
  2348. WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
  2349. }
  2350. } catch (e) {
  2351. console.error(e);
  2352. }
  2353. }, 0);
  2354. return true;
  2355. };
  2356. // Called by Flash.
  2357. WebSocket.__log = function(message) {
  2358. console.log(decodeURIComponent(message));
  2359. };
  2360. // Called by Flash.
  2361. WebSocket.__error = function(message) {
  2362. console.error(decodeURIComponent(message));
  2363. };
  2364. WebSocket.__addTask = function(task) {
  2365. if (WebSocket.__flash) {
  2366. task();
  2367. } else {
  2368. WebSocket.__tasks.push(task);
  2369. }
  2370. };
  2371. /**
  2372. * Test if the browser is running flash lite.
  2373. * @return {boolean} True if flash lite is running, false otherwise.
  2374. */
  2375. WebSocket.__isFlashLite = function() {
  2376. if (!window.navigator || !window.navigator.mimeTypes) {
  2377. return false;
  2378. }
  2379. var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
  2380. if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
  2381. return false;
  2382. }
  2383. return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
  2384. };
  2385. if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
  2386. if (window.addEventListener) {
  2387. window.addEventListener("load", function(){
  2388. WebSocket.__initialize();
  2389. }, false);
  2390. } else {
  2391. window.attachEvent("onload", function(){
  2392. WebSocket.__initialize();
  2393. });
  2394. }
  2395. }
  2396. })();
  2397. /**
  2398. * socket.io
  2399. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  2400. * MIT Licensed
  2401. */
  2402. (function (exports, io, global) {
  2403. /**
  2404. * Expose constructor.
  2405. *
  2406. * @api public
  2407. */
  2408. exports.XHR = XHR;
  2409. /**
  2410. * XHR constructor
  2411. *
  2412. * @costructor
  2413. * @api public
  2414. */
  2415. function XHR (socket) {
  2416. if (!socket) return;
  2417. io.Transport.apply(this, arguments);
  2418. this.sendBuffer = [];
  2419. };
  2420. /**
  2421. * Inherits from Transport.
  2422. */
  2423. io.util.inherit(XHR, io.Transport);
  2424. /**
  2425. * Establish a connection
  2426. *
  2427. * @returns {Transport}
  2428. * @api public
  2429. */
  2430. XHR.prototype.open = function () {
  2431. this.socket.setBuffer(false);
  2432. this.onOpen();
  2433. this.get();
  2434. // we need to make sure the request succeeds since we have no indication
  2435. // whether the request opened or not until it succeeded.
  2436. this.setCloseTimeout();
  2437. return this;
  2438. };
  2439. /**
  2440. * Check if we need to send data to the Socket.IO server, if we have data in our
  2441. * buffer we encode it and forward it to the `post` method.
  2442. *
  2443. * @api private
  2444. */
  2445. XHR.prototype.payload = function (payload) {
  2446. var msgs = [];
  2447. for (var i = 0, l = payload.length; i < l; i++) {
  2448. msgs.push(io.parser.encodePacket(payload[i]));
  2449. }
  2450. this.send(io.parser.encodePayload(msgs));
  2451. };
  2452. /**
  2453. * Send data to the Socket.IO server.
  2454. *
  2455. * @param data The message
  2456. * @returns {Transport}
  2457. * @api public
  2458. */
  2459. XHR.prototype.send = function (data) {
  2460. this.post(data);
  2461. return this;
  2462. };
  2463. /**
  2464. * Posts a encoded message to the Socket.IO server.
  2465. *
  2466. * @param {String} data A encoded message.
  2467. * @api private
  2468. */
  2469. function empty () { };
  2470. XHR.prototype.post = function (data) {
  2471. var self = this;
  2472. this.socket.setBuffer(true);
  2473. function stateChange () {
  2474. if (this.readyState == 4) {
  2475. this.onreadystatechange = empty;
  2476. self.posting = false;
  2477. if (this.status == 200){
  2478. self.socket.setBuffer(false);
  2479. } else {
  2480. self.onClose();
  2481. }
  2482. }
  2483. }
  2484. function onload () {
  2485. this.onload = empty;
  2486. self.socket.setBuffer(false);
  2487. };
  2488. this.sendXHR = this.request('POST');
  2489. if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {
  2490. this.sendXHR.onload = this.sendXHR.onerror = onload;
  2491. } else {
  2492. this.sendXHR.onreadystatechange = stateChange;
  2493. }
  2494. this.sendXHR.send(data);
  2495. };
  2496. /**
  2497. * Disconnects the established `XHR` connection.
  2498. *
  2499. * @returns {Transport}
  2500. * @api public
  2501. */
  2502. XHR.prototype.close = function () {
  2503. this.onClose();
  2504. return this;
  2505. };
  2506. /**
  2507. * Generates a configured XHR request
  2508. *
  2509. * @param {String} url The url that needs to be requested.
  2510. * @param {String} method The method the request should use.
  2511. * @returns {XMLHttpRequest}
  2512. * @api private
  2513. */
  2514. XHR.prototype.request = function (method) {
  2515. var req = io.util.request(this.socket.isXDomain())
  2516. , query = io.util.query(this.socket.options.query, 't=' + +new Date);
  2517. req.open(method || 'GET', this.prepareUrl() + query, true);
  2518. if (method == 'POST') {
  2519. try {
  2520. if (req.setRequestHeader) {
  2521. req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
  2522. } else {
  2523. // XDomainRequest
  2524. req.contentType = 'text/plain';
  2525. }
  2526. } catch (e) {}
  2527. }
  2528. return req;
  2529. };
  2530. /**
  2531. * Returns the scheme to use for the transport URLs.
  2532. *
  2533. * @api private
  2534. */
  2535. XHR.prototype.scheme = function () {
  2536. return this.socket.options.secure ? 'https' : 'http';
  2537. };
  2538. /**
  2539. * Check if the XHR transports are supported
  2540. *
  2541. * @param {Boolean} xdomain Check if we support cross domain requests.
  2542. * @returns {Boolean}
  2543. * @api public
  2544. */
  2545. XHR.check = function (socket, xdomain) {
  2546. try {
  2547. if (io.util.request(xdomain)) {
  2548. return true;
  2549. }
  2550. } catch(e) {}
  2551. return false;
  2552. };
  2553. /**
  2554. * Check if the XHR transport supports corss domain requests.
  2555. *
  2556. * @returns {Boolean}
  2557. * @api public
  2558. */
  2559. XHR.xdomainCheck = function () {
  2560. return XHR.check(null, true);
  2561. };
  2562. })(
  2563. 'undefined' != typeof io ? io.Transport : module.exports
  2564. , 'undefined' != typeof io ? io : module.parent.exports
  2565. , this
  2566. );
  2567. /**
  2568. * socket.io
  2569. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  2570. * MIT Licensed
  2571. */
  2572. (function (exports, io) {
  2573. /**
  2574. * Expose constructor.
  2575. */
  2576. exports.htmlfile = HTMLFile;
  2577. /**
  2578. * The HTMLFile transport creates a `forever iframe` based transport
  2579. * for Internet Explorer. Regular forever iframe implementations will
  2580. * continuously trigger the browsers buzy indicators. If the forever iframe
  2581. * is created inside a `htmlfile` these indicators will not be trigged.
  2582. *
  2583. * @constructor
  2584. * @extends {io.Transport.XHR}
  2585. * @api public
  2586. */
  2587. function HTMLFile (socket) {
  2588. io.Transport.XHR.apply(this, arguments);
  2589. };
  2590. /**
  2591. * Inherits from XHR transport.
  2592. */
  2593. io.util.inherit(HTMLFile, io.Transport.XHR);
  2594. /**
  2595. * Transport name
  2596. *
  2597. * @api public
  2598. */
  2599. HTMLFile.prototype.name = 'htmlfile';
  2600. /**
  2601. * Creates a new ActiveX `htmlfile` with a forever loading iframe
  2602. * that can be used to listen to messages. Inside the generated
  2603. * `htmlfile` a reference will be made to the HTMLFile transport.
  2604. *
  2605. * @api private
  2606. */
  2607. HTMLFile.prototype.get = function () {
  2608. this.doc = new ActiveXObject('htmlfile');
  2609. this.doc.open();
  2610. this.doc.write('<html></html>');
  2611. this.doc.close();
  2612. this.doc.parentWindow.s = this;
  2613. var iframeC = this.doc.createElement('div');
  2614. iframeC.className = 'socketio';
  2615. this.doc.body.appendChild(iframeC);
  2616. this.iframe = this.doc.createElement('iframe');
  2617. iframeC.appendChild(this.iframe);
  2618. var self = this
  2619. , query = io.util.query(this.socket.options.query, 't='+ +new Date);
  2620. this.iframe.src = this.prepareUrl() + query;
  2621. io.util.on(window, 'unload', function () {
  2622. self.destroy();
  2623. });
  2624. };
  2625. /**
  2626. * The Socket.IO server will write script tags inside the forever
  2627. * iframe, this function will be used as callback for the incoming
  2628. * information.
  2629. *
  2630. * @param {String} data The message
  2631. * @param {document} doc Reference to the context
  2632. * @api private
  2633. */
  2634. HTMLFile.prototype._ = function (data, doc) {
  2635. this.onData(data);
  2636. try {
  2637. var script = doc.getElementsByTagName('script')[0];
  2638. script.parentNode.removeChild(script);
  2639. } catch (e) { }
  2640. };
  2641. /**
  2642. * Destroy the established connection, iframe and `htmlfile`.
  2643. * And calls the `CollectGarbage` function of Internet Explorer
  2644. * to release the memory.
  2645. *
  2646. * @api private
  2647. */
  2648. HTMLFile.prototype.destroy = function () {
  2649. if (this.iframe){
  2650. try {
  2651. this.iframe.src = 'about:blank';
  2652. } catch(e){}
  2653. this.doc = null;
  2654. this.iframe.parentNode.removeChild(this.iframe);
  2655. this.iframe = null;
  2656. CollectGarbage();
  2657. }
  2658. };
  2659. /**
  2660. * Disconnects the established connection.
  2661. *
  2662. * @returns {Transport} Chaining.
  2663. * @api public
  2664. */
  2665. HTMLFile.prototype.close = function () {
  2666. this.destroy();
  2667. return io.Transport.XHR.prototype.close.call(this);
  2668. };
  2669. /**
  2670. * Checks if the browser supports this transport. The browser
  2671. * must have an `ActiveXObject` implementation.
  2672. *
  2673. * @return {Boolean}
  2674. * @api public
  2675. */
  2676. HTMLFile.check = function () {
  2677. if ('ActiveXObject' in window){
  2678. try {
  2679. var a = new ActiveXObject('htmlfile');
  2680. return a && io.Transport.XHR.check();
  2681. } catch(e){}
  2682. }
  2683. return false;
  2684. };
  2685. /**
  2686. * Check if cross domain requests are supported.
  2687. *
  2688. * @returns {Boolean}
  2689. * @api public
  2690. */
  2691. HTMLFile.xdomainCheck = function () {
  2692. // we can probably do handling for sub-domains, we should
  2693. // test that it's cross domain but a subdomain here
  2694. return false;
  2695. };
  2696. /**
  2697. * Add the transport to your public io.transports array.
  2698. *
  2699. * @api private
  2700. */
  2701. io.transports.push('htmlfile');
  2702. })(
  2703. 'undefined' != typeof io ? io.Transport : module.exports
  2704. , 'undefined' != typeof io ? io : module.parent.exports
  2705. );
  2706. /**
  2707. * socket.io
  2708. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  2709. * MIT Licensed
  2710. */
  2711. (function (exports, io, global) {
  2712. /**
  2713. * Expose constructor.
  2714. */
  2715. exports['xhr-polling'] = XHRPolling;
  2716. /**
  2717. * The XHR-polling transport uses long polling XHR requests to create a
  2718. * "persistent" connection with the server.
  2719. *
  2720. * @constructor
  2721. * @api public
  2722. */
  2723. function XHRPolling () {
  2724. io.Transport.XHR.apply(this, arguments);
  2725. };
  2726. /**
  2727. * Inherits from XHR transport.
  2728. */
  2729. io.util.inherit(XHRPolling, io.Transport.XHR);
  2730. /**
  2731. * Merge the properties from XHR transport
  2732. */
  2733. io.util.merge(XHRPolling, io.Transport.XHR);
  2734. /**
  2735. * Transport name
  2736. *
  2737. * @api public
  2738. */
  2739. XHRPolling.prototype.name = 'xhr-polling';
  2740. /**
  2741. * Establish a connection, for iPhone and Android this will be done once the page
  2742. * is loaded.
  2743. *
  2744. * @returns {Transport} Chaining.
  2745. * @api public
  2746. */
  2747. XHRPolling.prototype.open = function () {
  2748. var self = this;
  2749. io.Transport.XHR.prototype.open.call(self);
  2750. return false;
  2751. };
  2752. /**
  2753. * Starts a XHR request to wait for incoming messages.
  2754. *
  2755. * @api private
  2756. */
  2757. function empty () {};
  2758. XHRPolling.prototype.get = function () {
  2759. if (!this.open) return;
  2760. var self = this;
  2761. function stateChange () {
  2762. if (this.readyState == 4) {
  2763. this.onreadystatechange = empty;
  2764. if (this.status == 200) {
  2765. self.onData(this.responseText);
  2766. self.get();
  2767. } else {
  2768. self.onClose();
  2769. }
  2770. }
  2771. };
  2772. function onload () {
  2773. this.onload = empty;
  2774. self.onData(this.responseText);
  2775. self.get();
  2776. };
  2777. this.xhr = this.request();
  2778. if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {
  2779. this.xhr.onload = this.xhr.onerror = onload;
  2780. } else {
  2781. this.xhr.onreadystatechange = stateChange;
  2782. }
  2783. this.xhr.send(null);
  2784. };
  2785. /**
  2786. * Handle the unclean close behavior.
  2787. *
  2788. * @api private
  2789. */
  2790. XHRPolling.prototype.onClose = function () {
  2791. io.Transport.XHR.prototype.onClose.call(this);
  2792. if (this.xhr) {
  2793. this.xhr.onreadystatechange = this.xhr.onload = empty;
  2794. try {
  2795. this.xhr.abort();
  2796. } catch(e){}
  2797. this.xhr = null;
  2798. }
  2799. };
  2800. /**
  2801. * Webkit based browsers show a infinit spinner when you start a XHR request
  2802. * before the browsers onload event is called so we need to defer opening of
  2803. * the transport until the onload event is called. Wrapping the cb in our
  2804. * defer method solve this.
  2805. *
  2806. * @param {Socket} socket The socket instance that needs a transport
  2807. * @param {Function} fn The callback
  2808. * @api private
  2809. */
  2810. XHRPolling.prototype.ready = function (socket, fn) {
  2811. var self = this;
  2812. io.util.defer(function () {
  2813. fn.call(self);
  2814. });
  2815. };
  2816. /**
  2817. * Add the transport to your public io.transports array.
  2818. *
  2819. * @api private
  2820. */
  2821. io.transports.push('xhr-polling');
  2822. })(
  2823. 'undefined' != typeof io ? io.Transport : module.exports
  2824. , 'undefined' != typeof io ? io : module.parent.exports
  2825. , this
  2826. );
  2827. /**
  2828. * socket.io
  2829. * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
  2830. * MIT Licensed
  2831. */
  2832. (function (exports, io) {
  2833. /**
  2834. * Expose constructor.
  2835. */
  2836. exports['jsonp-polling'] = JSONPPolling;
  2837. /**
  2838. * The JSONP transport creates an persistent connection by dynamically
  2839. * inserting a script tag in the page. This script tag will receive the
  2840. * information of the Socket.IO server. When new information is received
  2841. * it creates a new script tag for the new data stream.
  2842. *
  2843. * @constructor
  2844. * @extends {io.Transport.xhr-polling}
  2845. * @api public
  2846. */
  2847. function JSONPPolling (socket) {
  2848. io.Transport['xhr-polling'].apply(this, arguments);
  2849. this.index = io.j.length;
  2850. var self = this;
  2851. io.j.push(function (msg) {
  2852. self._(msg);
  2853. });
  2854. };
  2855. /**
  2856. * Inherits from XHR polling transport.
  2857. */
  2858. io.util.inherit(JSONPPolling, io.Transport['xhr-polling']);
  2859. /**
  2860. * Transport name
  2861. *
  2862. * @api public
  2863. */
  2864. JSONPPolling.prototype.name = 'jsonp-polling';
  2865. /**
  2866. * Posts a encoded message to the Socket.IO server using an iframe.
  2867. * The iframe is used because script tags can create POST based requests.
  2868. * The iframe is positioned outside of the view so the user does not
  2869. * notice it's existence.
  2870. *
  2871. * @param {String} data A encoded message.
  2872. * @api private
  2873. */
  2874. JSONPPolling.prototype.post = function (data) {
  2875. var self = this
  2876. , query = io.util.query(
  2877. this.socket.options.query
  2878. , 't='+ (+new Date) + '&i=' + this.index
  2879. );
  2880. if (!this.form) {
  2881. var form = document.createElement('form')
  2882. , area = document.createElement('textarea')
  2883. , id = this.iframeId = 'socketio_iframe_' + this.index
  2884. , iframe;
  2885. form.className = 'socketio';
  2886. form.style.position = 'absolute';
  2887. form.style.top = '-1000px';
  2888. form.style.left = '-1000px';
  2889. form.target = id;
  2890. form.method = 'POST';
  2891. form.setAttribute('accept-charset', 'utf-8');
  2892. area.name = 'd';
  2893. form.appendChild(area);
  2894. document.body.appendChild(form);
  2895. this.form = form;
  2896. this.area = area;
  2897. }
  2898. this.form.action = this.prepareUrl() + query;
  2899. function complete () {
  2900. initIframe();
  2901. self.socket.setBuffer(false);
  2902. };
  2903. function initIframe () {
  2904. if (self.iframe) {
  2905. self.form.removeChild(self.iframe);
  2906. }
  2907. try {
  2908. // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
  2909. iframe = document.createElement('<iframe name="'+ self.iframeId +'">');
  2910. } catch (e) {
  2911. iframe = document.createElement('iframe');
  2912. iframe.name = self.iframeId;
  2913. }
  2914. iframe.id = self.iframeId;
  2915. self.form.appendChild(iframe);
  2916. self.iframe = iframe;
  2917. };
  2918. initIframe();
  2919. this.area.value = data;
  2920. try {
  2921. this.form.submit();
  2922. } catch(e) {}
  2923. if (this.iframe.attachEvent) {
  2924. iframe.onreadystatechange = function () {
  2925. if (self.iframe.readyState == 'complete') {
  2926. complete();
  2927. }
  2928. };
  2929. } else {
  2930. this.iframe.onload = complete;
  2931. }
  2932. this.socket.setBuffer(true);
  2933. };
  2934. /**
  2935. * Creates a new JSONP poll that can be used to listen
  2936. * for messages from the Socket.IO server.
  2937. *
  2938. * @api private
  2939. */
  2940. JSONPPolling.prototype.get = function () {
  2941. var self = this
  2942. , script = document.createElement('script')
  2943. , query = io.util.query(
  2944. this.socket.options.query
  2945. , 't='+ (+new Date) + '&i=' + this.index
  2946. );
  2947. if (this.script) {
  2948. this.script.parentNode.removeChild(this.script);
  2949. this.script = null;
  2950. }
  2951. script.async = true;
  2952. script.src = this.prepareUrl() + query;
  2953. script.onerror = function () {
  2954. self.onClose();
  2955. };
  2956. var insertAt = document.getElementsByTagName('script')[0]
  2957. insertAt.parentNode.insertBefore(script, insertAt);
  2958. this.script = script;
  2959. };
  2960. /**
  2961. * Callback function for the incoming message stream from the Socket.IO server.
  2962. *
  2963. * @param {String} data The message
  2964. * @api private
  2965. */
  2966. JSONPPolling.prototype._ = function (msg) {
  2967. this.onData(msg);
  2968. if (this.open) {
  2969. this.get();
  2970. }
  2971. return this;
  2972. };
  2973. /**
  2974. * Checks if browser supports this transport.
  2975. *
  2976. * @return {Boolean}
  2977. * @api public
  2978. */
  2979. JSONPPolling.check = function () {
  2980. return true;
  2981. };
  2982. /**
  2983. * Check if cross domain requests are supported
  2984. *
  2985. * @returns {Boolean}
  2986. * @api public
  2987. */
  2988. JSONPPolling.xdomainCheck = function () {
  2989. return true;
  2990. };
  2991. /**
  2992. * Add the transport to your public io.transports array.
  2993. *
  2994. * @api private
  2995. */
  2996. io.transports.push('jsonp-polling');
  2997. })(
  2998. 'undefined' != typeof io ? io.Transport : module.exports
  2999. , 'undefined' != typeof io ? io : module.parent.exports
  3000. );