PageRenderTime 11ms CodeModel.GetById 3ms app.highlight 48ms RepoModel.GetById 11ms 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/**
   4 * socket.io
   5 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
   6 * MIT Licensed
   7 */
   8
   9(function (exports) {
  10
  11  /**
  12   * IO namespace.
  13   *
  14   * @namespace
  15   */
  16
  17  var io = exports;
  18
  19  /**
  20   * Socket.IO version
  21   *
  22   * @api public
  23   */
  24
  25  io.version = '0.8.5';
  26
  27  /**
  28   * Protocol implemented.
  29   *
  30   * @api public
  31   */
  32
  33  io.protocol = 1;
  34
  35  /**
  36   * Available transports, these will be populated with the available transports
  37   *
  38   * @api public
  39   */
  40
  41  io.transports = [];
  42
  43  /**
  44   * Keep track of jsonp callbacks.
  45   *
  46   * @api private
  47   */
  48
  49  io.j = [];
  50
  51  /**
  52   * Keep track of our io.Sockets
  53   *
  54   * @api private
  55   */
  56  io.sockets = {};
  57
  58
  59  /**
  60   * Manages connections to hosts.
  61   *
  62   * @param {String} uri
  63   * @Param {Boolean} force creation of new socket (defaults to false)
  64   * @api public
  65   */
  66
  67  io.connect = function (host, details) {
  68    var uri = io.util.parseUri(host)
  69      , uuri
  70      , socket;
  71
  72    if ('undefined' != typeof document) {
  73      uri.protocol = uri.protocol || document.location.protocol.slice(0, -1);
  74      uri.host = uri.host || document.domain;
  75      uri.port = uri.port || document.location.port;
  76    }
  77
  78    uuri = io.util.uniqueUri(uri);
  79
  80    var options = {
  81        host: uri.host
  82      , secure: 'https' == uri.protocol
  83      , port: uri.port || ('https' == uri.protocol ? 443 : 80)
  84      , query: uri.query || ''
  85    };
  86
  87    io.util.merge(options, details);
  88
  89    if (options['force new connection'] || !io.sockets[uuri]) {
  90      socket = new io.Socket(options);
  91    }
  92
  93    if (!options['force new connection'] && socket) {
  94      io.sockets[uuri] = socket;
  95    }
  96
  97    socket = socket || io.sockets[uuri];
  98
  99    // if path is different from '' or /
 100    return socket.of(uri.path.length > 1 ? uri.path : '');
 101  };
 102
 103})('object' === typeof module ? module.exports : (window.io = {}));
 104
 105/**
 106 * socket.io
 107 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 108 * MIT Licensed
 109 */
 110
 111(function (exports, global) {
 112
 113  /**
 114   * Utilities namespace.
 115   *
 116   * @namespace
 117   */
 118
 119  var util = exports.util = {};
 120
 121  /**
 122   * Parses an URI
 123   *
 124   * @author Steven Levithan <stevenlevithan.com> (MIT license)
 125   * @api public
 126   */
 127
 128  var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
 129
 130  var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
 131               'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
 132               'anchor'];
 133
 134  util.parseUri = function (str) {
 135    var m = re.exec(str || '')
 136      , uri = {}
 137      , i = 14;
 138
 139    while (i--) {
 140      uri[parts[i]] = m[i] || '';
 141    }
 142
 143    return uri;
 144  };
 145
 146  /**
 147   * Produces a unique url that identifies a Socket.IO connection.
 148   *
 149   * @param {Object} uri
 150   * @api public
 151   */
 152
 153  util.uniqueUri = function (uri) {
 154    var protocol = uri.protocol
 155      , host = uri.host
 156      , port = uri.port;
 157
 158    if ('document' in global) {
 159      host = host || document.domain;
 160      port = port || (protocol == 'https'
 161        && document.location.protocol !== 'https:' ? 443 : document.location.port);
 162    } else {
 163      host = host || 'localhost';
 164
 165      if (!port && protocol == 'https') {
 166        port = 443;
 167      }
 168    }
 169
 170    return (protocol || 'http') + '://' + host + ':' + (port || 80);
 171  };
 172
 173  /**
 174   * Mergest 2 query strings in to once unique query string
 175   *
 176   * @param {String} base
 177   * @param {String} addition
 178   * @api public
 179   */
 180
 181  util.query = function (base, addition) {
 182    var query = util.chunkQuery(base || '')
 183      , components = [];
 184
 185    util.merge(query, util.chunkQuery(addition || ''));
 186    for (var part in query) {
 187      if (query.hasOwnProperty(part)) {
 188        components.push(part + '=' + query[part]);
 189      }
 190    }
 191
 192    return components.length ? '?' + components.join('&') : '';
 193  };
 194
 195  /**
 196   * Transforms a querystring in to an object
 197   *
 198   * @param {String} qs
 199   * @api public
 200   */
 201
 202  util.chunkQuery = function (qs) {
 203    var query = {}
 204      , params = qs.split('&')
 205      , i = 0
 206      , l = params.length
 207      , kv;
 208
 209    for (; i < l; ++i) {
 210      kv = params[i].split('=');
 211      if (kv[0]) {
 212        query[kv[0]] = decodeURIComponent(kv[1]);
 213      }
 214    }
 215
 216    return query;
 217  };
 218
 219  /**
 220   * Executes the given function when the page is loaded.
 221   *
 222   *     io.util.load(function () { console.log('page loaded'); });
 223   *
 224   * @param {Function} fn
 225   * @api public
 226   */
 227
 228  var pageLoaded = false;
 229
 230  util.load = function (fn) {
 231    if ('document' in global && document.readyState === 'complete' || pageLoaded) {
 232      return fn();
 233    }
 234
 235    util.on(global, 'load', fn, false);
 236  };
 237
 238  /**
 239   * Adds an event.
 240   *
 241   * @api private
 242   */
 243
 244  util.on = function (element, event, fn, capture) {
 245    if (element.attachEvent) {
 246      element.attachEvent('on' + event, fn);
 247    } else if (element.addEventListener) {
 248      element.addEventListener(event, fn, capture);
 249    }
 250  };
 251
 252  /**
 253   * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
 254   *
 255   * @param {Boolean} [xdomain] Create a request that can be used cross domain.
 256   * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
 257   * @api private
 258   */
 259
 260  util.request = function (xdomain) {
 261
 262    if ('undefined' != typeof window) {
 263      if (xdomain && window.XDomainRequest) {
 264        return new XDomainRequest();
 265      }
 266
 267      if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
 268        return new XMLHttpRequest();
 269      }
 270
 271      if (!xdomain) {
 272        try {
 273          return new window.ActiveXObject('Microsoft.XMLHTTP');
 274        } catch(e) { }
 275      }
 276    }
 277
 278    return null;
 279  };
 280
 281  /**
 282   * XHR based transport constructor.
 283   *
 284   * @constructor
 285   * @api public
 286   */
 287
 288  /**
 289   * Change the internal pageLoaded value.
 290   */
 291
 292  if ('undefined' != typeof window) {
 293    util.load(function () {
 294      pageLoaded = true;
 295    });
 296  }
 297
 298  /**
 299   * Defers a function to ensure a spinner is not displayed by the browser
 300   *
 301   * @param {Function} fn
 302   * @api public
 303   */
 304
 305  util.defer = function (fn) {
 306    if (!util.ua.webkit) {
 307      return fn();
 308    }
 309
 310    util.load(function () {
 311      setTimeout(fn, 100);
 312    });
 313  };
 314
 315  /**
 316   * Merges two objects.
 317   *
 318   * @api public
 319   */
 320  
 321  util.merge = function merge (target, additional, deep, lastseen) {
 322    var seen = lastseen || []
 323      , depth = typeof deep == 'undefined' ? 2 : deep
 324      , prop;
 325
 326    for (prop in additional) {
 327      if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
 328        if (typeof target[prop] !== 'object' || !depth) {
 329          target[prop] = additional[prop];
 330          seen.push(additional[prop]);
 331        } else {
 332          util.merge(target[prop], additional[prop], depth - 1, seen);
 333        }
 334      }
 335    }
 336
 337    return target;
 338  };
 339
 340  /**
 341   * Merges prototypes from objects
 342   *
 343   * @api public
 344   */
 345  
 346  util.mixin = function (ctor, ctor2) {
 347    util.merge(ctor.prototype, ctor2.prototype);
 348  };
 349
 350  /**
 351   * Shortcut for prototypical and static inheritance.
 352   *
 353   * @api private
 354   */
 355
 356  util.inherit = function (ctor, ctor2) {
 357    function f() {};
 358    f.prototype = ctor2.prototype;
 359    ctor.prototype = new f;
 360  };
 361
 362  /**
 363   * Checks if the given object is an Array.
 364   *
 365   *     io.util.isArray([]); // true
 366   *     io.util.isArray({}); // false
 367   *
 368   * @param Object obj
 369   * @api public
 370   */
 371
 372  util.isArray = Array.isArray || function (obj) {
 373    return Object.prototype.toString.call(obj) === '[object Array]';
 374  };
 375
 376  /**
 377   * Intersects values of two arrays into a third
 378   *
 379   * @api public
 380   */
 381
 382  util.intersect = function (arr, arr2) {
 383    var ret = []
 384      , longest = arr.length > arr2.length ? arr : arr2
 385      , shortest = arr.length > arr2.length ? arr2 : arr;
 386
 387    for (var i = 0, l = shortest.length; i < l; i++) {
 388      if (~util.indexOf(longest, shortest[i]))
 389        ret.push(shortest[i]);
 390    }
 391
 392    return ret;
 393  }
 394
 395  /**
 396   * Array indexOf compatibility.
 397   *
 398   * @see bit.ly/a5Dxa2
 399   * @api public
 400   */
 401
 402  util.indexOf = function (arr, o, i) {
 403    if (Array.prototype.indexOf) {
 404      return Array.prototype.indexOf.call(arr, o, i);
 405    }
 406
 407    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0; 
 408         i < j && arr[i] !== o; i++);
 409
 410    return j <= i ? -1 : i;
 411  };
 412
 413  /**
 414   * Converts enumerables to array.
 415   *
 416   * @api public
 417   */
 418
 419  util.toArray = function (enu) {
 420    var arr = [];
 421
 422    for (var i = 0, l = enu.length; i < l; i++)
 423      arr.push(enu[i]);
 424
 425    return arr;
 426  };
 427
 428  /**
 429   * UA / engines detection namespace.
 430   *
 431   * @namespace
 432   */
 433
 434  util.ua = {};
 435
 436  /**
 437   * Whether the UA supports CORS for XHR.
 438   *
 439   * @api public
 440   */
 441
 442  util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
 443  (function () {
 444    try {
 445      var a = new XMLHttpRequest();
 446    } catch (e) {
 447      return false;
 448    }
 449
 450    return a.withCredentials != undefined;
 451  })();
 452
 453  /**
 454   * Detect webkit.
 455   *
 456   * @api public
 457   */
 458
 459  util.ua.webkit = 'undefined' != typeof navigator
 460    && /webkit/i.test(navigator.userAgent);
 461
 462})(
 463    'undefined' != typeof window ? io : module.exports
 464  , this
 465);
 466
 467/**
 468 * socket.io
 469 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 470 * MIT Licensed
 471 */
 472
 473(function (exports, io) {
 474
 475  /**
 476   * Expose constructor.
 477   */
 478
 479  exports.EventEmitter = EventEmitter;
 480
 481  /**
 482   * Event emitter constructor.
 483   *
 484   * @api public.
 485   */
 486
 487  function EventEmitter () {};
 488
 489  /**
 490   * Adds a listener
 491   *
 492   * @api public
 493   */
 494
 495  EventEmitter.prototype.on = function (name, fn) {
 496    if (!this.$events) {
 497      this.$events = {};
 498    }
 499
 500    if (!this.$events[name]) {
 501      this.$events[name] = fn;
 502    } else if (io.util.isArray(this.$events[name])) {
 503      this.$events[name].push(fn);
 504    } else {
 505      this.$events[name] = [this.$events[name], fn];
 506    }
 507
 508    return this;
 509  };
 510
 511  EventEmitter.prototype.addListener = EventEmitter.prototype.on;
 512
 513  /**
 514   * Adds a volatile listener.
 515   *
 516   * @api public
 517   */
 518
 519  EventEmitter.prototype.once = function (name, fn) {
 520    var self = this;
 521
 522    function on () {
 523      self.removeListener(name, on);
 524      fn.apply(this, arguments);
 525    };
 526
 527    on.listener = fn;
 528    this.on(name, on);
 529
 530    return this;
 531  };
 532
 533  /**
 534   * Removes a listener.
 535   *
 536   * @api public
 537   */
 538
 539  EventEmitter.prototype.removeListener = function (name, fn) {
 540    if (this.$events && this.$events[name]) {
 541      var list = this.$events[name];
 542
 543      if (io.util.isArray(list)) {
 544        var pos = -1;
 545
 546        for (var i = 0, l = list.length; i < l; i++) {
 547          if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
 548            pos = i;
 549            break;
 550          }
 551        }
 552
 553        if (pos < 0) {
 554          return this;
 555        }
 556
 557        list.splice(pos, 1);
 558
 559        if (!list.length) {
 560          delete this.$events[name];
 561        }
 562      } else if (list === fn || (list.listener && list.listener === fn)) {
 563        delete this.$events[name];
 564      }
 565    }
 566
 567    return this;
 568  };
 569
 570  /**
 571   * Removes all listeners for an event.
 572   *
 573   * @api public
 574   */
 575
 576  EventEmitter.prototype.removeAllListeners = function (name) {
 577    // TODO: enable this when node 0.5 is stable
 578    //if (name === undefined) {
 579      //this.$events = {};
 580      //return this;
 581    //}
 582
 583    if (this.$events && this.$events[name]) {
 584      this.$events[name] = null;
 585    }
 586
 587    return this;
 588  };
 589
 590  /**
 591   * Gets all listeners for a certain event.
 592   *
 593   * @api publci
 594   */
 595
 596  EventEmitter.prototype.listeners = function (name) {
 597    if (!this.$events) {
 598      this.$events = {};
 599    }
 600
 601    if (!this.$events[name]) {
 602      this.$events[name] = [];
 603    }
 604
 605    if (!io.util.isArray(this.$events[name])) {
 606      this.$events[name] = [this.$events[name]];
 607    }
 608
 609    return this.$events[name];
 610  };
 611
 612  /**
 613   * Emits an event.
 614   *
 615   * @api public
 616   */
 617
 618  EventEmitter.prototype.emit = function (name) {
 619    if (!this.$events) {
 620      return false;
 621    }
 622
 623    var handler = this.$events[name];
 624
 625    if (!handler) {
 626      return false;
 627    }
 628
 629    var args = Array.prototype.slice.call(arguments, 1);
 630
 631    if ('function' == typeof handler) {
 632      handler.apply(this, args);
 633    } else if (io.util.isArray(handler)) {
 634      var listeners = handler.slice();
 635
 636      for (var i = 0, l = listeners.length; i < l; i++) {
 637        listeners[i].apply(this, args);
 638      }
 639    } else {
 640      return false;
 641    }
 642
 643    return true;
 644  };
 645
 646})(
 647    'undefined' != typeof io ? io : module.exports
 648  , 'undefined' != typeof io ? io : module.parent.exports
 649);
 650
 651/**
 652 * socket.io
 653 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 654 * MIT Licensed
 655 */
 656
 657/**
 658 * Based on JSON2 (http://www.JSON.org/js.html).
 659 */
 660
 661(function (exports, nativeJSON) {
 662  "use strict";
 663
 664  // use native JSON if it's available
 665  if (nativeJSON && nativeJSON.parse){
 666    return exports.JSON = {
 667      parse: nativeJSON.parse
 668    , stringify: nativeJSON.stringify
 669    }
 670  }
 671
 672  var JSON = exports.JSON = {};
 673
 674  function f(n) {
 675      // Format integers to have at least two digits.
 676      return n < 10 ? '0' + n : n;
 677  }
 678
 679  function date(d, key) {
 680    return isFinite(d.valueOf()) ?
 681        d.getUTCFullYear()     + '-' +
 682        f(d.getUTCMonth() + 1) + '-' +
 683        f(d.getUTCDate())      + 'T' +
 684        f(d.getUTCHours())     + ':' +
 685        f(d.getUTCMinutes())   + ':' +
 686        f(d.getUTCSeconds())   + 'Z' : null;
 687  };
 688
 689  var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 690      escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 691      gap,
 692      indent,
 693      meta = {    // table of character substitutions
 694          '\b': '\\b',
 695          '\t': '\\t',
 696          '\n': '\\n',
 697          '\f': '\\f',
 698          '\r': '\\r',
 699          '"' : '\\"',
 700          '\\': '\\\\'
 701      },
 702      rep;
 703
 704
 705  function quote(string) {
 706
 707// If the string contains no control characters, no quote characters, and no
 708// backslash characters, then we can safely slap some quotes around it.
 709// Otherwise we must also replace the offending characters with safe escape
 710// sequences.
 711
 712      escapable.lastIndex = 0;
 713      return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
 714          var c = meta[a];
 715          return typeof c === 'string' ? c :
 716              '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 717      }) + '"' : '"' + string + '"';
 718  }
 719
 720
 721  function str(key, holder) {
 722
 723// Produce a string from holder[key].
 724
 725      var i,          // The loop counter.
 726          k,          // The member key.
 727          v,          // The member value.
 728          length,
 729          mind = gap,
 730          partial,
 731          value = holder[key];
 732
 733// If the value has a toJSON method, call it to obtain a replacement value.
 734
 735      if (value instanceof Date) {
 736          value = date(key);
 737      }
 738
 739// If we were called with a replacer function, then call the replacer to
 740// obtain a replacement value.
 741
 742      if (typeof rep === 'function') {
 743          value = rep.call(holder, key, value);
 744      }
 745
 746// What happens next depends on the value's type.
 747
 748      switch (typeof value) {
 749      case 'string':
 750          return quote(value);
 751
 752      case 'number':
 753
 754// JSON numbers must be finite. Encode non-finite numbers as null.
 755
 756          return isFinite(value) ? String(value) : 'null';
 757
 758      case 'boolean':
 759      case 'null':
 760
 761// If the value is a boolean or null, convert it to a string. Note:
 762// typeof null does not produce 'null'. The case is included here in
 763// the remote chance that this gets fixed someday.
 764
 765          return String(value);
 766
 767// If the type is 'object', we might be dealing with an object or an array or
 768// null.
 769
 770      case 'object':
 771
 772// Due to a specification blunder in ECMAScript, typeof null is 'object',
 773// so watch out for that case.
 774
 775          if (!value) {
 776              return 'null';
 777          }
 778
 779// Make an array to hold the partial results of stringifying this object value.
 780
 781          gap += indent;
 782          partial = [];
 783
 784// Is the value an array?
 785
 786          if (Object.prototype.toString.apply(value) === '[object Array]') {
 787
 788// The value is an array. Stringify every element. Use null as a placeholder
 789// for non-JSON values.
 790
 791              length = value.length;
 792              for (i = 0; i < length; i += 1) {
 793                  partial[i] = str(i, value) || 'null';
 794              }
 795
 796// Join all of the elements together, separated with commas, and wrap them in
 797// brackets.
 798
 799              v = partial.length === 0 ? '[]' : gap ?
 800                  '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
 801                  '[' + partial.join(',') + ']';
 802              gap = mind;
 803              return v;
 804          }
 805
 806// If the replacer is an array, use it to select the members to be stringified.
 807
 808          if (rep && typeof rep === 'object') {
 809              length = rep.length;
 810              for (i = 0; i < length; i += 1) {
 811                  if (typeof rep[i] === 'string') {
 812                      k = rep[i];
 813                      v = str(k, value);
 814                      if (v) {
 815                          partial.push(quote(k) + (gap ? ': ' : ':') + v);
 816                      }
 817                  }
 818              }
 819          } else {
 820
 821// Otherwise, iterate through all of the keys in the object.
 822
 823              for (k in value) {
 824                  if (Object.prototype.hasOwnProperty.call(value, k)) {
 825                      v = str(k, value);
 826                      if (v) {
 827                          partial.push(quote(k) + (gap ? ': ' : ':') + v);
 828                      }
 829                  }
 830              }
 831          }
 832
 833// Join all of the member texts together, separated with commas,
 834// and wrap them in braces.
 835
 836          v = partial.length === 0 ? '{}' : gap ?
 837              '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
 838              '{' + partial.join(',') + '}';
 839          gap = mind;
 840          return v;
 841      }
 842  }
 843
 844// If the JSON object does not yet have a stringify method, give it one.
 845
 846  JSON.stringify = function (value, replacer, space) {
 847
 848// The stringify method takes a value and an optional replacer, and an optional
 849// space parameter, and returns a JSON text. The replacer can be a function
 850// that can replace values, or an array of strings that will select the keys.
 851// A default replacer method can be provided. Use of the space parameter can
 852// produce text that is more easily readable.
 853
 854      var i;
 855      gap = '';
 856      indent = '';
 857
 858// If the space parameter is a number, make an indent string containing that
 859// many spaces.
 860
 861      if (typeof space === 'number') {
 862          for (i = 0; i < space; i += 1) {
 863              indent += ' ';
 864          }
 865
 866// If the space parameter is a string, it will be used as the indent string.
 867
 868      } else if (typeof space === 'string') {
 869          indent = space;
 870      }
 871
 872// If there is a replacer, it must be a function or an array.
 873// Otherwise, throw an error.
 874
 875      rep = replacer;
 876      if (replacer && typeof replacer !== 'function' &&
 877              (typeof replacer !== 'object' ||
 878              typeof replacer.length !== 'number')) {
 879          throw new Error('JSON.stringify');
 880      }
 881
 882// Make a fake root object containing our value under the key of ''.
 883// Return the result of stringifying the value.
 884
 885      return str('', {'': value});
 886  };
 887
 888// If the JSON object does not yet have a parse method, give it one.
 889
 890  JSON.parse = function (text, reviver) {
 891  // The parse method takes a text and an optional reviver function, and returns
 892  // a JavaScript value if the text is a valid JSON text.
 893
 894      var j;
 895
 896      function walk(holder, key) {
 897
 898  // The walk method is used to recursively walk the resulting structure so
 899  // that modifications can be made.
 900
 901          var k, v, value = holder[key];
 902          if (value && typeof value === 'object') {
 903              for (k in value) {
 904                  if (Object.prototype.hasOwnProperty.call(value, k)) {
 905                      v = walk(value, k);
 906                      if (v !== undefined) {
 907                          value[k] = v;
 908                      } else {
 909                          delete value[k];
 910                      }
 911                  }
 912              }
 913          }
 914          return reviver.call(holder, key, value);
 915      }
 916
 917
 918  // Parsing happens in four stages. In the first stage, we replace certain
 919  // Unicode characters with escape sequences. JavaScript handles many characters
 920  // incorrectly, either silently deleting them, or treating them as line endings.
 921
 922      text = String(text);
 923      cx.lastIndex = 0;
 924      if (cx.test(text)) {
 925          text = text.replace(cx, function (a) {
 926              return '\\u' +
 927                  ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 928          });
 929      }
 930
 931  // In the second stage, we run the text against regular expressions that look
 932  // for non-JSON patterns. We are especially concerned with '()' and 'new'
 933  // because they can cause invocation, and '=' because it can cause mutation.
 934  // But just to be safe, we want to reject all unexpected forms.
 935
 936  // We split the second stage into 4 regexp operations in order to work around
 937  // crippling inefficiencies in IE's and Safari's regexp engines. First we
 938  // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
 939  // replace all simple value tokens with ']' characters. Third, we delete all
 940  // open brackets that follow a colon or comma or that begin the text. Finally,
 941  // we look to see that the remaining characters are only whitespace or ']' or
 942  // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
 943
 944      if (/^[\],:{}\s]*$/
 945              .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
 946                  .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
 947                  .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
 948
 949  // In the third stage we use the eval function to compile the text into a
 950  // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
 951  // in JavaScript: it can begin a block or an object literal. We wrap the text
 952  // in parens to eliminate the ambiguity.
 953
 954          j = eval('(' + text + ')');
 955
 956  // In the optional fourth stage, we recursively walk the new structure, passing
 957  // each name/value pair to a reviver function for possible transformation.
 958
 959          return typeof reviver === 'function' ?
 960              walk({'': j}, '') : j;
 961      }
 962
 963  // If the text is not JSON parseable, then a SyntaxError is thrown.
 964
 965      throw new SyntaxError('JSON.parse');
 966  };
 967
 968})(
 969    'undefined' != typeof io ? io : module.exports
 970  , typeof JSON !== 'undefined' ? JSON : undefined
 971);
 972
 973/**
 974 * socket.io
 975 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 976 * MIT Licensed
 977 */
 978
 979(function (exports, io) {
 980
 981  /**
 982   * Parser namespace.
 983   *
 984   * @namespace
 985   */
 986
 987  var parser = exports.parser = {};
 988
 989  /**
 990   * Packet types.
 991   */
 992
 993  var packets = parser.packets = [
 994      'disconnect'
 995    , 'connect'
 996    , 'heartbeat'
 997    , 'message'
 998    , 'json'
 999    , 'event'
1000    , 'ack'
1001    , 'error'
1002    , 'noop'
1003  ];
1004
1005  /**
1006   * Errors reasons.
1007   */
1008
1009  var reasons = parser.reasons = [
1010      'transport not supported'
1011    , 'client not handshaken'
1012    , 'unauthorized'
1013  ];
1014
1015  /**
1016   * Errors advice.
1017   */
1018
1019  var advice = parser.advice = [
1020      'reconnect'
1021  ];
1022
1023  /**
1024   * Shortcuts.
1025   */
1026
1027  var JSON = io.JSON
1028    , indexOf = io.util.indexOf;
1029
1030  /**
1031   * Encodes a packet.
1032   *
1033   * @api private
1034   */
1035
1036  parser.encodePacket = function (packet) {
1037    var type = indexOf(packets, packet.type)
1038      , id = packet.id || ''
1039      , endpoint = packet.endpoint || ''
1040      , ack = packet.ack
1041      , data = null;
1042
1043    switch (packet.type) {
1044      case 'error':
1045        var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
1046          , adv = packet.advice ? indexOf(advice, packet.advice) : '';
1047
1048        if (reason !== '' || adv !== '')
1049          data = reason + (adv !== '' ? ('+' + adv) : '');
1050
1051        break;
1052
1053      case 'message':
1054        if (packet.data !== '')
1055          data = packet.data;
1056        break;
1057
1058      case 'event':
1059        var ev = { name: packet.name };
1060
1061        if (packet.args && packet.args.length) {
1062          ev.args = packet.args;
1063        }
1064
1065        data = JSON.stringify(ev);
1066        break;
1067
1068      case 'json':
1069        data = JSON.stringify(packet.data);
1070        break;
1071
1072      case 'connect':
1073        if (packet.qs)
1074          data = packet.qs;
1075        break;
1076
1077      case 'ack':
1078        data = packet.ackId
1079          + (packet.args && packet.args.length
1080              ? '+' + JSON.stringify(packet.args) : '');
1081        break;
1082    }
1083
1084    // construct packet with required fragments
1085    var encoded = [
1086        type
1087      , id + (ack == 'data' ? '+' : '')
1088      , endpoint
1089    ];
1090
1091    // data fragment is optional
1092    if (data !== null && data !== undefined)
1093      encoded.push(data);
1094
1095    return encoded.join(':');
1096  };
1097
1098  /**
1099   * Encodes multiple messages (payload).
1100   *
1101   * @param {Array} messages
1102   * @api private
1103   */
1104
1105  parser.encodePayload = function (packets) {
1106    var decoded = '';
1107
1108    if (packets.length == 1)
1109      return packets[0];
1110
1111    for (var i = 0, l = packets.length; i < l; i++) {
1112      var packet = packets[i];
1113      decoded += '\ufffd' + packet.length + '\ufffd' + packets[i];
1114    }
1115
1116    return decoded;
1117  };
1118
1119  /**
1120   * Decodes a packet
1121   *
1122   * @api private
1123   */
1124
1125  var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
1126
1127  parser.decodePacket = function (data) {
1128    var pieces = data.match(regexp);
1129
1130    if (!pieces) return {};
1131
1132    var id = pieces[2] || ''
1133      , data = pieces[5] || ''
1134      , packet = {
1135            type: packets[pieces[1]]
1136          , endpoint: pieces[4] || ''
1137        };
1138
1139    // whether we need to acknowledge the packet
1140    if (id) {
1141      packet.id = id;
1142      if (pieces[3])
1143        packet.ack = 'data';
1144      else
1145        packet.ack = true;
1146    }
1147
1148    // handle different packet types
1149    switch (packet.type) {
1150      case 'error':
1151        var pieces = data.split('+');
1152        packet.reason = reasons[pieces[0]] || '';
1153        packet.advice = advice[pieces[1]] || '';
1154        break;
1155
1156      case 'message':
1157        packet.data = data || '';
1158        break;
1159
1160      case 'event':
1161        try {
1162          var opts = JSON.parse(data);
1163          packet.name = opts.name;
1164          packet.args = opts.args;
1165        } catch (e) { }
1166
1167        packet.args = packet.args || [];
1168        break;
1169
1170      case 'json':
1171        try {
1172          packet.data = JSON.parse(data);
1173        } catch (e) { }
1174        break;
1175
1176      case 'connect':
1177        packet.qs = data || '';
1178        break;
1179
1180      case 'ack':
1181        var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
1182        if (pieces) {
1183          packet.ackId = pieces[1];
1184          packet.args = [];
1185
1186          if (pieces[3]) {
1187            try {
1188              packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
1189            } catch (e) { }
1190          }
1191        }
1192        break;
1193
1194      case 'disconnect':
1195      case 'heartbeat':
1196        break;
1197    };
1198
1199    return packet;
1200  };
1201
1202  /**
1203   * Decodes data payload. Detects multiple messages
1204   *
1205   * @return {Array} messages
1206   * @api public
1207   */
1208
1209  parser.decodePayload = function (data) {
1210    // IE doesn't like data[i] for unicode chars, charAt works fine
1211    if (data.charAt(0) == '\ufffd') {
1212      var ret = [];
1213
1214      for (var i = 1, length = ''; i < data.length; i++) {
1215        if (data.charAt(i) == '\ufffd') {
1216          ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
1217          i += Number(length) + 1;
1218          length = '';
1219        } else {
1220          length += data.charAt(i);
1221        }
1222      }
1223
1224      return ret;
1225    } else {
1226      return [parser.decodePacket(data)];
1227    }
1228  };
1229
1230})(
1231    'undefined' != typeof io ? io : module.exports
1232  , 'undefined' != typeof io ? io : module.parent.exports
1233);
1234
1235/**
1236 * socket.io
1237 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1238 * MIT Licensed
1239 */
1240
1241(function (exports, io) {
1242
1243  /**
1244   * Expose constructor.
1245   */
1246
1247  exports.Transport = Transport;
1248
1249  /**
1250   * This is the transport template for all supported transport methods.
1251   *
1252   * @constructor
1253   * @api public
1254   */
1255
1256  function Transport (socket, sessid) {
1257    this.socket = socket;
1258    this.sessid = sessid;
1259  };
1260
1261  /**
1262   * Apply EventEmitter mixin.
1263   */
1264
1265  io.util.mixin(Transport, io.EventEmitter);
1266
1267  /**
1268   * Handles the response from the server. When a new response is received
1269   * it will automatically update the timeout, decode the message and
1270   * forwards the response to the onMessage function for further processing.
1271   *
1272   * @param {String} data Response from the server.
1273   * @api private
1274   */
1275
1276  Transport.prototype.onData = function (data) {
1277    this.clearCloseTimeout();
1278    this.setCloseTimeout();
1279
1280    if (data !== '') {
1281      // todo: we should only do decodePayload for xhr transports
1282      var msgs = io.parser.decodePayload(data);
1283
1284      if (msgs && msgs.length) {
1285        for (var i = 0, l = msgs.length; i < l; i++) {
1286          this.onPacket(msgs[i]);
1287        }
1288      }
1289    }
1290
1291    return this;
1292  };
1293
1294  /**
1295   * Handles packets.
1296   *
1297   * @api private
1298   */
1299
1300  Transport.prototype.onPacket = function (packet) {
1301    if (packet.type == 'heartbeat') {
1302      return this.onHeartbeat();
1303    }
1304
1305    if (packet.type == 'connect' && packet.endpoint == '') {
1306      this.onConnect();
1307    }
1308
1309    this.socket.onPacket(packet);
1310
1311    return this;
1312  };
1313
1314  /**
1315   * Sets close timeout
1316   *
1317   * @api private
1318   */
1319  
1320  Transport.prototype.setCloseTimeout = function () {
1321    if (!this.closeTimeout) {
1322      var self = this;
1323
1324      this.closeTimeout = setTimeout(function () {
1325        self.onDisconnect();
1326      }, this.socket.closeTimeout);
1327    }
1328  };
1329
1330  /**
1331   * Called when transport disconnects.
1332   *
1333   * @api private
1334   */
1335
1336  Transport.prototype.onDisconnect = function () {
1337    if (this.close) this.close();
1338    this.clearTimeouts();
1339    this.socket.onDisconnect();
1340    return this;
1341  };
1342
1343  /**
1344   * Called when transport connects
1345   *
1346   * @api private
1347   */
1348
1349  Transport.prototype.onConnect = function () {
1350    this.socket.onConnect();
1351    return this;
1352  }
1353
1354  /**
1355   * Clears close timeout
1356   *
1357   * @api private
1358   */
1359
1360  Transport.prototype.clearCloseTimeout = function () {
1361    if (this.closeTimeout) {
1362      clearTimeout(this.closeTimeout);
1363      this.closeTimeout = null;
1364    }
1365  };
1366
1367  /**
1368   * Clear timeouts
1369   *
1370   * @api private
1371   */
1372
1373  Transport.prototype.clearTimeouts = function () {
1374    this.clearCloseTimeout();
1375
1376    if (this.reopenTimeout) {
1377      clearTimeout(this.reopenTimeout);
1378    }
1379  };
1380
1381  /**
1382   * Sends a packet
1383   *
1384   * @param {Object} packet object.
1385   * @api private
1386   */
1387
1388  Transport.prototype.packet = function (packet) {
1389    this.send(io.parser.encodePacket(packet));
1390  };
1391
1392  /**
1393   * Send the received heartbeat message back to server. So the server
1394   * knows we are still connected.
1395   *
1396   * @param {String} heartbeat Heartbeat response from the server.
1397   * @api private
1398   */
1399
1400  Transport.prototype.onHeartbeat = function (heartbeat) {
1401    this.packet({ type: 'heartbeat' });
1402  };
1403 
1404  /**
1405   * Called when the transport opens.
1406   *
1407   * @api private
1408   */
1409
1410  Transport.prototype.onOpen = function () {
1411    this.open = true;
1412    this.clearCloseTimeout();
1413    this.socket.onOpen();
1414  };
1415
1416  /**
1417   * Notifies the base when the connection with the Socket.IO server
1418   * has been disconnected.
1419   *
1420   * @api private
1421   */
1422
1423  Transport.prototype.onClose = function () {
1424    var self = this;
1425
1426    /* FIXME: reopen delay causing a infinit loop
1427    this.reopenTimeout = setTimeout(function () {
1428      self.open();
1429    }, this.socket.options['reopen delay']);*/
1430
1431    this.open = false;
1432    this.setCloseTimeout();
1433    this.socket.onClose();
1434  };
1435
1436  /**
1437   * Generates a connection url based on the Socket.IO URL Protocol.
1438   * See <https://github.com/learnboost/socket.io-node/> for more details.
1439   *
1440   * @returns {String} Connection url
1441   * @api private
1442   */
1443
1444  Transport.prototype.prepareUrl = function () {
1445    var options = this.socket.options;
1446
1447    return this.scheme() + '://'
1448      + options.host + ':' + options.port + '/'
1449      + options.resource + '/' + io.protocol
1450      + '/' + this.name + '/' + this.sessid;
1451  };
1452
1453  /**
1454   * Checks if the transport is ready to start a connection.
1455   *
1456   * @param {Socket} socket The socket instance that needs a transport
1457   * @param {Function} fn The callback
1458   * @api private
1459   */
1460
1461  Transport.prototype.ready = function (socket, fn) {
1462    fn.call(this);
1463  };
1464})(
1465    'undefined' != typeof io ? io : module.exports
1466  , 'undefined' != typeof io ? io : module.parent.exports
1467);
1468
1469/**
1470 * socket.io
1471 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1472 * MIT Licensed
1473 */
1474
1475(function (exports, io, global) {
1476
1477  /**
1478   * Expose constructor.
1479   */
1480
1481  exports.Socket = Socket;
1482
1483  /**
1484   * Create a new `Socket.IO client` which can establish a persistent
1485   * connection with a Socket.IO enabled server.
1486   *
1487   * @api public
1488   */
1489
1490  function Socket (options) {
1491    this.options = {
1492        port: 80
1493      , secure: false
1494      , document: 'document' in global ? document : false
1495      , resource: 'socket.io'
1496      , transports: io.transports
1497      , 'connect timeout': 10000
1498      , 'try multiple transports': true
1499      , 'reconnect': true
1500      , 'reconnection delay': 500
1501      , 'reconnection limit': Infinity
1502      , 'reopen delay': 3000
1503      , 'max reconnection attempts': 10
1504      , 'sync disconnect on unload': true
1505      , 'auto connect': true
1506      , 'flash policy port': 10843
1507    };
1508
1509    io.util.merge(this.options, options);
1510
1511    this.connected = false;
1512    this.open = false;
1513    this.connecting = false;
1514    this.reconnecting = false;
1515    this.namespaces = {};
1516    this.buffer = [];
1517    this.doBuffer = false;
1518
1519    if (this.options['sync disconnect on unload'] &&
1520        (!this.isXDomain() || io.util.ua.hasCORS)) {
1521      var self = this;
1522
1523      io.util.on(global, 'beforeunload', function () {
1524        self.disconnectSync();
1525      }, false);
1526    }
1527
1528    if (this.options['auto connect']) {
1529      this.connect();
1530    }
1531};
1532
1533  /**
1534   * Apply EventEmitter mixin.
1535   */
1536
1537  io.util.mixin(Socket, io.EventEmitter);
1538
1539  /**
1540   * Returns a namespace listener/emitter for this socket
1541   *
1542   * @api public
1543   */
1544
1545  Socket.prototype.of = function (name) {
1546    if (!this.namespaces[name]) {
1547      this.namespaces[name] = new io.SocketNamespace(this, name);
1548
1549      if (name !== '') {
1550        this.namespaces[name].packet({ type: 'connect' });
1551      }
1552    }
1553
1554    return this.namespaces[name];
1555  };
1556
1557  /**
1558   * Emits the given event to the Socket and all namespaces
1559   *
1560   * @api private
1561   */
1562
1563  Socket.prototype.publish = function () {
1564    this.emit.apply(this, arguments);
1565
1566    var nsp;
1567
1568    for (var i in this.namespaces) {
1569      if (this.namespaces.hasOwnProperty(i)) {
1570        nsp = this.of(i);
1571        nsp.$emit.apply(nsp, arguments);
1572      }
1573    }
1574  };
1575
1576  /**
1577   * Performs the handshake
1578   *
1579   * @api private
1580   */
1581
1582  function empty () { };
1583
1584  Socket.prototype.handshake = function (fn) {
1585    var self = this
1586      , options = this.options;
1587
1588    function complete (data) {
1589      if (data instanceof Error) {
1590        self.onError(data.message);
1591      } else {
1592        fn.apply(null, data.split(':'));
1593      }
1594    };
1595
1596    var url = [
1597          'http' + (options.secure ? 's' : '') + ':/'
1598        , options.host + ':' + options.port
1599        , this.options.resource
1600        , io.protocol
1601        , io.util.query(this.options.query, 't=' + +new Date)
1602      ].join('/');
1603
1604    if (this.isXDomain()) {
1605      var insertAt = document.getElementsByTagName('script')[0]
1606        , script = document.createElement('script');
1607
1608      script.src = url + '&jsonp=' + io.j.length;
1609      insertAt.parentNode.insertBefore(script, insertAt);
1610
1611      io.j.push(function (data) {
1612        complete(data);
1613        script.parentNode.removeChild(script);
1614      });
1615    } else {
1616      var xhr = io.util.request();
1617
1618      xhr.open('GET', url, true);
1619      xhr.onreadystatechange = function () {
1620        if (xhr.readyState == 4) {
1621          xhr.onreadystatechange = empty;
1622
1623          if (xhr.status == 200) {
1624            complete(xhr.responseText);
1625          } else {
1626            !self.reconnecting && self.onError(xhr.responseText);
1627          }
1628        }
1629      };
1630      xhr.send(null);
1631    }
1632  };
1633
1634  /**
1635   * Find an available transport based on the options supplied in the constructor.
1636   *
1637   * @api private
1638   */
1639
1640  Socket.prototype.getTransport = function (override) {
1641    var transports = override || this.transports, match;
1642
1643    for (var i = 0, transport; transport = transports[i]; i++) {
1644      if (io.Transport[transport]
1645        && io.Transport[transport].check(this)
1646        && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
1647        return new io.Transport[transport](this, this.sessionid);
1648      }
1649    }
1650
1651    return null;
1652  };
1653
1654  /**
1655   * Connects to the server.
1656   *
1657   * @param {Function} [fn] Callback.
1658   * @returns {io.Socket}
1659   * @api public
1660   */
1661
1662  Socket.prototype.connect = function (fn) {
1663    if (this.connecting) {
1664      return this;
1665    }
1666
1667    var self = this;
1668
1669    this.handshake(function (sid, heartbeat, close, transports) {
1670      self.sessionid = sid;
1671      self.closeTimeout = close * 1000;
1672      self.heartbeatTimeout = heartbeat * 1000;
1673      self.transports = io.util.intersect(
1674          transports.split(',')
1675        , self.options.transports
1676      );
1677
1678      function connect (transports){
1679        if (self.transport) self.transport.clearTimeouts();
1680
1681        self.transport = self.getTransport(transports);
1682        if (!self.transport) return self.publish('connect_failed');
1683
1684        // once the transport is ready
1685        self.transport.ready(self, function () {
1686          self.connecting = true;
1687          self.publish('connecting', self.transport.name);
1688          self.transport.open();
1689
1690          if (self.options['connect timeout']) {
1691            self.connectTimeoutTimer = setTimeout(function () {
1692              if (!self.connected) {
1693                self.connecting = false;
1694
1695                if (self.options['try multiple transports']) {
1696                  if (!self.remainingTransports) {
1697                    self.remainingTransports = self.transports.slice(0);
1698                  }
1699
1700                  var remaining = self.remainingTransports;
1701
1702                  while (remaining.length > 0 && remaining.splice(0,1)[0] !=
1703                         self.transport.name) {}
1704
1705                    if (remaining.length){
1706                      connect(remaining);
1707                    } else {
1708                      self.publish('connect_failed');
1709                    }
1710                }
1711              }
1712            }, self.options['connect timeout']);
1713          }
1714        });
1715      }
1716
1717      connect();
1718
1719      self.once('connect', function (){
1720        clearTimeout(self.connectTimeoutTimer);
1721
1722        fn && typeof fn == 'function' && fn();
1723      });
1724    });
1725
1726    return this;
1727  };
1728
1729  /**
1730   * Sends a message.
1731   *
1732   * @param {Object} data packet.
1733   * @returns {io.Socket}
1734   * @api public
1735   */
1736
1737  Socket.prototype.packet = function (data) {
1738    if (this.connected && !this.doBuffer) {
1739      this.transport.packet(data);
1740    } else {
1741      this.buffer.push(data);
1742    }
1743
1744    return this;
1745  };
1746
1747  /**
1748   * Sets buffer state
1749   *
1750   * @api private
1751   */
1752
1753  Socket.prototype.setBuffer = function (v) {
1754    this.doBuffer = v;
1755
1756    if (!v && this.connected && this.buffer.length) {
1757      this.transport.payload(this.buffer);
1758      this.buffer = [];
1759    }
1760  };
1761
1762  /**
1763   * Disconnect the established connect.
1764   *
1765   * @returns {io.Socket}
1766   * @api public
1767   */
1768
1769  Socket.prototype.disconnect = function () {
1770    if (this.connected) {
1771      if (this.open) {
1772        this.of('').packet({ type: 'disconnect' });
1773      }
1774
1775      // handle disconnection immediately
1776      this.onDisconnect('booted');
1777    }
1778
1779    return this;
1780  };
1781
1782  /**
1783   * Disconnects the socket with a sync XHR.
1784   *
1785   * @api private
1786   */
1787
1788  Socket.prototype.disconnectSync = function () {
1789    // ensure disconnection
1790    var xhr = io.util.request()
1791      , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;
1792
1793    xhr.open('GET', uri, true);
1794
1795    // handle disconnection immediately
1796    this.onDisconnect('booted');
1797  };
1798
1799  /**
1800   * Check if we need to use cross domain enabled transports. Cross domain would
1801   * be a different port or different domain name.
1802   *
1803   * @returns {Boolean}
1804   * @api private
1805   */
1806
1807  Socket.prototype.isXDomain = function () {
1808
1809    var port = window.location.port ||
1810      ('https:' == window.location.protocol ? 443 : 80);
1811
1812    return this.options.host !== document.domain || this.options.port != port;
1813  };
1814
1815  /**
1816   * Called upon handshake.
1817   *
1818   * @api private
1819   */
1820
1821  Socket.prototype.onConnect = function () {
1822    if (!this.connected) {
1823      this.connected = true;
1824      this.connecting = false;
1825      if (!this.doBuffer) {
1826        // make sure to flush the buffer
1827        this.setBuffer(false);
1828      }
1829      this.emit('connect');
1830    }
1831  };
1832
1833  /**
1834   * Called when the transport opens
1835   *
1836   * @api private
1837   */
1838
1839  Socket.prototype.onOpen = function () {
1840    this.open = true;
1841  };
1842
1843  /**
1844   * Called when the transport closes.
1845   *
1846   * @api private
1847   */
1848
1849  Socket.prototype.onClose = function () {
1850    this.open = false;
1851  };
1852
1853  /**
1854   * Called when the transport first opens a connection
1855   *
1856   * @param text
1857   */
1858
1859  Socket.prototype.onPacket = function (packet) {
1860    this.of(packet.endpoint).onPacket(packet);
1861  };
1862
1863  /**
1864   * Handles an error.
1865   *
1866   * @api private
1867   */
1868
1869  Socket.prototype.onError = function (err) {
1870    if (err && err.advice) {
1871      if (err.advice === 'reconnect' && this.connected) {
1872        this.disconnect();
1873        this.reconnect();
1874      }
1875    }
1876
1877    this.publish('error', err && err.reason ? err.reason : err);
1878  };
1879
1880  /**
1881   * Called when the transport disconnects.
1882   *
1883   * @api private
1884   */
1885
1886  Socket.prototype.onDisconnect = function (reason) {
1887    var wasConnected = this.connected;
1888
1889    this.connected = false;
1890    this.connecting = false;
1891    this.open = false;
1892
1893    if (wasConnected) {
1894      this.transport.close();
1895      this.transport.clearTimeouts();
1896      this.publish('disconnect', reason);
1897
1898      if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
1899        this.reconnect();
1900      }
1901    }
1902  };
1903
1904  /**
1905   * Called upon reconnection.
1906   *
1907   * @api private
1908   */
1909
1910  Socket.prototype.reconnect = function () {
1911    this.reconnecting = true;
1912    this.reconnectionAttempts = 0;
1913    this.reconnectionDelay = this.options['reconnection delay'];
1914
1915    var self = this
1916      , maxAttempts = this.options['max reconnection attempts']
1917      , tryMultiple = this.options['try multiple transports']
1918      , limit = this.options['reconnection limit'];
1919
1920    function reset () {
1921      if (self.connected) {
1922        for (var i in self.namespaces) {
1923          if (self.namespaces.hasOwnProperty(i) && '' !== i) {
1924              self.namespaces[i].packet({ type: 'connect' });
1925          }
1926        }
1927        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
1928      }
1929
1930      self.removeListener('connect_failed', maybeReconnect);
1931      self.removeListener('connect', maybeReconnect);
1932
1933      self.reconnecting = false;
1934
1935      delete self.reconnectionAttempts;
1936      delete self.reconnectionDelay;
1937      delete self.reconnectionTimer;
1938      delete self.redoTransports;
1939
1940      self.options['try multiple transports'] = tryMultiple;
1941    };
1942
1943    function maybeReconnect () {
1944      if (!self.reconnecting) {
1945        return;
1946      }
1947
1948      if (self.connected) {
1949        return reset();
1950      };
1951
1952      if (self.connecting && self.reconnecting) {
1953        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
1954      }
1955
1956      if (self.reconnectionAttempts++ >= maxAttempts) {
1957        if (!self.redoTransports) {
1958          self.on('connect_failed', maybeReconnect);
1959          self.options['try multiple transports'] = true;
1960          self.transport = self.getTransport();
1961          self.redoTransports = true;
1962          self.connect();
1963        } else {
1964          self.publish('reconnect_failed');
1965          reset();
1966        }
1967      } else {
1968        if (self.reconnectionDelay < limit) {
1969          self.reconnectionDelay *= 2; // exponential back off
1970        }
1971
1972        self.connect();
1973        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
1974        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
1975      }
1976    };
1977
1978    this.options['try multiple transports'] = false;
1979    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
1980
1981    this.on('connect', maybeReconnect);
1982  };
1983
1984})(
1985    'undefined' != typeof io ? io : module.exports
1986  , 'undefined' != typeof io ? io : module.parent.exports
1987  , this
1988);
1989/**
1990 * socket.io
1991 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
1992 * MIT Licensed
1993 */
1994
1995(function (exports, io) {
1996
1997  /**
1998   * Expose constructor.
1999   */
2000
2001  exports.SocketNamespace = SocketNamespace;
2002
2003  /**
2004   * Socket namespace constructor.
2005   *
2006   * @constructor
2007   * @api public
2008   */
2009
2010  function SocketNamespace (socket, name) {
2011    this.socket = socket;
2012    this.name = name || '';
2013    this.flags = {};
2014    this.json = new Flag(this, 'json');
2015    this.ackPackets = 0;
2016    this.acks = {};
2017  };
2018
2019  /**
2020   * Apply EventEmitter mixin.
2021   */
2022
2023  io.util.mixin(SocketNamespace, io.EventEmitter);
2024
2025  /**
2026   * Copies emit since we override it
2027   *
2028   * @api private
2029   */
2030
2031  SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;
2032
2033  /**
2034   * Creates a new namespace, by proxying the request to the socket. This
2035   * allows us to use the synax as we do on the server.
2036   *
2037   * @api public
2038   */
2039
2040  SocketNamespace.prototype.of = function () {
2041    return this.socket.of.apply(this.socket, arguments);
2042  };
2043
2044  /**
2045   * Sends a packet.
2046   *
2047   * @api private
2048   */
2049
2050  SocketNamespace.prototype.packet = function (packet) {
2051    packet.endpoint = this.name;
2052    this.socket.packet(packet);
2053    this.flags = {};
2054    return this;
2055  };
2056
2057  /**
2058   * Sends a message
2059   *
2060   * @api public
2061   */
2062
2063  SocketNamespace.prototype.send = function (data, fn) {
2064    var packet = {
2065        type: this.flags.json ? 'json' : 'message'
2066      , data: data
2067    };
2068
2069    if ('function' == typeof fn) {
2070      packet.id = ++this.ackPackets;
2071      packet.ack = true;
2072      this.acks[packet.id] = fn;
2073    }
2074
2075    return this.packet(packet);
2076  };
2077
2078  /**
2079   * Emits an event
2080   *
2081   * @api public
2082   */
2083  
2084  SocketNamespace.prototype.emit = function (name) {
2085    var args = Array.prototype.slice.call(arguments, 1)
2086      , lastArg = args[args.length - 1]
2087      , packet = {
2088            type: 'event'
2089          , name: name
2090        };
2091
2092    if ('function' == typeof lastArg) {
2093      packet.id = ++this.ackPackets;
2094      packet.ack = 'data';
2095      this.acks[packet.id] = lastArg;
2096      args = args.slice(0, args.length - 1);
2097    }
2098
2099    packet.args = args;
2100
2101    return this.packet(packet);
2102  };
2103
2104  /**
2105   * Disconnects the namespace
2106   *
2107   * @api private
2108   */
2109
2110  SocketNamespace.prototype.disconnect = function () {
2111    if (this.name === '') {
2112      this.socket.disconnect();
2113    } else {
2114      this.packet({ type: 'disconnect' });
2115      this.$emit('disconnect');
2116    }
2117
2118    return this;
2119  };
2120
2121  /**
2122   * Handles a packet
2123   *
2124   * @api private
2125   */
2126
2127  SocketNamespace.prototype.onPacket = function (packet) {
2128    var self = this;
2129
2130    function ack () {
2131      self.packet({
2132          type: 'ack'
2133        , args: io.util.toArray(arguments)
2134        , ackId: packet.id
2135      });
2136    };
2137
2138    switch (packet.type) {
2139      case 'connect':
2140        this.$emit('connect');
2141        break;
2142
2143      case 'disconnect':
2144        if (this.name === '') {
2145          this.socket.onDisconnect(packet.reason || 'booted');
2146        } else {
2147          this.$emit('disconnect', packet.reason);
2148        }
2149        break;
2150
2151      case 'message':
2152      case 'json':
2153        var params = ['message', packet.data];
2154
2155        if (packet.ack == 'data') {
2156          params.push(ack);
2157        } else if (packet.ack) {
2158          this.packet({ type: 'ack', ackId: packet.id });
2159        }
2160
2161        this.$emit.apply(this, params);
2162        break;
2163
2164      case 'event':
2165        var params = [packet.name].concat(packet.args);
2166
2167        if (packet.ack == 'data')
2168          params.push(ack);
2169
2170        this.$emit.apply(this, params);
2171        break;
2172
2173      case 'ack':
2174        if (this.acks[packet.ackId]) {
2175          this.acks[packet.ackId].apply(this, packet.args);
2176          delete this.acks[packet.ackId];
2177        }
2178        break;
2179
2180      case 'error':
2181        if (packet.advice){
2182          this.socket.onError(packet);
2183        } else {
2184          if (packet.reason == 'unauthorized') {
2185            this.$emit('connect_failed', packet.reason);
2186          } else {
2187            this.$emit('error', packet.reason);
2188          }
2189        }
2190        break;
2191    }
2192  };
2193
2194  /**
2195   * Flag interface.
2196   *
2197   * @api private
2198   */
2199
2200  function Flag (nsp, name) {
2201    this.namespace = nsp;
2202    this.name = name;
2203  };
2204
2205  /**
2206   * Send a message
2207   *
2208   * @api public
2209   */
2210
2211  Flag.prototype.send = function () {
2212    this.namespace.flags[this.name] = true;
2213    this.namespace.send.apply(this.namespace, arguments);
2214  };
2215
2216  /**
2217   * Emit an event
2218   *
2219   * @api public
2220   */
2221
2222  Flag.prototype.emit = function () {
2223    this.namespace.flags[this.name] = true;
2224    this.namespace.emit.apply(this.namespace, arguments);
2225  };
2226
2227})(
2228    'undefined' != typeof io ? io : module.exports
2229  , 'undefined' != typeof io ? io : module.parent.exports
2230);
2231
2232/**
2233 * socket.io
2234 * Copyright(c) 2011 LearnBoost <d

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