PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/socket.io.js

https://github.com/TakumiBaba/callForwardingExtension
JavaScript | 2598 lines | 2225 code | 146 blank | 227 comment | 108 complexity | 9dab974d1106e796548647dd91186440 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*! Socket.IO.js build:0.8.5, 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.5';
  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 <d…

Large files files are truncated, but you can click here to view the full file