├── .gitignore
├── .tern-project
├── Gruntfile.coffee
├── README.mkd
├── fidget.sh
├── images
└── vim-fiddle.gif
├── node_server.js
├── package.json
├── plugin
└── fidget.vim
├── template
├── index.html
├── jsFiddle.html
├── jsFiddle.js
├── main.css
├── main.js
├── socket.io.js
└── socket_client.js
└── testCurl.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | .sass-cache
2 | node_modules/
3 | *.swp
4 | *.pyc
5 |
--------------------------------------------------------------------------------
/.tern-project:
--------------------------------------------------------------------------------
1 | {
2 | "libs": [
3 | "browser",
4 | "jquery"
5 | ],
6 | "plugins": {
7 | "node": {
8 | "baseURL": "./",
9 | "paths":{}
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Gruntfile.coffee:
--------------------------------------------------------------------------------
1 | module.exports = (grunt) ->
2 | grunt.initConfig({
3 | watch:
4 | reTest:
5 | files: ['*.sh']
6 | tasks: ['shell:testCurl']
7 | browserTest:
8 | files: ['**/*client.js']
9 | options:
10 | livereload: true
11 | nodemon:
12 | dev:
13 | script: 'node_server.js'
14 | options:
15 | args: ['/Users/mohitaggarwal/Documents/coolProjects/vim-fiddle']
16 | shell:
17 | testCurl:
18 | options:
19 | stdout: false
20 | stderr: false
21 | command: 'sh testCurl.sh'
22 |
23 | concurrent:
24 | options:
25 | logConcurrentOutput: true
26 | mainTask: ['nodemon', 'watch']
27 |
28 | })
29 |
30 | grunt.loadNpmTasks 'grunt-nodemon'
31 | grunt.loadNpmTasks 'grunt-contrib-watch'
32 | grunt.loadNpmTasks 'grunt-shell'
33 | grunt.loadNpmTasks 'grunt-concurrent'
34 |
35 | grunt.registerTask 'default', ['concurrent']
36 |
--------------------------------------------------------------------------------
/README.mkd:
--------------------------------------------------------------------------------
1 | # vim-fidget - JsFiddle for Vim
2 | ## What??
3 | This is a plugin (with a very creative name!) that emulates JsFiddle in vim and lets you post it to actual jsfiddle.com so that it can be shared.
4 | 
5 |
6 | ## Why??
7 | I am a web developer and the whole concept of trying out small chunks of programs makes JsFiddle really cool **BUT...**
8 |
9 | **WHERE IS MY VIM....?** this plugin answers that (it also does *live update* say whatt)
10 |
11 | ## Installation
12 |
13 | - Manual installation:
14 | 1. Copy the files to your `.vim` directory
15 | 2. then run `npm install` in the repo
16 | - [Pathogen](https://github.com/tpope/vim-pathogen)
17 | - `cd ~/.vim/bundle && git clone git://github.com/mohitleo9/vim-fidget.git && npm install`
18 | - [Vundle](https://github.com/gmarik/vundle)
19 | 1. Add `Bundle 'mohitleo9/vim-fidget'` to .vimrc
20 | 2. Run `:BundleInstall`
21 | 3. Then `go to the bundle/vim-fidget && run npm install`
22 | - [NeoBundle](https://github.com/Shougo/neobundle.vim)
23 | 1. Add
24 |
25 | NeoBundle 'mohitleo9/vim-fidget',{
26 | \ 'build' : {
27 | \ 'unix' : 'npm install',
28 | \ 'mac' : 'npm install',
29 | \ },
30 | \}
31 | to .vimrc
32 | 2. Run `:NeoBundleInstall`
33 |
34 | ## How to use ??
35 | It adds two commands
36 |
37 | `VimFidget` : create a fidget and open a browser window for live preview
38 |
39 | `VimFidgetBrowse` : upload the fidget to jsfiddle
40 | Also the server dies when you quit index.html buffer
41 |
42 | # Amending the default templates
43 | You can change the template files in bundle/vim-fidget/template to include
44 | stuff that you frequently use. For example, if you work locally and would like a base Fidget that includes jQuery, Modernizr and a meta tag for correct display of HTML on mobile devices you could:
45 |
46 | - download jQuery and Modernizr to your template folder
47 | - amend the `index.html` file as follows:
48 |
49 | ````html
50 |
51 |
52 |
53 |
54 | Vim Fidget
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | ````
70 |
71 | You can also alter the default CSS (main.css) and JS (main.js) in the same manner.
72 |
73 | ## Credits:
74 | - I took a lot of ideas from (and some code!) [vim-fiddle](https://github.com/mharju/vim-fiddle)
75 | - Also for using nodeJs and other stuff I looked(and took some code) at [suan/vim-instant-markdown](https://github.com/suan/vim-instant-markdown)
76 |
77 | ## That's it for today Folks!!!
78 |
--------------------------------------------------------------------------------
/fidget.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$FIDGETDIR" == "" ]; then
4 | FIDGETDIR=/tmp
5 | fi
6 |
7 | if [ "$1" == "" ]; then
8 | FIDGET=$FIDGETDIR/`python -c "import random; print hex(int(str(random.random())[2:10]))[2:]"`
9 | else
10 | FIDGET=$FIDGETDIR/$1
11 | fi
12 |
13 | echo "Creating fiddle to $FIDGET"
14 | # set -e makes sure that we exit on failure
15 | (set -e;
16 | # get the actual file path avoiding symlinks
17 | SOURCE="${BASH_SOURCE[0]}"
18 | while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
19 | DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
20 | SOURCE="$(readlink "$SOURCE")"
21 | [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
22 | done
23 | DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
24 |
25 | echo $DIR
26 | mkdir $FIDGET;
27 | cp $DIR/template/* $FIDGET;
28 | echo $FIDGET
29 | node $DIR/node_server.js $FIDGET >/dev/null 2>/dev/null &
30 | )
31 |
--------------------------------------------------------------------------------
/images/vim-fiddle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mohitleo9/vim-fidget/4309192ab420b46f9c0c7a9feaee367497e90561/images/vim-fiddle.gif
--------------------------------------------------------------------------------
/node_server.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var server = require('http').createServer(httpHandler),
4 | spawn = require('child_process').spawn,
5 | fs = require('fs'),
6 | exec = require('child_process').exec,
7 | io = require('socket.io').listen(server),
8 | querystring = require('querystring'),
9 | url = require('url'),
10 | send = require('send'),
11 | server,
12 | socket;
13 |
14 | server.listen(8092);
15 | var assetsLocation = process.argv[2];
16 |
17 | function httpHandler(req, res) {
18 | switch(req.method){
19 | case 'GET':
20 | path = url.parse(req.url).pathname;
21 | if (path.indexOf('read/') > -1){
22 | // this means stream the contents of the file
23 | fileName = path.substring(path.indexOf('read/') + 'read/'.length);
24 | buf = fs.readFileSync(assetsLocation + "/" + fileName);
25 | res.write(buf.toString());
26 | res.end();
27 | return;
28 | }
29 | // nodejs automatically provide the current assetsLocation path
30 | if (path === null || path === '/') {
31 | res.write(assetsLocation);
32 | res.end();
33 | return;
34 | }
35 | send(req, path, {root: assetsLocation})
36 | .pipe(res);
37 | return;
38 | case 'POST':
39 | var postData = '';
40 | req.on('data', function(chunck) {
41 | postData += chunck.toString();
42 | });
43 | req.on('end', function () {
44 | postData = querystring.parse(postData);
45 |
46 | if(postData.action === 'cssReload'){
47 | io.emit('cssReload', postData.name);
48 | }
49 |
50 | if(postData.action === 'reload'){
51 | io.emit('reload', 'reload');
52 | }
53 | });
54 |
55 | res.write('ok');
56 | res.end();
57 | return;
58 |
59 | case 'PUT':
60 | if (process.platform.toLowerCase().indexOf('darwin') >= 0){
61 | spawn('open', ['http://localhost:8092' + req.url]);
62 | }
63 | else { // assume unix/linux
64 | spawn('xdg-open', ['http://localhost:8092' + req.url]);
65 | }
66 | res.write('ok');
67 | res.end();
68 | return;
69 |
70 | case 'DELETE':
71 | io.emit('die', 'die');
72 | process.exit(1);
73 | return;
74 |
75 | case 'READ':
76 | return;
77 | }
78 | }
79 |
80 | io.on('connection', function(socket) {
81 | console.log("user connected");
82 | });
83 |
84 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vim-fidget",
3 | "version": "0.0.2",
4 | "main": "node_server.js",
5 | "bin": {
6 | "vim-fidget": "./fidget.sh"
7 | },
8 | "preferGlobal": "true",
9 | "dependencies": {
10 | "socket.io": "^1.0.6",
11 | "send": "^0.8.3"
12 | },
13 | "devDependencies": {
14 | "grunt": "^0.4.5",
15 | "grunt-cli": "^0.1.13",
16 | "grunt-concurrent": "^0.5.0",
17 | "grunt-contrib-watch": "^0.6.1",
18 | "grunt-nodemon": "^0.3.0",
19 | "grunt-shell": "^0.7.0",
20 | "send": "^0.8.3",
21 | "socket.io": "^1.0.6"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/plugin/fidget.vim:
--------------------------------------------------------------------------------
1 | if (exists("g:vim_fidget_loaded") && g:vim_fidget_loaded)
2 | finish
3 | endif
4 | let g:vim_fidget_loaded = 1
5 | " # Configuration
6 |
7 | function! s:reloadCss()
8 | call system("curl -d 'action=cssReload&name=main.css' http://localhost:8092/ &>/dev/null &")
9 | endfu
10 |
11 |
12 | function! s:reload()
13 | call system("curl -d 'action=reload' http://localhost:8092/ &>/dev/null &")
14 | endfu
15 | " for some reason putting this inside a function does not work
16 | let s:path = expand(':p:h:h')
17 | " This is necessary for stuff to take place :)
18 | let s:fidget_path = s:path.'/fidget.sh'
19 | function! s:startDaemon()
20 | silent call system(s:fidget_path)
21 | " this is to wait for the server to startup
22 | while empty(system("curl -s localhost:8092"))
23 | exe 'sleep 100m'
24 | endwhile
25 | let g:fidget_files_path = system("curl -s localhost:8092")
26 | endfu
27 |
28 | function! s:killDaemon()
29 | call system("curl -s -X DELETE http://localhost:8092/ &>/dev/null")
30 | endfu
31 |
32 |
33 | function! s:openBrowser()
34 | call system("curl -s -X PUT http://localhost:8092/index.html &>/dev/null &")
35 | endfu
36 |
37 | function! s:createJsFiddle()
38 | call system("curl -s -X PUT http://localhost:8092/jsFiddle.html &>/dev/null &")
39 | endfunction
40 |
41 | fu! s:cleanUp()
42 | call s:killDaemon()
43 | au! fidget-start_commands *
44 | endfu
45 |
46 |
47 | fu! s:start_vim_fidget()
48 | " load the files
49 | call s:startDaemon()
50 | tabnew
51 | exe 'e '.g:fidget_files_path.'/index.html'
52 | exe 'split '.g:fidget_files_path.'/main.js'
53 | exe 'vsplit '.g:fidget_files_path.'/main.css'
54 | " # Define the autocmds "
55 | aug fidget-start_commands
56 | au!
57 | au BufWritePost *main.css call s:reloadCss()
58 | au BufWritePost *main.js call s:reload()
59 | au BufWritePost *index.html call s:reload()
60 | au BufDelete,BufUnload,BufUnload *index.html call s:cleanUp()
61 | au BufDelete,BufUnload,BufUnload *main.css call s:cleanUp()
62 | au BufDelete,BufUnload,BufUnload,BufWipeout *main.js call s:cleanUp()
63 | au VimLeavePre * call s:cleanUp()
64 | aug END
65 | call s:openBrowser()
66 | endfu
67 |
68 | command! -nargs=0 VimFidget call s:start_vim_fidget()
69 | command! -nargs=0 VimFidgetBrowse call s:createJsFiddle()
70 | command! -nargs=0 VimFidgetKillServer call s:cleanUp()
71 |
--------------------------------------------------------------------------------
/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | asdf asdf ;;;;asdf asdf asdf
10 | asdf asdf ;;;;asdf asdf asdf
11 | asdf asdf ;;;;asdf asdf asdf
12 | asdf asdf ;;;;asdf asdf asdf
13 | asdf asdf ;;;;asdf asdf asdf
14 | asdf asdf ;;;;asdf asdf asdf
15 | asdf asdf ;;;;asdf asdf asdf
16 | asdf asdf ;;;;asdf asdf asdf
17 |
18 |
19 |
--------------------------------------------------------------------------------
/template/jsFiddle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 0 && !this.encoding) {
444 | var pack = this.packetBuffer.shift();
445 | this.packet(pack);
446 | }
447 | };
448 |
449 | /**
450 | * Clean up transport subscriptions and packet buffer.
451 | *
452 | * @api private
453 | */
454 |
455 | Manager.prototype.cleanup = function(){
456 | var sub;
457 | while (sub = this.subs.shift()) sub.destroy();
458 |
459 | this.packetBuffer = [];
460 | this.encoding = false;
461 |
462 | this.decoder.destroy();
463 | };
464 |
465 | /**
466 | * Close the current socket.
467 | *
468 | * @api private
469 | */
470 |
471 | Manager.prototype.close =
472 | Manager.prototype.disconnect = function(){
473 | this.skipReconnect = true;
474 | this.engine.close();
475 | };
476 |
477 | /**
478 | * Called upon engine close.
479 | *
480 | * @api private
481 | */
482 |
483 | Manager.prototype.onclose = function(reason){
484 | debug('close');
485 | this.cleanup();
486 | this.readyState = 'closed';
487 | this.emit('close', reason);
488 | if (this._reconnection && !this.skipReconnect) {
489 | this.reconnect();
490 | }
491 | };
492 |
493 | /**
494 | * Attempt a reconnection.
495 | *
496 | * @api private
497 | */
498 |
499 | Manager.prototype.reconnect = function(){
500 | if (this.reconnecting) return this;
501 |
502 | var self = this;
503 | this.attempts++;
504 |
505 | if (this.attempts > this._reconnectionAttempts) {
506 | debug('reconnect failed');
507 | this.emitAll('reconnect_failed');
508 | this.reconnecting = false;
509 | } else {
510 | var delay = this.attempts * this.reconnectionDelay();
511 | delay = Math.min(delay, this.reconnectionDelayMax());
512 | debug('will wait %dms before reconnect attempt', delay);
513 |
514 | this.reconnecting = true;
515 | var timer = setTimeout(function(){
516 | debug('attempting reconnect');
517 | self.emitAll('reconnect_attempt', self.attempts);
518 | self.emitAll('reconnecting', self.attempts);
519 | self.open(function(err){
520 | if (err) {
521 | debug('reconnect attempt error');
522 | self.reconnecting = false;
523 | self.reconnect();
524 | self.emitAll('reconnect_error', err.data);
525 | } else {
526 | debug('reconnect success');
527 | self.onreconnect();
528 | }
529 | });
530 | }, delay);
531 |
532 | this.subs.push({
533 | destroy: function(){
534 | clearTimeout(timer);
535 | }
536 | });
537 | }
538 | };
539 |
540 | /**
541 | * Called upon successful reconnect.
542 | *
543 | * @api private
544 | */
545 |
546 | Manager.prototype.onreconnect = function(){
547 | var attempt = this.attempts;
548 | this.attempts = 0;
549 | this.reconnecting = false;
550 | this.emitAll('reconnect', attempt);
551 | };
552 |
553 | },{"./on":4,"./socket":5,"./url":6,"component-bind":7,"component-emitter":8,"debug":9,"engine.io-client":11,"object-component":37,"socket.io-parser":40}],4:[function(require,module,exports){
554 |
555 | /**
556 | * Module exports.
557 | */
558 |
559 | module.exports = on;
560 |
561 | /**
562 | * Helper for subscriptions.
563 | *
564 | * @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter`
565 | * @param {String} event name
566 | * @param {Function} callback
567 | * @api public
568 | */
569 |
570 | function on(obj, ev, fn) {
571 | obj.on(ev, fn);
572 | return {
573 | destroy: function(){
574 | obj.removeListener(ev, fn);
575 | }
576 | };
577 | }
578 |
579 | },{}],5:[function(require,module,exports){
580 |
581 | /**
582 | * Module dependencies.
583 | */
584 |
585 | var parser = require('socket.io-parser');
586 | var Emitter = require('component-emitter');
587 | var toArray = require('to-array');
588 | var on = require('./on');
589 | var bind = require('component-bind');
590 | var debug = require('debug')('socket.io-client:socket');
591 | var hasBin = require('has-binary-data');
592 | var indexOf = require('indexof');
593 |
594 | /**
595 | * Module exports.
596 | */
597 |
598 | module.exports = exports = Socket;
599 |
600 | /**
601 | * Internal events (blacklisted).
602 | * These events can't be emitted by the user.
603 | *
604 | * @api private
605 | */
606 |
607 | var events = {
608 | connect: 1,
609 | connect_error: 1,
610 | connect_timeout: 1,
611 | disconnect: 1,
612 | error: 1,
613 | reconnect: 1,
614 | reconnect_attempt: 1,
615 | reconnect_failed: 1,
616 | reconnect_error: 1,
617 | reconnecting: 1
618 | };
619 |
620 | /**
621 | * Shortcut to `Emitter#emit`.
622 | */
623 |
624 | var emit = Emitter.prototype.emit;
625 |
626 | /**
627 | * `Socket` constructor.
628 | *
629 | * @api public
630 | */
631 |
632 | function Socket(io, nsp){
633 | this.io = io;
634 | this.nsp = nsp;
635 | this.json = this; // compat
636 | this.ids = 0;
637 | this.acks = {};
638 | this.open();
639 | this.receiveBuffer = [];
640 | this.sendBuffer = [];
641 | this.connected = false;
642 | this.disconnected = true;
643 | this.subEvents();
644 | }
645 |
646 | /**
647 | * Mix in `Emitter`.
648 | */
649 |
650 | Emitter(Socket.prototype);
651 |
652 | /**
653 | * Subscribe to open, close and packet events
654 | *
655 | * @api private
656 | */
657 |
658 | Socket.prototype.subEvents = function() {
659 | var io = this.io;
660 | this.subs = [
661 | on(io, 'open', bind(this, 'onopen')),
662 | on(io, 'packet', bind(this, 'onpacket')),
663 | on(io, 'close', bind(this, 'onclose'))
664 | ];
665 | };
666 |
667 | /**
668 | * Called upon engine `open`.
669 | *
670 | * @api private
671 | */
672 |
673 | Socket.prototype.open =
674 | Socket.prototype.connect = function(){
675 | if (this.connected) return this;
676 |
677 | this.io.open(); // ensure open
678 | if ('open' == this.io.readyState) this.onopen();
679 | return this;
680 | };
681 |
682 | /**
683 | * Sends a `message` event.
684 | *
685 | * @return {Socket} self
686 | * @api public
687 | */
688 |
689 | Socket.prototype.send = function(){
690 | var args = toArray(arguments);
691 | args.unshift('message');
692 | this.emit.apply(this, args);
693 | return this;
694 | };
695 |
696 | /**
697 | * Override `emit`.
698 | * If the event is in `events`, it's emitted normally.
699 | *
700 | * @param {String} event name
701 | * @return {Socket} self
702 | * @api public
703 | */
704 |
705 | Socket.prototype.emit = function(ev){
706 | if (events.hasOwnProperty(ev)) {
707 | emit.apply(this, arguments);
708 | return this;
709 | }
710 |
711 | var args = toArray(arguments);
712 | var parserType = parser.EVENT; // default
713 | if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
714 | var packet = { type: parserType, data: args };
715 |
716 | // event ack callback
717 | if ('function' == typeof args[args.length - 1]) {
718 | debug('emitting packet with ack id %d', this.ids);
719 | this.acks[this.ids] = args.pop();
720 | packet.id = this.ids++;
721 | }
722 |
723 | if (this.connected) {
724 | this.packet(packet);
725 | } else {
726 | this.sendBuffer.push(packet);
727 | }
728 |
729 | return this;
730 | };
731 |
732 | /**
733 | * Sends a packet.
734 | *
735 | * @param {Object} packet
736 | * @api private
737 | */
738 |
739 | Socket.prototype.packet = function(packet){
740 | packet.nsp = this.nsp;
741 | this.io.packet(packet);
742 | };
743 |
744 | /**
745 | * "Opens" the socket.
746 | *
747 | * @api private
748 | */
749 |
750 | Socket.prototype.onopen = function(){
751 | debug('transport is open - connecting');
752 |
753 | // write connect packet if necessary
754 | if ('/' != this.nsp) {
755 | this.packet({ type: parser.CONNECT });
756 | }
757 | };
758 |
759 | /**
760 | * Called upon engine `close`.
761 | *
762 | * @param {String} reason
763 | * @api private
764 | */
765 |
766 | Socket.prototype.onclose = function(reason){
767 | debug('close (%s)', reason);
768 | this.connected = false;
769 | this.disconnected = true;
770 | this.emit('disconnect', reason);
771 | };
772 |
773 | /**
774 | * Called with socket packet.
775 | *
776 | * @param {Object} packet
777 | * @api private
778 | */
779 |
780 | Socket.prototype.onpacket = function(packet){
781 | if (packet.nsp != this.nsp) return;
782 |
783 | switch (packet.type) {
784 | case parser.CONNECT:
785 | this.onconnect();
786 | break;
787 |
788 | case parser.EVENT:
789 | this.onevent(packet);
790 | break;
791 |
792 | case parser.BINARY_EVENT:
793 | this.onevent(packet);
794 | break;
795 |
796 | case parser.ACK:
797 | this.onack(packet);
798 | break;
799 |
800 | case parser.BINARY_ACK:
801 | this.onack(packet);
802 | break;
803 |
804 | case parser.DISCONNECT:
805 | this.ondisconnect();
806 | break;
807 |
808 | case parser.ERROR:
809 | this.emit('error', packet.data);
810 | break;
811 | }
812 | };
813 |
814 | /**
815 | * Called upon a server event.
816 | *
817 | * @param {Object} packet
818 | * @api private
819 | */
820 |
821 | Socket.prototype.onevent = function(packet){
822 | var args = packet.data || [];
823 | debug('emitting event %j', args);
824 |
825 | if (null != packet.id) {
826 | debug('attaching ack callback to event');
827 | args.push(this.ack(packet.id));
828 | }
829 |
830 | if (this.connected) {
831 | emit.apply(this, args);
832 | } else {
833 | this.receiveBuffer.push(args);
834 | }
835 | };
836 |
837 | /**
838 | * Produces an ack callback to emit with an event.
839 | *
840 | * @api private
841 | */
842 |
843 | Socket.prototype.ack = function(id){
844 | var self = this;
845 | var sent = false;
846 | return function(){
847 | // prevent double callbacks
848 | if (sent) return;
849 | sent = true;
850 | var args = toArray(arguments);
851 | debug('sending ack %j', args);
852 |
853 | var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK;
854 | self.packet({
855 | type: type,
856 | id: id,
857 | data: args
858 | });
859 | };
860 | };
861 |
862 | /**
863 | * Called upon a server acknowlegement.
864 | *
865 | * @param {Object} packet
866 | * @api private
867 | */
868 |
869 | Socket.prototype.onack = function(packet){
870 | debug('calling ack %s with %j', packet.id, packet.data);
871 | var fn = this.acks[packet.id];
872 | fn.apply(this, packet.data);
873 | delete this.acks[packet.id];
874 | };
875 |
876 | /**
877 | * Called upon server connect.
878 | *
879 | * @api private
880 | */
881 |
882 | Socket.prototype.onconnect = function(){
883 | this.connected = true;
884 | this.disconnected = false;
885 | this.emit('connect');
886 | this.emitBuffered();
887 | };
888 |
889 | /**
890 | * Emit buffered events (received and emitted).
891 | *
892 | * @api private
893 | */
894 |
895 | Socket.prototype.emitBuffered = function(){
896 | var i;
897 | for (i = 0; i < this.receiveBuffer.length; i++) {
898 | emit.apply(this, this.receiveBuffer[i]);
899 | }
900 | this.receiveBuffer = [];
901 |
902 | for (i = 0; i < this.sendBuffer.length; i++) {
903 | this.packet(this.sendBuffer[i]);
904 | }
905 | this.sendBuffer = [];
906 | };
907 |
908 | /**
909 | * Called upon server disconnect.
910 | *
911 | * @api private
912 | */
913 |
914 | Socket.prototype.ondisconnect = function(){
915 | debug('server disconnect (%s)', this.nsp);
916 | this.destroy();
917 | this.onclose('io server disconnect');
918 | };
919 |
920 | /**
921 | * Called upon forced client/server side disconnections,
922 | * this method ensures the manager stops tracking us and
923 | * that reconnections don't get triggered for this.
924 | *
925 | * @api private.
926 | */
927 |
928 | Socket.prototype.destroy = function(){
929 | // clean subscriptions to avoid reconnections
930 | for (var i = 0; i < this.subs.length; i++) {
931 | this.subs[i].destroy();
932 | }
933 |
934 | this.io.destroy(this);
935 | };
936 |
937 | /**
938 | * Disconnects the socket manually.
939 | *
940 | * @return {Socket} self
941 | * @api public
942 | */
943 |
944 | Socket.prototype.close =
945 | Socket.prototype.disconnect = function(){
946 | if (!this.connected) return this;
947 |
948 | debug('performing disconnect (%s)', this.nsp);
949 | this.packet({ type: parser.DISCONNECT });
950 |
951 | // remove socket from pool
952 | this.destroy();
953 |
954 | // fire events
955 | this.onclose('io client disconnect');
956 | return this;
957 | };
958 |
959 | },{"./on":4,"component-bind":7,"component-emitter":8,"debug":9,"has-binary-data":32,"indexof":36,"socket.io-parser":40,"to-array":43}],6:[function(require,module,exports){
960 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
961 | /**
962 | * Module dependencies.
963 | */
964 |
965 | var parseuri = require('parseuri');
966 | var debug = require('debug')('socket.io-client:url');
967 |
968 | /**
969 | * Module exports.
970 | */
971 |
972 | module.exports = url;
973 |
974 | /**
975 | * URL parser.
976 | *
977 | * @param {String} url
978 | * @param {Object} An object meant to mimic window.location.
979 | * Defaults to window.location.
980 | * @api public
981 | */
982 |
983 | function url(uri, loc){
984 | var obj = uri;
985 |
986 | // default to window.location
987 | var loc = loc || global.location;
988 | if (null == uri) uri = loc.protocol + '//' + loc.hostname;
989 |
990 | // relative path support
991 | if ('string' == typeof uri) {
992 | if ('/' == uri.charAt(0)) {
993 | if ('undefined' != typeof loc) {
994 | uri = loc.hostname + uri;
995 | }
996 | }
997 |
998 | if (!/^(https?|wss?):\/\//.test(uri)) {
999 | debug('protocol-less url %s', uri);
1000 | if ('undefined' != typeof loc) {
1001 | uri = loc.protocol + '//' + uri;
1002 | } else {
1003 | uri = 'https://' + uri;
1004 | }
1005 | }
1006 |
1007 | // parse
1008 | debug('parse %s', uri);
1009 | obj = parseuri(uri);
1010 | }
1011 |
1012 | // make sure we treat `localhost:80` and `localhost` equally
1013 | if (!obj.port) {
1014 | if (/^(http|ws)$/.test(obj.protocol)) {
1015 | obj.port = '80';
1016 | }
1017 | else if (/^(http|ws)s$/.test(obj.protocol)) {
1018 | obj.port = '443';
1019 | }
1020 | }
1021 |
1022 | obj.path = obj.path || '/';
1023 |
1024 | // define unique id
1025 | obj.id = obj.protocol + '://' + obj.host + ':' + obj.port;
1026 | // define href
1027 | obj.href = obj.protocol + '://' + obj.host + (loc && loc.port == obj.port ? '' : (':' + obj.port));
1028 |
1029 | return obj;
1030 | }
1031 |
1032 | },{"debug":9,"parseuri":38}],7:[function(require,module,exports){
1033 | /**
1034 | * Slice reference.
1035 | */
1036 |
1037 | var slice = [].slice;
1038 |
1039 | /**
1040 | * Bind `obj` to `fn`.
1041 | *
1042 | * @param {Object} obj
1043 | * @param {Function|String} fn or string
1044 | * @return {Function}
1045 | * @api public
1046 | */
1047 |
1048 | module.exports = function(obj, fn){
1049 | if ('string' == typeof fn) fn = obj[fn];
1050 | if ('function' != typeof fn) throw new Error('bind() requires a function');
1051 | var args = slice.call(arguments, 2);
1052 | return function(){
1053 | return fn.apply(obj, args.concat(slice.call(arguments)));
1054 | }
1055 | };
1056 |
1057 | },{}],8:[function(require,module,exports){
1058 |
1059 | /**
1060 | * Expose `Emitter`.
1061 | */
1062 |
1063 | module.exports = Emitter;
1064 |
1065 | /**
1066 | * Initialize a new `Emitter`.
1067 | *
1068 | * @api public
1069 | */
1070 |
1071 | function Emitter(obj) {
1072 | if (obj) return mixin(obj);
1073 | };
1074 |
1075 | /**
1076 | * Mixin the emitter properties.
1077 | *
1078 | * @param {Object} obj
1079 | * @return {Object}
1080 | * @api private
1081 | */
1082 |
1083 | function mixin(obj) {
1084 | for (var key in Emitter.prototype) {
1085 | obj[key] = Emitter.prototype[key];
1086 | }
1087 | return obj;
1088 | }
1089 |
1090 | /**
1091 | * Listen on the given `event` with `fn`.
1092 | *
1093 | * @param {String} event
1094 | * @param {Function} fn
1095 | * @return {Emitter}
1096 | * @api public
1097 | */
1098 |
1099 | Emitter.prototype.on =
1100 | Emitter.prototype.addEventListener = function(event, fn){
1101 | this._callbacks = this._callbacks || {};
1102 | (this._callbacks[event] = this._callbacks[event] || [])
1103 | .push(fn);
1104 | return this;
1105 | };
1106 |
1107 | /**
1108 | * Adds an `event` listener that will be invoked a single
1109 | * time then automatically removed.
1110 | *
1111 | * @param {String} event
1112 | * @param {Function} fn
1113 | * @return {Emitter}
1114 | * @api public
1115 | */
1116 |
1117 | Emitter.prototype.once = function(event, fn){
1118 | var self = this;
1119 | this._callbacks = this._callbacks || {};
1120 |
1121 | function on() {
1122 | self.off(event, on);
1123 | fn.apply(this, arguments);
1124 | }
1125 |
1126 | on.fn = fn;
1127 | this.on(event, on);
1128 | return this;
1129 | };
1130 |
1131 | /**
1132 | * Remove the given callback for `event` or all
1133 | * registered callbacks.
1134 | *
1135 | * @param {String} event
1136 | * @param {Function} fn
1137 | * @return {Emitter}
1138 | * @api public
1139 | */
1140 |
1141 | Emitter.prototype.off =
1142 | Emitter.prototype.removeListener =
1143 | Emitter.prototype.removeAllListeners =
1144 | Emitter.prototype.removeEventListener = function(event, fn){
1145 | this._callbacks = this._callbacks || {};
1146 |
1147 | // all
1148 | if (0 == arguments.length) {
1149 | this._callbacks = {};
1150 | return this;
1151 | }
1152 |
1153 | // specific event
1154 | var callbacks = this._callbacks[event];
1155 | if (!callbacks) return this;
1156 |
1157 | // remove all handlers
1158 | if (1 == arguments.length) {
1159 | delete this._callbacks[event];
1160 | return this;
1161 | }
1162 |
1163 | // remove specific handler
1164 | var cb;
1165 | for (var i = 0; i < callbacks.length; i++) {
1166 | cb = callbacks[i];
1167 | if (cb === fn || cb.fn === fn) {
1168 | callbacks.splice(i, 1);
1169 | break;
1170 | }
1171 | }
1172 | return this;
1173 | };
1174 |
1175 | /**
1176 | * Emit `event` with the given args.
1177 | *
1178 | * @param {String} event
1179 | * @param {Mixed} ...
1180 | * @return {Emitter}
1181 | */
1182 |
1183 | Emitter.prototype.emit = function(event){
1184 | this._callbacks = this._callbacks || {};
1185 | var args = [].slice.call(arguments, 1)
1186 | , callbacks = this._callbacks[event];
1187 |
1188 | if (callbacks) {
1189 | callbacks = callbacks.slice(0);
1190 | for (var i = 0, len = callbacks.length; i < len; ++i) {
1191 | callbacks[i].apply(this, args);
1192 | }
1193 | }
1194 |
1195 | return this;
1196 | };
1197 |
1198 | /**
1199 | * Return array of callbacks for `event`.
1200 | *
1201 | * @param {String} event
1202 | * @return {Array}
1203 | * @api public
1204 | */
1205 |
1206 | Emitter.prototype.listeners = function(event){
1207 | this._callbacks = this._callbacks || {};
1208 | return this._callbacks[event] || [];
1209 | };
1210 |
1211 | /**
1212 | * Check if this emitter has `event` handlers.
1213 | *
1214 | * @param {String} event
1215 | * @return {Boolean}
1216 | * @api public
1217 | */
1218 |
1219 | Emitter.prototype.hasListeners = function(event){
1220 | return !! this.listeners(event).length;
1221 | };
1222 |
1223 | },{}],9:[function(require,module,exports){
1224 |
1225 | /**
1226 | * Expose `debug()` as the module.
1227 | */
1228 |
1229 | module.exports = debug;
1230 |
1231 | /**
1232 | * Create a debugger with the given `name`.
1233 | *
1234 | * @param {String} name
1235 | * @return {Type}
1236 | * @api public
1237 | */
1238 |
1239 | function debug(name) {
1240 | if (!debug.enabled(name)) return function(){};
1241 |
1242 | return function(fmt){
1243 | fmt = coerce(fmt);
1244 |
1245 | var curr = new Date;
1246 | var ms = curr - (debug[name] || curr);
1247 | debug[name] = curr;
1248 |
1249 | fmt = name
1250 | + ' '
1251 | + fmt
1252 | + ' +' + debug.humanize(ms);
1253 |
1254 | // This hackery is required for IE8
1255 | // where `console.log` doesn't have 'apply'
1256 | window.console
1257 | && console.log
1258 | && Function.prototype.apply.call(console.log, console, arguments);
1259 | }
1260 | }
1261 |
1262 | /**
1263 | * The currently active debug mode names.
1264 | */
1265 |
1266 | debug.names = [];
1267 | debug.skips = [];
1268 |
1269 | /**
1270 | * Enables a debug mode by name. This can include modes
1271 | * separated by a colon and wildcards.
1272 | *
1273 | * @param {String} name
1274 | * @api public
1275 | */
1276 |
1277 | debug.enable = function(name) {
1278 | try {
1279 | localStorage.debug = name;
1280 | } catch(e){}
1281 |
1282 | var split = (name || '').split(/[\s,]+/)
1283 | , len = split.length;
1284 |
1285 | for (var i = 0; i < len; i++) {
1286 | name = split[i].replace('*', '.*?');
1287 | if (name[0] === '-') {
1288 | debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
1289 | }
1290 | else {
1291 | debug.names.push(new RegExp('^' + name + '$'));
1292 | }
1293 | }
1294 | };
1295 |
1296 | /**
1297 | * Disable debug output.
1298 | *
1299 | * @api public
1300 | */
1301 |
1302 | debug.disable = function(){
1303 | debug.enable('');
1304 | };
1305 |
1306 | /**
1307 | * Humanize the given `ms`.
1308 | *
1309 | * @param {Number} m
1310 | * @return {String}
1311 | * @api private
1312 | */
1313 |
1314 | debug.humanize = function(ms) {
1315 | var sec = 1000
1316 | , min = 60 * 1000
1317 | , hour = 60 * min;
1318 |
1319 | if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
1320 | if (ms >= min) return (ms / min).toFixed(1) + 'm';
1321 | if (ms >= sec) return (ms / sec | 0) + 's';
1322 | return ms + 'ms';
1323 | };
1324 |
1325 | /**
1326 | * Returns true if the given mode name is enabled, false otherwise.
1327 | *
1328 | * @param {String} name
1329 | * @return {Boolean}
1330 | * @api public
1331 | */
1332 |
1333 | debug.enabled = function(name) {
1334 | for (var i = 0, len = debug.skips.length; i < len; i++) {
1335 | if (debug.skips[i].test(name)) {
1336 | return false;
1337 | }
1338 | }
1339 | for (var i = 0, len = debug.names.length; i < len; i++) {
1340 | if (debug.names[i].test(name)) {
1341 | return true;
1342 | }
1343 | }
1344 | return false;
1345 | };
1346 |
1347 | /**
1348 | * Coerce `val`.
1349 | */
1350 |
1351 | function coerce(val) {
1352 | if (val instanceof Error) return val.stack || val.message;
1353 | return val;
1354 | }
1355 |
1356 | // persist
1357 |
1358 | try {
1359 | if (window.localStorage) debug.enable(localStorage.debug);
1360 | } catch(e){}
1361 |
1362 | },{}],10:[function(require,module,exports){
1363 |
1364 | /**
1365 | * Module dependencies.
1366 | */
1367 |
1368 | var index = require('indexof');
1369 |
1370 | /**
1371 | * Expose `Emitter`.
1372 | */
1373 |
1374 | module.exports = Emitter;
1375 |
1376 | /**
1377 | * Initialize a new `Emitter`.
1378 | *
1379 | * @api public
1380 | */
1381 |
1382 | function Emitter(obj) {
1383 | if (obj) return mixin(obj);
1384 | };
1385 |
1386 | /**
1387 | * Mixin the emitter properties.
1388 | *
1389 | * @param {Object} obj
1390 | * @return {Object}
1391 | * @api private
1392 | */
1393 |
1394 | function mixin(obj) {
1395 | for (var key in Emitter.prototype) {
1396 | obj[key] = Emitter.prototype[key];
1397 | }
1398 | return obj;
1399 | }
1400 |
1401 | /**
1402 | * Listen on the given `event` with `fn`.
1403 | *
1404 | * @param {String} event
1405 | * @param {Function} fn
1406 | * @return {Emitter}
1407 | * @api public
1408 | */
1409 |
1410 | Emitter.prototype.on = function(event, fn){
1411 | this._callbacks = this._callbacks || {};
1412 | (this._callbacks[event] = this._callbacks[event] || [])
1413 | .push(fn);
1414 | return this;
1415 | };
1416 |
1417 | /**
1418 | * Adds an `event` listener that will be invoked a single
1419 | * time then automatically removed.
1420 | *
1421 | * @param {String} event
1422 | * @param {Function} fn
1423 | * @return {Emitter}
1424 | * @api public
1425 | */
1426 |
1427 | Emitter.prototype.once = function(event, fn){
1428 | var self = this;
1429 | this._callbacks = this._callbacks || {};
1430 |
1431 | function on() {
1432 | self.off(event, on);
1433 | fn.apply(this, arguments);
1434 | }
1435 |
1436 | fn._off = on;
1437 | this.on(event, on);
1438 | return this;
1439 | };
1440 |
1441 | /**
1442 | * Remove the given callback for `event` or all
1443 | * registered callbacks.
1444 | *
1445 | * @param {String} event
1446 | * @param {Function} fn
1447 | * @return {Emitter}
1448 | * @api public
1449 | */
1450 |
1451 | Emitter.prototype.off =
1452 | Emitter.prototype.removeListener =
1453 | Emitter.prototype.removeAllListeners = function(event, fn){
1454 | this._callbacks = this._callbacks || {};
1455 |
1456 | // all
1457 | if (0 == arguments.length) {
1458 | this._callbacks = {};
1459 | return this;
1460 | }
1461 |
1462 | // specific event
1463 | var callbacks = this._callbacks[event];
1464 | if (!callbacks) return this;
1465 |
1466 | // remove all handlers
1467 | if (1 == arguments.length) {
1468 | delete this._callbacks[event];
1469 | return this;
1470 | }
1471 |
1472 | // remove specific handler
1473 | var i = index(callbacks, fn._off || fn);
1474 | if (~i) callbacks.splice(i, 1);
1475 | return this;
1476 | };
1477 |
1478 | /**
1479 | * Emit `event` with the given args.
1480 | *
1481 | * @param {String} event
1482 | * @param {Mixed} ...
1483 | * @return {Emitter}
1484 | */
1485 |
1486 | Emitter.prototype.emit = function(event){
1487 | this._callbacks = this._callbacks || {};
1488 | var args = [].slice.call(arguments, 1)
1489 | , callbacks = this._callbacks[event];
1490 |
1491 | if (callbacks) {
1492 | callbacks = callbacks.slice(0);
1493 | for (var i = 0, len = callbacks.length; i < len; ++i) {
1494 | callbacks[i].apply(this, args);
1495 | }
1496 | }
1497 |
1498 | return this;
1499 | };
1500 |
1501 | /**
1502 | * Return array of callbacks for `event`.
1503 | *
1504 | * @param {String} event
1505 | * @return {Array}
1506 | * @api public
1507 | */
1508 |
1509 | Emitter.prototype.listeners = function(event){
1510 | this._callbacks = this._callbacks || {};
1511 | return this._callbacks[event] || [];
1512 | };
1513 |
1514 | /**
1515 | * Check if this emitter has `event` handlers.
1516 | *
1517 | * @param {String} event
1518 | * @return {Boolean}
1519 | * @api public
1520 | */
1521 |
1522 | Emitter.prototype.hasListeners = function(event){
1523 | return !! this.listeners(event).length;
1524 | };
1525 |
1526 | },{"indexof":36}],11:[function(require,module,exports){
1527 |
1528 | module.exports = require('./lib/');
1529 |
1530 | },{"./lib/":12}],12:[function(require,module,exports){
1531 |
1532 | module.exports = require('./socket');
1533 |
1534 | /**
1535 | * Exports parser
1536 | *
1537 | * @api public
1538 | *
1539 | */
1540 | module.exports.parser = require('engine.io-parser');
1541 |
1542 | },{"./socket":13,"engine.io-parser":22}],13:[function(require,module,exports){
1543 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
1544 | * Module dependencies.
1545 | */
1546 |
1547 | var transports = require('./transports');
1548 | var Emitter = require('component-emitter');
1549 | var debug = require('debug')('engine.io-client:socket');
1550 | var index = require('indexof');
1551 | var parser = require('engine.io-parser');
1552 | var parseuri = require('parseuri');
1553 | var parsejson = require('parsejson');
1554 | var parseqs = require('parseqs');
1555 |
1556 | /**
1557 | * Module exports.
1558 | */
1559 |
1560 | module.exports = Socket;
1561 |
1562 | /**
1563 | * Noop function.
1564 | *
1565 | * @api private
1566 | */
1567 |
1568 | function noop(){}
1569 |
1570 | /**
1571 | * Socket constructor.
1572 | *
1573 | * @param {String|Object} uri or options
1574 | * @param {Object} options
1575 | * @api public
1576 | */
1577 |
1578 | function Socket(uri, opts){
1579 | if (!(this instanceof Socket)) return new Socket(uri, opts);
1580 |
1581 | opts = opts || {};
1582 |
1583 | if (uri && 'object' == typeof uri) {
1584 | opts = uri;
1585 | uri = null;
1586 | }
1587 |
1588 | if (uri) {
1589 | uri = parseuri(uri);
1590 | opts.host = uri.host;
1591 | opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
1592 | opts.port = uri.port;
1593 | if (uri.query) opts.query = uri.query;
1594 | }
1595 |
1596 | this.secure = null != opts.secure ? opts.secure :
1597 | (global.location && 'https:' == location.protocol);
1598 |
1599 | if (opts.host) {
1600 | var pieces = opts.host.split(':');
1601 | opts.hostname = pieces.shift();
1602 | if (pieces.length) opts.port = pieces.pop();
1603 | }
1604 |
1605 | this.agent = opts.agent || false;
1606 | this.hostname = opts.hostname ||
1607 | (global.location ? location.hostname : 'localhost');
1608 | this.port = opts.port || (global.location && location.port ?
1609 | location.port :
1610 | (this.secure ? 443 : 80));
1611 | this.query = opts.query || {};
1612 | if ('string' == typeof this.query) this.query = parseqs.decode(this.query);
1613 | this.upgrade = false !== opts.upgrade;
1614 | this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
1615 | this.forceJSONP = !!opts.forceJSONP;
1616 | this.forceBase64 = !!opts.forceBase64;
1617 | this.timestampParam = opts.timestampParam || 't';
1618 | this.timestampRequests = opts.timestampRequests;
1619 | this.transports = opts.transports || ['polling', 'websocket'];
1620 | this.readyState = '';
1621 | this.writeBuffer = [];
1622 | this.callbackBuffer = [];
1623 | this.policyPort = opts.policyPort || 843;
1624 | this.rememberUpgrade = opts.rememberUpgrade || false;
1625 | this.open();
1626 | this.binaryType = null;
1627 | this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
1628 | }
1629 |
1630 | Socket.priorWebsocketSuccess = false;
1631 |
1632 | /**
1633 | * Mix in `Emitter`.
1634 | */
1635 |
1636 | Emitter(Socket.prototype);
1637 |
1638 | /**
1639 | * Protocol version.
1640 | *
1641 | * @api public
1642 | */
1643 |
1644 | Socket.protocol = parser.protocol; // this is an int
1645 |
1646 | /**
1647 | * Expose deps for legacy compatibility
1648 | * and standalone browser access.
1649 | */
1650 |
1651 | Socket.Socket = Socket;
1652 | Socket.Transport = require('./transport');
1653 | Socket.transports = require('./transports');
1654 | Socket.parser = require('engine.io-parser');
1655 |
1656 | /**
1657 | * Creates transport of the given type.
1658 | *
1659 | * @param {String} transport name
1660 | * @return {Transport}
1661 | * @api private
1662 | */
1663 |
1664 | Socket.prototype.createTransport = function (name) {
1665 | debug('creating transport "%s"', name);
1666 | var query = clone(this.query);
1667 |
1668 | // append engine.io protocol identifier
1669 | query.EIO = parser.protocol;
1670 |
1671 | // transport name
1672 | query.transport = name;
1673 |
1674 | // session id if we already have one
1675 | if (this.id) query.sid = this.id;
1676 |
1677 | var transport = new transports[name]({
1678 | agent: this.agent,
1679 | hostname: this.hostname,
1680 | port: this.port,
1681 | secure: this.secure,
1682 | path: this.path,
1683 | query: query,
1684 | forceJSONP: this.forceJSONP,
1685 | forceBase64: this.forceBase64,
1686 | timestampRequests: this.timestampRequests,
1687 | timestampParam: this.timestampParam,
1688 | policyPort: this.policyPort,
1689 | socket: this
1690 | });
1691 |
1692 | return transport;
1693 | };
1694 |
1695 | function clone (obj) {
1696 | var o = {};
1697 | for (var i in obj) {
1698 | if (obj.hasOwnProperty(i)) {
1699 | o[i] = obj[i];
1700 | }
1701 | }
1702 | return o;
1703 | }
1704 |
1705 | /**
1706 | * Initializes transport to use and starts probe.
1707 | *
1708 | * @api private
1709 | */
1710 | Socket.prototype.open = function () {
1711 | var transport;
1712 | if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
1713 | transport = 'websocket';
1714 | } else {
1715 | transport = this.transports[0];
1716 | }
1717 | this.readyState = 'opening';
1718 | var transport = this.createTransport(transport);
1719 | transport.open();
1720 | this.setTransport(transport);
1721 | };
1722 |
1723 | /**
1724 | * Sets the current transport. Disables the existing one (if any).
1725 | *
1726 | * @api private
1727 | */
1728 |
1729 | Socket.prototype.setTransport = function(transport){
1730 | debug('setting transport %s', transport.name);
1731 | var self = this;
1732 |
1733 | if (this.transport) {
1734 | debug('clearing existing transport %s', this.transport.name);
1735 | this.transport.removeAllListeners();
1736 | }
1737 |
1738 | // set up transport
1739 | this.transport = transport;
1740 |
1741 | // set up transport listeners
1742 | transport
1743 | .on('drain', function(){
1744 | self.onDrain();
1745 | })
1746 | .on('packet', function(packet){
1747 | self.onPacket(packet);
1748 | })
1749 | .on('error', function(e){
1750 | self.onError(e);
1751 | })
1752 | .on('close', function(){
1753 | self.onClose('transport close');
1754 | });
1755 | };
1756 |
1757 | /**
1758 | * Probes a transport.
1759 | *
1760 | * @param {String} transport name
1761 | * @api private
1762 | */
1763 |
1764 | Socket.prototype.probe = function (name) {
1765 | debug('probing transport "%s"', name);
1766 | var transport = this.createTransport(name, { probe: 1 })
1767 | , failed = false
1768 | , self = this;
1769 |
1770 | Socket.priorWebsocketSuccess = false;
1771 |
1772 | function onTransportOpen(){
1773 | if (self.onlyBinaryUpgrades) {
1774 | var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
1775 | failed = failed || upgradeLosesBinary;
1776 | }
1777 | if (failed) return;
1778 |
1779 | debug('probe transport "%s" opened', name);
1780 | transport.send([{ type: 'ping', data: 'probe' }]);
1781 | transport.once('packet', function (msg) {
1782 | if (failed) return;
1783 | if ('pong' == msg.type && 'probe' == msg.data) {
1784 | debug('probe transport "%s" pong', name);
1785 | self.upgrading = true;
1786 | self.emit('upgrading', transport);
1787 | Socket.priorWebsocketSuccess = 'websocket' == transport.name;
1788 |
1789 | debug('pausing current transport "%s"', self.transport.name);
1790 | self.transport.pause(function () {
1791 | if (failed) return;
1792 | if ('closed' == self.readyState || 'closing' == self.readyState) {
1793 | return;
1794 | }
1795 | debug('changing transport and sending upgrade packet');
1796 |
1797 | cleanup();
1798 |
1799 | self.setTransport(transport);
1800 | transport.send([{ type: 'upgrade' }]);
1801 | self.emit('upgrade', transport);
1802 | transport = null;
1803 | self.upgrading = false;
1804 | self.flush();
1805 | });
1806 | } else {
1807 | debug('probe transport "%s" failed', name);
1808 | var err = new Error('probe error');
1809 | err.transport = transport.name;
1810 | self.emit('upgradeError', err);
1811 | }
1812 | });
1813 | }
1814 |
1815 | function freezeTransport() {
1816 | if (failed) return;
1817 |
1818 | // Any callback called by transport should be ignored since now
1819 | failed = true;
1820 |
1821 | cleanup();
1822 |
1823 | transport.close();
1824 | transport = null;
1825 | }
1826 |
1827 | //Handle any error that happens while probing
1828 | function onerror(err) {
1829 | var error = new Error('probe error: ' + err);
1830 | error.transport = transport.name;
1831 |
1832 | freezeTransport();
1833 |
1834 | debug('probe transport "%s" failed because of error: %s', name, err);
1835 |
1836 | self.emit('upgradeError', error);
1837 | }
1838 |
1839 | function onTransportClose(){
1840 | onerror("transport closed");
1841 | }
1842 |
1843 | //When the socket is closed while we're probing
1844 | function onclose(){
1845 | onerror("socket closed");
1846 | }
1847 |
1848 | //When the socket is upgraded while we're probing
1849 | function onupgrade(to){
1850 | if (transport && to.name != transport.name) {
1851 | debug('"%s" works - aborting "%s"', to.name, transport.name);
1852 | freezeTransport();
1853 | }
1854 | }
1855 |
1856 | //Remove all listeners on the transport and on self
1857 | function cleanup(){
1858 | transport.removeListener('open', onTransportOpen);
1859 | transport.removeListener('error', onerror);
1860 | transport.removeListener('close', onTransportClose);
1861 | self.removeListener('close', onclose);
1862 | self.removeListener('upgrading', onupgrade);
1863 | }
1864 |
1865 | transport.once('open', onTransportOpen);
1866 | transport.once('error', onerror);
1867 | transport.once('close', onTransportClose);
1868 |
1869 | this.once('close', onclose);
1870 | this.once('upgrading', onupgrade);
1871 |
1872 | transport.open();
1873 |
1874 | };
1875 |
1876 | /**
1877 | * Called when connection is deemed open.
1878 | *
1879 | * @api public
1880 | */
1881 |
1882 | Socket.prototype.onOpen = function () {
1883 | debug('socket open');
1884 | this.readyState = 'open';
1885 | Socket.priorWebsocketSuccess = 'websocket' == this.transport.name;
1886 | this.emit('open');
1887 | this.flush();
1888 |
1889 | // we check for `readyState` in case an `open`
1890 | // listener already closed the socket
1891 | if ('open' == this.readyState && this.upgrade && this.transport.pause) {
1892 | debug('starting upgrade probes');
1893 | for (var i = 0, l = this.upgrades.length; i < l; i++) {
1894 | this.probe(this.upgrades[i]);
1895 | }
1896 | }
1897 | };
1898 |
1899 | /**
1900 | * Handles a packet.
1901 | *
1902 | * @api private
1903 | */
1904 |
1905 | Socket.prototype.onPacket = function (packet) {
1906 | if ('opening' == this.readyState || 'open' == this.readyState) {
1907 | debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
1908 |
1909 | this.emit('packet', packet);
1910 |
1911 | // Socket is live - any packet counts
1912 | this.emit('heartbeat');
1913 |
1914 | switch (packet.type) {
1915 | case 'open':
1916 | this.onHandshake(parsejson(packet.data));
1917 | break;
1918 |
1919 | case 'pong':
1920 | this.setPing();
1921 | break;
1922 |
1923 | case 'error':
1924 | var err = new Error('server error');
1925 | err.code = packet.data;
1926 | this.emit('error', err);
1927 | break;
1928 |
1929 | case 'message':
1930 | this.emit('data', packet.data);
1931 | this.emit('message', packet.data);
1932 | break;
1933 | }
1934 | } else {
1935 | debug('packet received with socket readyState "%s"', this.readyState);
1936 | }
1937 | };
1938 |
1939 | /**
1940 | * Called upon handshake completion.
1941 | *
1942 | * @param {Object} handshake obj
1943 | * @api private
1944 | */
1945 |
1946 | Socket.prototype.onHandshake = function (data) {
1947 | this.emit('handshake', data);
1948 | this.id = data.sid;
1949 | this.transport.query.sid = data.sid;
1950 | this.upgrades = this.filterUpgrades(data.upgrades);
1951 | this.pingInterval = data.pingInterval;
1952 | this.pingTimeout = data.pingTimeout;
1953 | this.onOpen();
1954 | // In case open handler closes socket
1955 | if ('closed' == this.readyState) return;
1956 | this.setPing();
1957 |
1958 | // Prolong liveness of socket on heartbeat
1959 | this.removeListener('heartbeat', this.onHeartbeat);
1960 | this.on('heartbeat', this.onHeartbeat);
1961 | };
1962 |
1963 | /**
1964 | * Resets ping timeout.
1965 | *
1966 | * @api private
1967 | */
1968 |
1969 | Socket.prototype.onHeartbeat = function (timeout) {
1970 | clearTimeout(this.pingTimeoutTimer);
1971 | var self = this;
1972 | self.pingTimeoutTimer = setTimeout(function () {
1973 | if ('closed' == self.readyState) return;
1974 | self.onClose('ping timeout');
1975 | }, timeout || (self.pingInterval + self.pingTimeout));
1976 | };
1977 |
1978 | /**
1979 | * Pings server every `this.pingInterval` and expects response
1980 | * within `this.pingTimeout` or closes connection.
1981 | *
1982 | * @api private
1983 | */
1984 |
1985 | Socket.prototype.setPing = function () {
1986 | var self = this;
1987 | clearTimeout(self.pingIntervalTimer);
1988 | self.pingIntervalTimer = setTimeout(function () {
1989 | debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
1990 | self.ping();
1991 | self.onHeartbeat(self.pingTimeout);
1992 | }, self.pingInterval);
1993 | };
1994 |
1995 | /**
1996 | * Sends a ping packet.
1997 | *
1998 | * @api public
1999 | */
2000 |
2001 | Socket.prototype.ping = function () {
2002 | this.sendPacket('ping');
2003 | };
2004 |
2005 | /**
2006 | * Called on `drain` event
2007 | *
2008 | * @api private
2009 | */
2010 |
2011 | Socket.prototype.onDrain = function() {
2012 | for (var i = 0; i < this.prevBufferLen; i++) {
2013 | if (this.callbackBuffer[i]) {
2014 | this.callbackBuffer[i]();
2015 | }
2016 | }
2017 |
2018 | this.writeBuffer.splice(0, this.prevBufferLen);
2019 | this.callbackBuffer.splice(0, this.prevBufferLen);
2020 |
2021 | // setting prevBufferLen = 0 is very important
2022 | // for example, when upgrading, upgrade packet is sent over,
2023 | // and a nonzero prevBufferLen could cause problems on `drain`
2024 | this.prevBufferLen = 0;
2025 |
2026 | if (this.writeBuffer.length == 0) {
2027 | this.emit('drain');
2028 | } else {
2029 | this.flush();
2030 | }
2031 | };
2032 |
2033 | /**
2034 | * Flush write buffers.
2035 | *
2036 | * @api private
2037 | */
2038 |
2039 | Socket.prototype.flush = function () {
2040 | if ('closed' != this.readyState && this.transport.writable &&
2041 | !this.upgrading && this.writeBuffer.length) {
2042 | debug('flushing %d packets in socket', this.writeBuffer.length);
2043 | this.transport.send(this.writeBuffer);
2044 | // keep track of current length of writeBuffer
2045 | // splice writeBuffer and callbackBuffer on `drain`
2046 | this.prevBufferLen = this.writeBuffer.length;
2047 | this.emit('flush');
2048 | }
2049 | };
2050 |
2051 | /**
2052 | * Sends a message.
2053 | *
2054 | * @param {String} message.
2055 | * @param {Function} callback function.
2056 | * @return {Socket} for chaining.
2057 | * @api public
2058 | */
2059 |
2060 | Socket.prototype.write =
2061 | Socket.prototype.send = function (msg, fn) {
2062 | this.sendPacket('message', msg, fn);
2063 | return this;
2064 | };
2065 |
2066 | /**
2067 | * Sends a packet.
2068 | *
2069 | * @param {String} packet type.
2070 | * @param {String} data.
2071 | * @param {Function} callback function.
2072 | * @api private
2073 | */
2074 |
2075 | Socket.prototype.sendPacket = function (type, data, fn) {
2076 | var packet = { type: type, data: data };
2077 | this.emit('packetCreate', packet);
2078 | this.writeBuffer.push(packet);
2079 | this.callbackBuffer.push(fn);
2080 | this.flush();
2081 | };
2082 |
2083 | /**
2084 | * Closes the connection.
2085 | *
2086 | * @api private
2087 | */
2088 |
2089 | Socket.prototype.close = function () {
2090 | if ('opening' == this.readyState || 'open' == this.readyState) {
2091 | this.onClose('forced close');
2092 | debug('socket closing - telling transport to close');
2093 | this.transport.close();
2094 | }
2095 |
2096 | return this;
2097 | };
2098 |
2099 | /**
2100 | * Called upon transport error
2101 | *
2102 | * @api private
2103 | */
2104 |
2105 | Socket.prototype.onError = function (err) {
2106 | debug('socket error %j', err);
2107 | Socket.priorWebsocketSuccess = false;
2108 | this.emit('error', err);
2109 | this.onClose('transport error', err);
2110 | };
2111 |
2112 | /**
2113 | * Called upon transport close.
2114 | *
2115 | * @api private
2116 | */
2117 |
2118 | Socket.prototype.onClose = function (reason, desc) {
2119 | if ('opening' == this.readyState || 'open' == this.readyState) {
2120 | debug('socket close with reason: "%s"', reason);
2121 | var self = this;
2122 |
2123 | // clear timers
2124 | clearTimeout(this.pingIntervalTimer);
2125 | clearTimeout(this.pingTimeoutTimer);
2126 |
2127 | // clean buffers in next tick, so developers can still
2128 | // grab the buffers on `close` event
2129 | setTimeout(function() {
2130 | self.writeBuffer = [];
2131 | self.callbackBuffer = [];
2132 | self.prevBufferLen = 0;
2133 | }, 0);
2134 |
2135 | // stop event from firing again for transport
2136 | this.transport.removeAllListeners('close');
2137 |
2138 | // ensure transport won't stay open
2139 | this.transport.close();
2140 |
2141 | // ignore further transport communication
2142 | this.transport.removeAllListeners();
2143 |
2144 | // set ready state
2145 | this.readyState = 'closed';
2146 |
2147 | // clear session id
2148 | this.id = null;
2149 |
2150 | // emit close event
2151 | this.emit('close', reason, desc);
2152 | }
2153 | };
2154 |
2155 | /**
2156 | * Filters upgrades, returning only those matching client transports.
2157 | *
2158 | * @param {Array} server upgrades
2159 | * @api private
2160 | *
2161 | */
2162 |
2163 | Socket.prototype.filterUpgrades = function (upgrades) {
2164 | var filteredUpgrades = [];
2165 | for (var i = 0, j = upgrades.length; i';
2576 | iframe = document.createElement(html);
2577 | } catch (e) {
2578 | iframe = document.createElement('iframe');
2579 | iframe.name = self.iframeId;
2580 | iframe.src = 'javascript:0';
2581 | }
2582 |
2583 | iframe.id = self.iframeId;
2584 |
2585 | self.form.appendChild(iframe);
2586 | self.iframe = iframe;
2587 | }
2588 |
2589 | initIframe();
2590 |
2591 | // escape \n to prevent it from being converted into \r\n by some UAs
2592 | // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
2593 | data = data.replace(rEscapedNewline, '\\\n');
2594 | this.area.value = data.replace(rNewline, '\\n');
2595 |
2596 | try {
2597 | this.form.submit();
2598 | } catch(e) {}
2599 |
2600 | if (this.iframe.attachEvent) {
2601 | this.iframe.onreadystatechange = function(){
2602 | if (self.iframe.readyState == 'complete') {
2603 | complete();
2604 | }
2605 | };
2606 | } else {
2607 | this.iframe.onload = complete;
2608 | }
2609 | };
2610 |
2611 | },{"./polling":18,"component-inherit":21}],17:[function(require,module,exports){
2612 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
2613 | * Module requirements.
2614 | */
2615 |
2616 | var XMLHttpRequest = require('xmlhttprequest');
2617 | var Polling = require('./polling');
2618 | var Emitter = require('component-emitter');
2619 | var inherit = require('component-inherit');
2620 | var debug = require('debug')('engine.io-client:polling-xhr');
2621 |
2622 | /**
2623 | * Module exports.
2624 | */
2625 |
2626 | module.exports = XHR;
2627 | module.exports.Request = Request;
2628 |
2629 | /**
2630 | * Empty function
2631 | */
2632 |
2633 | function empty(){}
2634 |
2635 | /**
2636 | * XHR Polling constructor.
2637 | *
2638 | * @param {Object} opts
2639 | * @api public
2640 | */
2641 |
2642 | function XHR(opts){
2643 | Polling.call(this, opts);
2644 |
2645 | if (global.location) {
2646 | var isSSL = 'https:' == location.protocol;
2647 | var port = location.port;
2648 |
2649 | // some user agents have empty `location.port`
2650 | if (!port) {
2651 | port = isSSL ? 443 : 80;
2652 | }
2653 |
2654 | this.xd = opts.hostname != global.location.hostname ||
2655 | port != opts.port;
2656 | }
2657 | }
2658 |
2659 | /**
2660 | * Inherits from Polling.
2661 | */
2662 |
2663 | inherit(XHR, Polling);
2664 |
2665 | /**
2666 | * XHR supports binary
2667 | */
2668 |
2669 | XHR.prototype.supportsBinary = true;
2670 |
2671 | /**
2672 | * Creates a request.
2673 | *
2674 | * @param {String} method
2675 | * @api private
2676 | */
2677 |
2678 | XHR.prototype.request = function(opts){
2679 | opts = opts || {};
2680 | opts.uri = this.uri();
2681 | opts.xd = this.xd;
2682 | opts.agent = this.agent || false;
2683 | opts.supportsBinary = this.supportsBinary;
2684 | return new Request(opts);
2685 | };
2686 |
2687 | /**
2688 | * Sends data.
2689 | *
2690 | * @param {String} data to send.
2691 | * @param {Function} called upon flush.
2692 | * @api private
2693 | */
2694 |
2695 | XHR.prototype.doWrite = function(data, fn){
2696 | var isBinary = typeof data !== 'string' && data !== undefined;
2697 | var req = this.request({ method: 'POST', data: data, isBinary: isBinary });
2698 | var self = this;
2699 | req.on('success', fn);
2700 | req.on('error', function(err){
2701 | self.onError('xhr post error', err);
2702 | });
2703 | this.sendXhr = req;
2704 | };
2705 |
2706 | /**
2707 | * Starts a poll cycle.
2708 | *
2709 | * @api private
2710 | */
2711 |
2712 | XHR.prototype.doPoll = function(){
2713 | debug('xhr poll');
2714 | var req = this.request();
2715 | var self = this;
2716 | req.on('data', function(data){
2717 | self.onData(data);
2718 | });
2719 | req.on('error', function(err){
2720 | self.onError('xhr poll error', err);
2721 | });
2722 | this.pollXhr = req;
2723 | };
2724 |
2725 | /**
2726 | * Request constructor
2727 | *
2728 | * @param {Object} options
2729 | * @api public
2730 | */
2731 |
2732 | function Request(opts){
2733 | this.method = opts.method || 'GET';
2734 | this.uri = opts.uri;
2735 | this.xd = !!opts.xd;
2736 | this.async = false !== opts.async;
2737 | this.data = undefined != opts.data ? opts.data : null;
2738 | this.agent = opts.agent;
2739 | this.create(opts.isBinary, opts.supportsBinary);
2740 | }
2741 |
2742 | /**
2743 | * Mix in `Emitter`.
2744 | */
2745 |
2746 | Emitter(Request.prototype);
2747 |
2748 | /**
2749 | * Creates the XHR object and sends the request.
2750 | *
2751 | * @api private
2752 | */
2753 |
2754 | Request.prototype.create = function(isBinary, supportsBinary){
2755 | var xhr = this.xhr = new XMLHttpRequest({ agent: this.agent, xdomain: this.xd });
2756 | var self = this;
2757 |
2758 | try {
2759 | debug('xhr open %s: %s', this.method, this.uri);
2760 | xhr.open(this.method, this.uri, this.async);
2761 | if (supportsBinary) {
2762 | // This has to be done after open because Firefox is stupid
2763 | // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
2764 | xhr.responseType = 'arraybuffer';
2765 | }
2766 |
2767 | if ('POST' == this.method) {
2768 | try {
2769 | if (isBinary) {
2770 | xhr.setRequestHeader('Content-type', 'application/octet-stream');
2771 | } else {
2772 | xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
2773 | }
2774 | } catch (e) {}
2775 | }
2776 |
2777 | // ie6 check
2778 | if ('withCredentials' in xhr) {
2779 | xhr.withCredentials = true;
2780 | }
2781 |
2782 | xhr.onreadystatechange = function(){
2783 | var data;
2784 |
2785 | try {
2786 | if (4 != xhr.readyState) return;
2787 | if (200 == xhr.status || 1223 == xhr.status) {
2788 | var contentType = xhr.getResponseHeader('Content-Type');
2789 | if (contentType === 'application/octet-stream') {
2790 | data = xhr.response;
2791 | } else {
2792 | if (!supportsBinary) {
2793 | data = xhr.responseText;
2794 | } else {
2795 | data = 'ok';
2796 | }
2797 | }
2798 | } else {
2799 | // make sure the `error` event handler that's user-set
2800 | // does not throw in the same tick and gets caught here
2801 | setTimeout(function(){
2802 | self.onError(xhr.status);
2803 | }, 0);
2804 | }
2805 | } catch (e) {
2806 | self.onError(e);
2807 | }
2808 |
2809 | if (null != data) {
2810 | self.onData(data);
2811 | }
2812 | };
2813 |
2814 | debug('xhr data %s', this.data);
2815 | xhr.send(this.data);
2816 | } catch (e) {
2817 | // Need to defer since .create() is called directly fhrom the constructor
2818 | // and thus the 'error' event can only be only bound *after* this exception
2819 | // occurs. Therefore, also, we cannot throw here at all.
2820 | setTimeout(function() {
2821 | self.onError(e);
2822 | }, 0);
2823 | return;
2824 | }
2825 |
2826 | if (global.document) {
2827 | this.index = Request.requestsCount++;
2828 | Request.requests[this.index] = this;
2829 | }
2830 | };
2831 |
2832 | /**
2833 | * Called upon successful response.
2834 | *
2835 | * @api private
2836 | */
2837 |
2838 | Request.prototype.onSuccess = function(){
2839 | this.emit('success');
2840 | this.cleanup();
2841 | };
2842 |
2843 | /**
2844 | * Called if we have data.
2845 | *
2846 | * @api private
2847 | */
2848 |
2849 | Request.prototype.onData = function(data){
2850 | this.emit('data', data);
2851 | this.onSuccess();
2852 | };
2853 |
2854 | /**
2855 | * Called upon error.
2856 | *
2857 | * @api private
2858 | */
2859 |
2860 | Request.prototype.onError = function(err){
2861 | this.emit('error', err);
2862 | this.cleanup();
2863 | };
2864 |
2865 | /**
2866 | * Cleans up house.
2867 | *
2868 | * @api private
2869 | */
2870 |
2871 | Request.prototype.cleanup = function(){
2872 | if ('undefined' == typeof this.xhr || null === this.xhr) {
2873 | return;
2874 | }
2875 | // xmlhttprequest
2876 | this.xhr.onreadystatechange = empty;
2877 |
2878 | try {
2879 | this.xhr.abort();
2880 | } catch(e) {}
2881 |
2882 | if (global.document) {
2883 | delete Request.requests[this.index];
2884 | }
2885 |
2886 | this.xhr = null;
2887 | };
2888 |
2889 | /**
2890 | * Aborts the request.
2891 | *
2892 | * @api public
2893 | */
2894 |
2895 | Request.prototype.abort = function(){
2896 | this.cleanup();
2897 | };
2898 |
2899 | /**
2900 | * Aborts pending requests when unloading the window. This is needed to prevent
2901 | * memory leaks (e.g. when using IE) and to ensure that no spurious error is
2902 | * emitted.
2903 | */
2904 |
2905 | if (global.document) {
2906 | Request.requestsCount = 0;
2907 | Request.requests = {};
2908 | if (global.attachEvent) {
2909 | global.attachEvent('onunload', unloadHandler);
2910 | } else if (global.addEventListener) {
2911 | global.addEventListener('beforeunload', unloadHandler);
2912 | }
2913 | }
2914 |
2915 | function unloadHandler() {
2916 | for (var i in Request.requests) {
2917 | if (Request.requests.hasOwnProperty(i)) {
2918 | Request.requests[i].abort();
2919 | }
2920 | }
2921 | }
2922 |
2923 | },{"./polling":18,"component-emitter":8,"component-inherit":21,"debug":9,"xmlhttprequest":20}],18:[function(require,module,exports){
2924 | /**
2925 | * Module dependencies.
2926 | */
2927 |
2928 | var Transport = require('../transport');
2929 | var parseqs = require('parseqs');
2930 | var parser = require('engine.io-parser');
2931 | var inherit = require('component-inherit');
2932 | var debug = require('debug')('engine.io-client:polling');
2933 |
2934 | /**
2935 | * Module exports.
2936 | */
2937 |
2938 | module.exports = Polling;
2939 |
2940 | /**
2941 | * Is XHR2 supported?
2942 | */
2943 |
2944 | var hasXHR2 = (function() {
2945 | var XMLHttpRequest = require('xmlhttprequest');
2946 | var xhr = new XMLHttpRequest({ agent: this.agent, xdomain: false });
2947 | return null != xhr.responseType;
2948 | })();
2949 |
2950 | /**
2951 | * Polling interface.
2952 | *
2953 | * @param {Object} opts
2954 | * @api private
2955 | */
2956 |
2957 | function Polling(opts){
2958 | var forceBase64 = (opts && opts.forceBase64);
2959 | if (!hasXHR2 || forceBase64) {
2960 | this.supportsBinary = false;
2961 | }
2962 | Transport.call(this, opts);
2963 | }
2964 |
2965 | /**
2966 | * Inherits from Transport.
2967 | */
2968 |
2969 | inherit(Polling, Transport);
2970 |
2971 | /**
2972 | * Transport name.
2973 | */
2974 |
2975 | Polling.prototype.name = 'polling';
2976 |
2977 | /**
2978 | * Opens the socket (triggers polling). We write a PING message to determine
2979 | * when the transport is open.
2980 | *
2981 | * @api private
2982 | */
2983 |
2984 | Polling.prototype.doOpen = function(){
2985 | this.poll();
2986 | };
2987 |
2988 | /**
2989 | * Pauses polling.
2990 | *
2991 | * @param {Function} callback upon buffers are flushed and transport is paused
2992 | * @api private
2993 | */
2994 |
2995 | Polling.prototype.pause = function(onPause){
2996 | var pending = 0;
2997 | var self = this;
2998 |
2999 | this.readyState = 'pausing';
3000 |
3001 | function pause(){
3002 | debug('paused');
3003 | self.readyState = 'paused';
3004 | onPause();
3005 | }
3006 |
3007 | if (this.polling || !this.writable) {
3008 | var total = 0;
3009 |
3010 | if (this.polling) {
3011 | debug('we are currently polling - waiting to pause');
3012 | total++;
3013 | this.once('pollComplete', function(){
3014 | debug('pre-pause polling complete');
3015 | --total || pause();
3016 | });
3017 | }
3018 |
3019 | if (!this.writable) {
3020 | debug('we are currently writing - waiting to pause');
3021 | total++;
3022 | this.once('drain', function(){
3023 | debug('pre-pause writing complete');
3024 | --total || pause();
3025 | });
3026 | }
3027 | } else {
3028 | pause();
3029 | }
3030 | };
3031 |
3032 | /**
3033 | * Starts polling cycle.
3034 | *
3035 | * @api public
3036 | */
3037 |
3038 | Polling.prototype.poll = function(){
3039 | debug('polling');
3040 | this.polling = true;
3041 | this.doPoll();
3042 | this.emit('poll');
3043 | };
3044 |
3045 | /**
3046 | * Overloads onData to detect payloads.
3047 | *
3048 | * @api private
3049 | */
3050 |
3051 | Polling.prototype.onData = function(data){
3052 | var self = this;
3053 | debug('polling got data %s', data);
3054 | var callback = function(packet, index, total) {
3055 | // if its the first message we consider the transport open
3056 | if ('opening' == self.readyState) {
3057 | self.onOpen();
3058 | }
3059 |
3060 | // if its a close packet, we close the ongoing requests
3061 | if ('close' == packet.type) {
3062 | self.onClose();
3063 | return false;
3064 | }
3065 |
3066 | // otherwise bypass onData and handle the message
3067 | self.onPacket(packet);
3068 | };
3069 |
3070 | // decode payload
3071 | parser.decodePayload(data, this.socket.binaryType, callback);
3072 |
3073 | // if an event did not trigger closing
3074 | if ('closed' != this.readyState) {
3075 | // if we got data we're not polling
3076 | this.polling = false;
3077 | this.emit('pollComplete');
3078 |
3079 | if ('open' == this.readyState) {
3080 | this.poll();
3081 | } else {
3082 | debug('ignoring poll - transport state "%s"', this.readyState);
3083 | }
3084 | }
3085 | };
3086 |
3087 | /**
3088 | * For polling, send a close packet.
3089 | *
3090 | * @api private
3091 | */
3092 |
3093 | Polling.prototype.doClose = function(){
3094 | var self = this;
3095 |
3096 | function close(){
3097 | debug('writing close packet');
3098 | self.write([{ type: 'close' }]);
3099 | }
3100 |
3101 | if ('open' == this.readyState) {
3102 | debug('transport open - closing');
3103 | close();
3104 | } else {
3105 | // in case we're trying to close while
3106 | // handshaking is in progress (GH-164)
3107 | debug('transport not open - deferring close');
3108 | this.once('open', close);
3109 | }
3110 | };
3111 |
3112 | /**
3113 | * Writes a packets payload.
3114 | *
3115 | * @param {Array} data packets
3116 | * @param {Function} drain callback
3117 | * @api private
3118 | */
3119 |
3120 | Polling.prototype.write = function(packets){
3121 | var self = this;
3122 | this.writable = false;
3123 | var callbackfn = function() {
3124 | self.writable = true;
3125 | self.emit('drain');
3126 | };
3127 |
3128 | var self = this;
3129 | parser.encodePayload(packets, this.supportsBinary, function(data) {
3130 | self.doWrite(data, callbackfn);
3131 | });
3132 | };
3133 |
3134 | /**
3135 | * Generates uri for connection.
3136 | *
3137 | * @api private
3138 | */
3139 |
3140 | Polling.prototype.uri = function(){
3141 | var query = this.query || {};
3142 | var schema = this.secure ? 'https' : 'http';
3143 | var port = '';
3144 |
3145 | // cache busting is forced
3146 | if (false !== this.timestampRequests) {
3147 | query[this.timestampParam] = +new Date + '-' + Transport.timestamps++;
3148 | }
3149 |
3150 | if (!this.supportsBinary && !query.sid) {
3151 | query.b64 = 1;
3152 | }
3153 |
3154 | query = parseqs.encode(query);
3155 |
3156 | // avoid port if default for schema
3157 | if (this.port && (('https' == schema && this.port != 443) ||
3158 | ('http' == schema && this.port != 80))) {
3159 | port = ':' + this.port;
3160 | }
3161 |
3162 | // prepend ? to query
3163 | if (query.length) {
3164 | query = '?' + query;
3165 | }
3166 |
3167 | return schema + '://' + this.hostname + port + this.path + query;
3168 | };
3169 |
3170 | },{"../transport":14,"component-inherit":21,"debug":9,"engine.io-parser":22,"parseqs":30,"xmlhttprequest":20}],19:[function(require,module,exports){
3171 | /**
3172 | * Module dependencies.
3173 | */
3174 |
3175 | var Transport = require('../transport');
3176 | var parser = require('engine.io-parser');
3177 | var parseqs = require('parseqs');
3178 | var inherit = require('component-inherit');
3179 | var debug = require('debug')('engine.io-client:websocket');
3180 |
3181 | /**
3182 | * `ws` exposes a WebSocket-compatible interface in
3183 | * Node, or the `WebSocket` or `MozWebSocket` globals
3184 | * in the browser.
3185 | */
3186 |
3187 | var WebSocket = require('ws');
3188 |
3189 | /**
3190 | * Module exports.
3191 | */
3192 |
3193 | module.exports = WS;
3194 |
3195 | /**
3196 | * WebSocket transport constructor.
3197 | *
3198 | * @api {Object} connection options
3199 | * @api public
3200 | */
3201 |
3202 | function WS(opts){
3203 | var forceBase64 = (opts && opts.forceBase64);
3204 | if (forceBase64) {
3205 | this.supportsBinary = false;
3206 | }
3207 | Transport.call(this, opts);
3208 | }
3209 |
3210 | /**
3211 | * Inherits from Transport.
3212 | */
3213 |
3214 | inherit(WS, Transport);
3215 |
3216 | /**
3217 | * Transport name.
3218 | *
3219 | * @api public
3220 | */
3221 |
3222 | WS.prototype.name = 'websocket';
3223 |
3224 | /*
3225 | * WebSockets support binary
3226 | */
3227 |
3228 | WS.prototype.supportsBinary = true;
3229 |
3230 | /**
3231 | * Opens socket.
3232 | *
3233 | * @api private
3234 | */
3235 |
3236 | WS.prototype.doOpen = function(){
3237 | if (!this.check()) {
3238 | // let probe timeout
3239 | return;
3240 | }
3241 |
3242 | var self = this;
3243 | var uri = this.uri();
3244 | var protocols = void(0);
3245 | var opts = { agent: this.agent };
3246 |
3247 | this.ws = new WebSocket(uri, protocols, opts);
3248 |
3249 | if (this.ws.binaryType === undefined) {
3250 | this.supportsBinary = false;
3251 | }
3252 |
3253 | this.ws.binaryType = 'arraybuffer';
3254 | this.addEventListeners();
3255 | };
3256 |
3257 | /**
3258 | * Adds event listeners to the socket
3259 | *
3260 | * @api private
3261 | */
3262 |
3263 | WS.prototype.addEventListeners = function(){
3264 | var self = this;
3265 |
3266 | this.ws.onopen = function(){
3267 | self.onOpen();
3268 | };
3269 | this.ws.onclose = function(){
3270 | self.onClose();
3271 | };
3272 | this.ws.onmessage = function(ev){
3273 | self.onData(ev.data);
3274 | };
3275 | this.ws.onerror = function(e){
3276 | self.onError('websocket error', e);
3277 | };
3278 | };
3279 |
3280 | /**
3281 | * Override `onData` to use a timer on iOS.
3282 | * See: https://gist.github.com/mloughran/2052006
3283 | *
3284 | * @api private
3285 | */
3286 |
3287 | if ('undefined' != typeof navigator
3288 | && /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
3289 | WS.prototype.onData = function(data){
3290 | var self = this;
3291 | setTimeout(function(){
3292 | Transport.prototype.onData.call(self, data);
3293 | }, 0);
3294 | };
3295 | }
3296 |
3297 | /**
3298 | * Writes data to socket.
3299 | *
3300 | * @param {Array} array of packets.
3301 | * @api private
3302 | */
3303 |
3304 | WS.prototype.write = function(packets){
3305 | var self = this;
3306 | this.writable = false;
3307 | // encodePacket efficient as it uses WS framing
3308 | // no need for encodePayload
3309 | for (var i = 0, l = packets.length; i < l; i++) {
3310 | parser.encodePacket(packets[i], this.supportsBinary, function(data) {
3311 | //Sometimes the websocket has already been closed but the browser didn't
3312 | //have a chance of informing us about it yet, in that case send will
3313 | //throw an error
3314 | try {
3315 | self.ws.send(data);
3316 | } catch (e){
3317 | debug('websocket closed before onclose event');
3318 | }
3319 | });
3320 | }
3321 |
3322 | function ondrain() {
3323 | self.writable = true;
3324 | self.emit('drain');
3325 | }
3326 | // fake drain
3327 | // defer to next tick to allow Socket to clear writeBuffer
3328 | setTimeout(ondrain, 0);
3329 | };
3330 |
3331 | /**
3332 | * Called upon close
3333 | *
3334 | * @api private
3335 | */
3336 |
3337 | WS.prototype.onClose = function(){
3338 | Transport.prototype.onClose.call(this);
3339 | };
3340 |
3341 | /**
3342 | * Closes socket.
3343 | *
3344 | * @api private
3345 | */
3346 |
3347 | WS.prototype.doClose = function(){
3348 | if (typeof this.ws !== 'undefined') {
3349 | this.ws.close();
3350 | }
3351 | };
3352 |
3353 | /**
3354 | * Generates uri for connection.
3355 | *
3356 | * @api private
3357 | */
3358 |
3359 | WS.prototype.uri = function(){
3360 | var query = this.query || {};
3361 | var schema = this.secure ? 'wss' : 'ws';
3362 | var port = '';
3363 |
3364 | // avoid port if default for schema
3365 | if (this.port && (('wss' == schema && this.port != 443)
3366 | || ('ws' == schema && this.port != 80))) {
3367 | port = ':' + this.port;
3368 | }
3369 |
3370 | // append timestamp to URI
3371 | if (this.timestampRequests) {
3372 | query[this.timestampParam] = +new Date;
3373 | }
3374 |
3375 | // communicate binary support capabilities
3376 | if (!this.supportsBinary) {
3377 | query.b64 = 1;
3378 | }
3379 |
3380 | query = parseqs.encode(query);
3381 |
3382 | // prepend ? to query
3383 | if (query.length) {
3384 | query = '?' + query;
3385 | }
3386 |
3387 | return schema + '://' + this.hostname + port + this.path + query;
3388 | };
3389 |
3390 | /**
3391 | * Feature detection for WebSocket.
3392 | *
3393 | * @return {Boolean} whether this transport is available.
3394 | * @api public
3395 | */
3396 |
3397 | WS.prototype.check = function(){
3398 | return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
3399 | };
3400 |
3401 | },{"../transport":14,"component-inherit":21,"debug":9,"engine.io-parser":22,"parseqs":30,"ws":31}],20:[function(require,module,exports){
3402 | // browser shim for xmlhttprequest module
3403 | var hasCORS = require('has-cors');
3404 |
3405 | module.exports = function(opts) {
3406 | var xdomain = opts.xdomain;
3407 |
3408 | // XMLHttpRequest can be disabled on IE
3409 | try {
3410 | if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) {
3411 | return new XMLHttpRequest();
3412 | }
3413 | } catch (e) { }
3414 |
3415 | if (!xdomain) {
3416 | try {
3417 | return new ActiveXObject('Microsoft.XMLHTTP');
3418 | } catch(e) { }
3419 | }
3420 | }
3421 |
3422 | },{"has-cors":34}],21:[function(require,module,exports){
3423 |
3424 | module.exports = function(a, b){
3425 | var fn = function(){};
3426 | fn.prototype = b.prototype;
3427 | a.prototype = new fn;
3428 | a.prototype.constructor = a;
3429 | };
3430 | },{}],22:[function(require,module,exports){
3431 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
3432 | * Module dependencies.
3433 | */
3434 |
3435 | var keys = require('./keys');
3436 | var sliceBuffer = require('arraybuffer.slice');
3437 | var base64encoder = require('base64-arraybuffer');
3438 | var after = require('after');
3439 | var utf8 = require('utf8');
3440 |
3441 | /**
3442 | * Check if we are running an android browser. That requires us to use
3443 | * ArrayBuffer with polling transports...
3444 | *
3445 | * http://ghinda.net/jpeg-blob-ajax-android/
3446 | */
3447 |
3448 | var isAndroid = navigator.userAgent.match(/Android/i);
3449 |
3450 | /**
3451 | * Current protocol version.
3452 | */
3453 |
3454 | exports.protocol = 2;
3455 |
3456 | /**
3457 | * Packet types.
3458 | */
3459 |
3460 | var packets = exports.packets = {
3461 | open: 0 // non-ws
3462 | , close: 1 // non-ws
3463 | , ping: 2
3464 | , pong: 3
3465 | , message: 4
3466 | , upgrade: 5
3467 | , noop: 6
3468 | };
3469 |
3470 | var packetslist = keys(packets);
3471 |
3472 | /**
3473 | * Premade error packet.
3474 | */
3475 |
3476 | var err = { type: 'error', data: 'parser error' };
3477 |
3478 | /**
3479 | * Create a blob api even for blob builder when vendor prefixes exist
3480 | */
3481 |
3482 | var Blob = require('blob');
3483 |
3484 | /**
3485 | * Encodes a packet.
3486 | *
3487 | * [ ]
3488 | *
3489 | * Example:
3490 | *
3491 | * 5hello world
3492 | * 3
3493 | * 4
3494 | *
3495 | * Binary is encoded in an identical principle
3496 | *
3497 | * @api private
3498 | */
3499 |
3500 | exports.encodePacket = function (packet, supportsBinary, callback) {
3501 | if (typeof supportsBinary == 'function') {
3502 | callback = supportsBinary;
3503 | supportsBinary = false;
3504 | }
3505 |
3506 | var data = (packet.data === undefined)
3507 | ? undefined
3508 | : packet.data.buffer || packet.data;
3509 |
3510 | if (global.ArrayBuffer && data instanceof ArrayBuffer) {
3511 | return encodeArrayBuffer(packet, supportsBinary, callback);
3512 | } else if (Blob && data instanceof global.Blob) {
3513 | return encodeBlob(packet, supportsBinary, callback);
3514 | }
3515 |
3516 | // Sending data as a utf-8 string
3517 | var encoded = packets[packet.type];
3518 |
3519 | // data fragment is optional
3520 | if (undefined !== packet.data) {
3521 | encoded += utf8.encode(String(packet.data));
3522 | }
3523 |
3524 | return callback('' + encoded);
3525 |
3526 | };
3527 |
3528 | /**
3529 | * Encode packet helpers for binary types
3530 | */
3531 |
3532 | function encodeArrayBuffer(packet, supportsBinary, callback) {
3533 | if (!supportsBinary) {
3534 | return exports.encodeBase64Packet(packet, callback);
3535 | }
3536 |
3537 | var data = packet.data;
3538 | var contentArray = new Uint8Array(data);
3539 | var resultBuffer = new Uint8Array(1 + data.byteLength);
3540 |
3541 | resultBuffer[0] = packets[packet.type];
3542 | for (var i = 0; i < contentArray.length; i++) {
3543 | resultBuffer[i+1] = contentArray[i];
3544 | }
3545 |
3546 | return callback(resultBuffer.buffer);
3547 | }
3548 |
3549 | function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
3550 | if (!supportsBinary) {
3551 | return exports.encodeBase64Packet(packet, callback);
3552 | }
3553 |
3554 | var fr = new FileReader();
3555 | fr.onload = function() {
3556 | packet.data = fr.result;
3557 | exports.encodePacket(packet, supportsBinary, callback);
3558 | };
3559 | return fr.readAsArrayBuffer(packet.data);
3560 | }
3561 |
3562 | function encodeBlob(packet, supportsBinary, callback) {
3563 | if (!supportsBinary) {
3564 | return exports.encodeBase64Packet(packet, callback);
3565 | }
3566 |
3567 | if (isAndroid) {
3568 | return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
3569 | }
3570 |
3571 | var length = new Uint8Array(1);
3572 | length[0] = packets[packet.type];
3573 | var blob = new Blob([length.buffer, packet.data]);
3574 |
3575 | return callback(blob);
3576 | }
3577 |
3578 | /**
3579 | * Encodes a packet with binary data in a base64 string
3580 | *
3581 | * @param {Object} packet, has `type` and `data`
3582 | * @return {String} base64 encoded message
3583 | */
3584 |
3585 | exports.encodeBase64Packet = function(packet, callback) {
3586 | var message = 'b' + exports.packets[packet.type];
3587 | if (Blob && packet.data instanceof Blob) {
3588 | var fr = new FileReader();
3589 | fr.onload = function() {
3590 | var b64 = fr.result.split(',')[1];
3591 | callback(message + b64);
3592 | };
3593 | return fr.readAsDataURL(packet.data);
3594 | }
3595 |
3596 | var b64data;
3597 | try {
3598 | b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
3599 | } catch (e) {
3600 | // iPhone Safari doesn't let you apply with typed arrays
3601 | var typed = new Uint8Array(packet.data);
3602 | var basic = new Array(typed.length);
3603 | for (var i = 0; i < typed.length; i++) {
3604 | basic[i] = typed[i];
3605 | }
3606 | b64data = String.fromCharCode.apply(null, basic);
3607 | }
3608 | message += global.btoa(b64data);
3609 | return callback(message);
3610 | };
3611 |
3612 | /**
3613 | * Decodes a packet. Changes format to Blob if requested.
3614 | *
3615 | * @return {Object} with `type` and `data` (if any)
3616 | * @api private
3617 | */
3618 |
3619 | exports.decodePacket = function (data, binaryType) {
3620 | // String data
3621 | if (typeof data == 'string' || data === undefined) {
3622 | if (data.charAt(0) == 'b') {
3623 | return exports.decodeBase64Packet(data.substr(1), binaryType);
3624 | }
3625 |
3626 | data = utf8.decode(data);
3627 | var type = data.charAt(0);
3628 |
3629 | if (Number(type) != type || !packetslist[type]) {
3630 | return err;
3631 | }
3632 |
3633 | if (data.length > 1) {
3634 | return { type: packetslist[type], data: data.substring(1) };
3635 | } else {
3636 | return { type: packetslist[type] };
3637 | }
3638 | }
3639 |
3640 | var asArray = new Uint8Array(data);
3641 | var type = asArray[0];
3642 | var rest = sliceBuffer(data, 1);
3643 | if (Blob && binaryType === 'blob') {
3644 | rest = new Blob([rest]);
3645 | }
3646 | return { type: packetslist[type], data: rest };
3647 | };
3648 |
3649 | /**
3650 | * Decodes a packet encoded in a base64 string
3651 | *
3652 | * @param {String} base64 encoded message
3653 | * @return {Object} with `type` and `data` (if any)
3654 | */
3655 |
3656 | exports.decodeBase64Packet = function(msg, binaryType) {
3657 | var type = packetslist[msg.charAt(0)];
3658 | if (!global.ArrayBuffer) {
3659 | return { type: type, data: { base64: true, data: msg.substr(1) } };
3660 | }
3661 |
3662 | var data = base64encoder.decode(msg.substr(1));
3663 |
3664 | if (binaryType === 'blob' && Blob) {
3665 | data = new Blob([data]);
3666 | }
3667 |
3668 | return { type: type, data: data };
3669 | };
3670 |
3671 | /**
3672 | * Encodes multiple messages (payload).
3673 | *
3674 | * :data
3675 | *
3676 | * Example:
3677 | *
3678 | * 11:hello world2:hi
3679 | *
3680 | * If any contents are binary, they will be encoded as base64 strings. Base64
3681 | * encoded strings are marked with a b before the length specifier
3682 | *
3683 | * @param {Array} packets
3684 | * @api private
3685 | */
3686 |
3687 | exports.encodePayload = function (packets, supportsBinary, callback) {
3688 | if (typeof supportsBinary == 'function') {
3689 | callback = supportsBinary;
3690 | supportsBinary = null;
3691 | }
3692 |
3693 | if (supportsBinary) {
3694 | if (Blob && !isAndroid) {
3695 | return exports.encodePayloadAsBlob(packets, callback);
3696 | }
3697 |
3698 | return exports.encodePayloadAsArrayBuffer(packets, callback);
3699 | }
3700 |
3701 | if (!packets.length) {
3702 | return callback('0:');
3703 | }
3704 |
3705 | function setLengthHeader(message) {
3706 | return message.length + ':' + message;
3707 | }
3708 |
3709 | function encodeOne(packet, doneCallback) {
3710 | exports.encodePacket(packet, supportsBinary, function(message) {
3711 | doneCallback(null, setLengthHeader(message));
3712 | });
3713 | }
3714 |
3715 | map(packets, encodeOne, function(err, results) {
3716 | return callback(results.join(''));
3717 | });
3718 | };
3719 |
3720 | /**
3721 | * Async array map using after
3722 | */
3723 |
3724 | function map(ary, each, done) {
3725 | var result = new Array(ary.length);
3726 | var next = after(ary.length, done);
3727 |
3728 | var eachWithIndex = function(i, el, cb) {
3729 | each(el, function(error, msg) {
3730 | result[i] = msg;
3731 | cb(error, result);
3732 | });
3733 | };
3734 |
3735 | for (var i = 0; i < ary.length; i++) {
3736 | eachWithIndex(i, ary[i], next);
3737 | }
3738 | }
3739 |
3740 | /*
3741 | * Decodes data when a payload is maybe expected. Possible binary contents are
3742 | * decoded from their base64 representation
3743 | *
3744 | * @param {String} data, callback method
3745 | * @api public
3746 | */
3747 |
3748 | exports.decodePayload = function (data, binaryType, callback) {
3749 | if (typeof data != 'string') {
3750 | return exports.decodePayloadAsBinary(data, binaryType, callback);
3751 | }
3752 |
3753 | if (typeof binaryType === 'function') {
3754 | callback = binaryType;
3755 | binaryType = null;
3756 | }
3757 |
3758 | var packet;
3759 | if (data == '') {
3760 | // parser error - ignoring payload
3761 | return callback(err, 0, 1);
3762 | }
3763 |
3764 | var length = ''
3765 | , n, msg;
3766 |
3767 | for (var i = 0, l = data.length; i < l; i++) {
3768 | var chr = data.charAt(i);
3769 |
3770 | if (':' != chr) {
3771 | length += chr;
3772 | } else {
3773 | if ('' == length || (length != (n = Number(length)))) {
3774 | // parser error - ignoring payload
3775 | return callback(err, 0, 1);
3776 | }
3777 |
3778 | msg = data.substr(i + 1, n);
3779 |
3780 | if (length != msg.length) {
3781 | // parser error - ignoring payload
3782 | return callback(err, 0, 1);
3783 | }
3784 |
3785 | if (msg.length) {
3786 | packet = exports.decodePacket(msg, binaryType);
3787 |
3788 | if (err.type == packet.type && err.data == packet.data) {
3789 | // parser error in individual packet - ignoring payload
3790 | return callback(err, 0, 1);
3791 | }
3792 |
3793 | var ret = callback(packet, i + n, l);
3794 | if (false === ret) return;
3795 | }
3796 |
3797 | // advance cursor
3798 | i += n;
3799 | length = '';
3800 | }
3801 | }
3802 |
3803 | if (length != '') {
3804 | // parser error - ignoring payload
3805 | return callback(err, 0, 1);
3806 | }
3807 |
3808 | };
3809 |
3810 | /**
3811 | * Encodes multiple messages (payload) as binary.
3812 | *
3813 | * <1 = binary, 0 = string>[...]
3815 | *
3816 | * Example:
3817 | * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
3818 | *
3819 | * @param {Array} packets
3820 | * @return {ArrayBuffer} encoded payload
3821 | * @api private
3822 | */
3823 |
3824 | exports.encodePayloadAsArrayBuffer = function(packets, callback) {
3825 | if (!packets.length) {
3826 | return callback(new ArrayBuffer(0));
3827 | }
3828 |
3829 | function encodeOne(packet, doneCallback) {
3830 | exports.encodePacket(packet, true, function(data) {
3831 | return doneCallback(null, data);
3832 | });
3833 | }
3834 |
3835 | map(packets, encodeOne, function(err, encodedPackets) {
3836 | var totalLength = encodedPackets.reduce(function(acc, p) {
3837 | var len;
3838 | if (typeof p === 'string'){
3839 | len = p.length;
3840 | } else {
3841 | len = p.byteLength;
3842 | }
3843 | return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
3844 | }, 0);
3845 |
3846 | var resultArray = new Uint8Array(totalLength);
3847 |
3848 | var bufferIndex = 0;
3849 | encodedPackets.forEach(function(p) {
3850 | var isString = typeof p === 'string';
3851 | var ab = p;
3852 | if (isString) {
3853 | var view = new Uint8Array(p.length);
3854 | for (var i = 0; i < p.length; i++) {
3855 | view[i] = p.charCodeAt(i);
3856 | }
3857 | ab = view.buffer;
3858 | }
3859 |
3860 | if (isString) { // not true binary
3861 | resultArray[bufferIndex++] = 0;
3862 | } else { // true binary
3863 | resultArray[bufferIndex++] = 1;
3864 | }
3865 |
3866 | var lenStr = ab.byteLength.toString();
3867 | for (var i = 0; i < lenStr.length; i++) {
3868 | resultArray[bufferIndex++] = parseInt(lenStr[i]);
3869 | }
3870 | resultArray[bufferIndex++] = 255;
3871 |
3872 | var view = new Uint8Array(ab);
3873 | for (var i = 0; i < view.length; i++) {
3874 | resultArray[bufferIndex++] = view[i];
3875 | }
3876 | });
3877 |
3878 | return callback(resultArray.buffer);
3879 | });
3880 | };
3881 |
3882 | /**
3883 | * Encode as Blob
3884 | */
3885 |
3886 | exports.encodePayloadAsBlob = function(packets, callback) {
3887 | function encodeOne(packet, doneCallback) {
3888 | exports.encodePacket(packet, true, function(encoded) {
3889 | var binaryIdentifier = new Uint8Array(1);
3890 | binaryIdentifier[0] = 1;
3891 | if (typeof encoded === 'string') {
3892 | var view = new Uint8Array(encoded.length);
3893 | for (var i = 0; i < encoded.length; i++) {
3894 | view[i] = encoded.charCodeAt(i);
3895 | }
3896 | encoded = view.buffer;
3897 | binaryIdentifier[0] = 0;
3898 | }
3899 |
3900 | var len = (encoded instanceof ArrayBuffer)
3901 | ? encoded.byteLength
3902 | : encoded.size;
3903 |
3904 | var lenStr = len.toString();
3905 | var lengthAry = new Uint8Array(lenStr.length + 1);
3906 | for (var i = 0; i < lenStr.length; i++) {
3907 | lengthAry[i] = parseInt(lenStr[i]);
3908 | }
3909 | lengthAry[lenStr.length] = 255;
3910 |
3911 | if (Blob) {
3912 | var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
3913 | doneCallback(null, blob);
3914 | }
3915 | });
3916 | }
3917 |
3918 | map(packets, encodeOne, function(err, results) {
3919 | return callback(new Blob(results));
3920 | });
3921 | };
3922 |
3923 | /*
3924 | * Decodes data when a payload is maybe expected. Strings are decoded by
3925 | * interpreting each byte as a key code for entries marked to start with 0. See
3926 | * description of encodePayloadAsBinary
3927 | *
3928 | * @param {ArrayBuffer} data, callback method
3929 | * @api public
3930 | */
3931 |
3932 | exports.decodePayloadAsBinary = function (data, binaryType, callback) {
3933 | if (typeof binaryType === 'function') {
3934 | callback = binaryType;
3935 | binaryType = null;
3936 | }
3937 |
3938 | var bufferTail = data;
3939 | var buffers = [];
3940 |
3941 | while (bufferTail.byteLength > 0) {
3942 | var tailArray = new Uint8Array(bufferTail);
3943 | var isString = tailArray[0] === 0;
3944 | var msgLength = '';
3945 | for (var i = 1; ; i++) {
3946 | if (tailArray[i] == 255) break;
3947 | msgLength += tailArray[i];
3948 | }
3949 | bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
3950 | msgLength = parseInt(msgLength);
3951 |
3952 | var msg = sliceBuffer(bufferTail, 0, msgLength);
3953 | if (isString) {
3954 | try {
3955 | msg = String.fromCharCode.apply(null, new Uint8Array(msg));
3956 | } catch (e) {
3957 | // iPhone Safari doesn't let you apply to typed arrays
3958 | var typed = new Uint8Array(msg);
3959 | msg = '';
3960 | for (var i = 0; i < typed.length; i++) {
3961 | msg += String.fromCharCode(typed[i]);
3962 | }
3963 | }
3964 | }
3965 | buffers.push(msg);
3966 | bufferTail = sliceBuffer(bufferTail, msgLength);
3967 | }
3968 |
3969 | var total = buffers.length;
3970 | buffers.forEach(function(buffer, i) {
3971 | callback(exports.decodePacket(buffer, binaryType), i, total);
3972 | });
3973 | };
3974 |
3975 | },{"./keys":23,"after":24,"arraybuffer.slice":25,"base64-arraybuffer":26,"blob":27,"utf8":28}],23:[function(require,module,exports){
3976 |
3977 | /**
3978 | * Gets the keys for an object.
3979 | *
3980 | * @return {Array} keys
3981 | * @api private
3982 | */
3983 |
3984 | module.exports = Object.keys || function keys (obj){
3985 | var arr = [];
3986 | var has = Object.prototype.hasOwnProperty;
3987 |
3988 | for (var i in obj) {
3989 | if (has.call(obj, i)) {
3990 | arr.push(i);
3991 | }
3992 | }
3993 | return arr;
3994 | };
3995 |
3996 | },{}],24:[function(require,module,exports){
3997 | module.exports = after
3998 |
3999 | function after(count, callback, err_cb) {
4000 | var bail = false
4001 | err_cb = err_cb || noop
4002 | proxy.count = count
4003 |
4004 | return (count === 0) ? callback() : proxy
4005 |
4006 | function proxy(err, result) {
4007 | if (proxy.count <= 0) {
4008 | throw new Error('after called too many times')
4009 | }
4010 | --proxy.count
4011 |
4012 | // after first error, rest are passed to err_cb
4013 | if (err) {
4014 | bail = true
4015 | callback(err)
4016 | // future error callbacks will go to error handler
4017 | callback = err_cb
4018 | } else if (proxy.count === 0 && !bail) {
4019 | callback(null, result)
4020 | }
4021 | }
4022 | }
4023 |
4024 | function noop() {}
4025 |
4026 | },{}],25:[function(require,module,exports){
4027 | /**
4028 | * An abstraction for slicing an arraybuffer even when
4029 | * ArrayBuffer.prototype.slice is not supported
4030 | *
4031 | * @api public
4032 | */
4033 |
4034 | module.exports = function(arraybuffer, start, end) {
4035 | var bytes = arraybuffer.byteLength;
4036 | start = start || 0;
4037 | end = end || bytes;
4038 |
4039 | if (arraybuffer.slice) { return arraybuffer.slice(start, end); }
4040 |
4041 | if (start < 0) { start += bytes; }
4042 | if (end < 0) { end += bytes; }
4043 | if (end > bytes) { end = bytes; }
4044 |
4045 | if (start >= bytes || start >= end || bytes === 0) {
4046 | return new ArrayBuffer(0);
4047 | }
4048 |
4049 | var abv = new Uint8Array(arraybuffer);
4050 | var result = new Uint8Array(end - start);
4051 | for (var i = start, ii = 0; i < end; i++, ii++) {
4052 | result[ii] = abv[i];
4053 | }
4054 | return result.buffer;
4055 | };
4056 |
4057 | },{}],26:[function(require,module,exports){
4058 | /*
4059 | * base64-arraybuffer
4060 | * https://github.com/niklasvh/base64-arraybuffer
4061 | *
4062 | * Copyright (c) 2012 Niklas von Hertzen
4063 | * Licensed under the MIT license.
4064 | */
4065 | (function(chars){
4066 | "use strict";
4067 |
4068 | exports.encode = function(arraybuffer) {
4069 | var bytes = new Uint8Array(arraybuffer),
4070 | i, len = bytes.length, base64 = "";
4071 |
4072 | for (i = 0; i < len; i+=3) {
4073 | base64 += chars[bytes[i] >> 2];
4074 | base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
4075 | base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
4076 | base64 += chars[bytes[i + 2] & 63];
4077 | }
4078 |
4079 | if ((len % 3) === 2) {
4080 | base64 = base64.substring(0, base64.length - 1) + "=";
4081 | } else if (len % 3 === 1) {
4082 | base64 = base64.substring(0, base64.length - 2) + "==";
4083 | }
4084 |
4085 | return base64;
4086 | };
4087 |
4088 | exports.decode = function(base64) {
4089 | var bufferLength = base64.length * 0.75,
4090 | len = base64.length, i, p = 0,
4091 | encoded1, encoded2, encoded3, encoded4;
4092 |
4093 | if (base64[base64.length - 1] === "=") {
4094 | bufferLength--;
4095 | if (base64[base64.length - 2] === "=") {
4096 | bufferLength--;
4097 | }
4098 | }
4099 |
4100 | var arraybuffer = new ArrayBuffer(bufferLength),
4101 | bytes = new Uint8Array(arraybuffer);
4102 |
4103 | for (i = 0; i < len; i+=4) {
4104 | encoded1 = chars.indexOf(base64[i]);
4105 | encoded2 = chars.indexOf(base64[i+1]);
4106 | encoded3 = chars.indexOf(base64[i+2]);
4107 | encoded4 = chars.indexOf(base64[i+3]);
4108 |
4109 | bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
4110 | bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
4111 | bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
4112 | }
4113 |
4114 | return arraybuffer;
4115 | };
4116 | })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
4117 |
4118 | },{}],27:[function(require,module,exports){
4119 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
4120 | * Create a blob builder even when vendor prefixes exist
4121 | */
4122 |
4123 | var BlobBuilder = global.BlobBuilder
4124 | || global.WebKitBlobBuilder
4125 | || global.MSBlobBuilder
4126 | || global.MozBlobBuilder;
4127 |
4128 | /**
4129 | * Check if Blob constructor is supported
4130 | */
4131 |
4132 | var blobSupported = (function() {
4133 | try {
4134 | var b = new Blob(['hi']);
4135 | return b.size == 2;
4136 | } catch(e) {
4137 | return false;
4138 | }
4139 | })();
4140 |
4141 | /**
4142 | * Check if BlobBuilder is supported
4143 | */
4144 |
4145 | var blobBuilderSupported = BlobBuilder
4146 | && BlobBuilder.prototype.append
4147 | && BlobBuilder.prototype.getBlob;
4148 |
4149 | function BlobBuilderConstructor(ary, options) {
4150 | options = options || {};
4151 |
4152 | var bb = new BlobBuilder();
4153 | for (var i = 0; i < ary.length; i++) {
4154 | bb.append(ary[i]);
4155 | }
4156 | return (options.type) ? bb.getBlob(options.type) : bb.getBlob();
4157 | };
4158 |
4159 | module.exports = (function() {
4160 | if (blobSupported) {
4161 | return global.Blob;
4162 | } else if (blobBuilderSupported) {
4163 | return BlobBuilderConstructor;
4164 | } else {
4165 | return undefined;
4166 | }
4167 | })();
4168 |
4169 | },{}],28:[function(require,module,exports){
4170 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/*! http://mths.be/utf8js v2.0.0 by @mathias */
4171 | ;(function(root) {
4172 |
4173 | // Detect free variables `exports`
4174 | var freeExports = typeof exports == 'object' && exports;
4175 |
4176 | // Detect free variable `module`
4177 | var freeModule = typeof module == 'object' && module &&
4178 | module.exports == freeExports && module;
4179 |
4180 | // Detect free variable `global`, from Node.js or Browserified code,
4181 | // and use it as `root`
4182 | var freeGlobal = typeof global == 'object' && global;
4183 | if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
4184 | root = freeGlobal;
4185 | }
4186 |
4187 | /*--------------------------------------------------------------------------*/
4188 |
4189 | var stringFromCharCode = String.fromCharCode;
4190 |
4191 | // Taken from http://mths.be/punycode
4192 | function ucs2decode(string) {
4193 | var output = [];
4194 | var counter = 0;
4195 | var length = string.length;
4196 | var value;
4197 | var extra;
4198 | while (counter < length) {
4199 | value = string.charCodeAt(counter++);
4200 | if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4201 | // high surrogate, and there is a next character
4202 | extra = string.charCodeAt(counter++);
4203 | if ((extra & 0xFC00) == 0xDC00) { // low surrogate
4204 | output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4205 | } else {
4206 | // unmatched surrogate; only append this code unit, in case the next
4207 | // code unit is the high surrogate of a surrogate pair
4208 | output.push(value);
4209 | counter--;
4210 | }
4211 | } else {
4212 | output.push(value);
4213 | }
4214 | }
4215 | return output;
4216 | }
4217 |
4218 | // Taken from http://mths.be/punycode
4219 | function ucs2encode(array) {
4220 | var length = array.length;
4221 | var index = -1;
4222 | var value;
4223 | var output = '';
4224 | while (++index < length) {
4225 | value = array[index];
4226 | if (value > 0xFFFF) {
4227 | value -= 0x10000;
4228 | output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
4229 | value = 0xDC00 | value & 0x3FF;
4230 | }
4231 | output += stringFromCharCode(value);
4232 | }
4233 | return output;
4234 | }
4235 |
4236 | /*--------------------------------------------------------------------------*/
4237 |
4238 | function createByte(codePoint, shift) {
4239 | return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
4240 | }
4241 |
4242 | function encodeCodePoint(codePoint) {
4243 | if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
4244 | return stringFromCharCode(codePoint);
4245 | }
4246 | var symbol = '';
4247 | if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
4248 | symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
4249 | }
4250 | else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
4251 | symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
4252 | symbol += createByte(codePoint, 6);
4253 | }
4254 | else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
4255 | symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
4256 | symbol += createByte(codePoint, 12);
4257 | symbol += createByte(codePoint, 6);
4258 | }
4259 | symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
4260 | return symbol;
4261 | }
4262 |
4263 | function utf8encode(string) {
4264 | var codePoints = ucs2decode(string);
4265 |
4266 | // console.log(JSON.stringify(codePoints.map(function(x) {
4267 | // return 'U+' + x.toString(16).toUpperCase();
4268 | // })));
4269 |
4270 | var length = codePoints.length;
4271 | var index = -1;
4272 | var codePoint;
4273 | var byteString = '';
4274 | while (++index < length) {
4275 | codePoint = codePoints[index];
4276 | byteString += encodeCodePoint(codePoint);
4277 | }
4278 | return byteString;
4279 | }
4280 |
4281 | /*--------------------------------------------------------------------------*/
4282 |
4283 | function readContinuationByte() {
4284 | if (byteIndex >= byteCount) {
4285 | throw Error('Invalid byte index');
4286 | }
4287 |
4288 | var continuationByte = byteArray[byteIndex] & 0xFF;
4289 | byteIndex++;
4290 |
4291 | if ((continuationByte & 0xC0) == 0x80) {
4292 | return continuationByte & 0x3F;
4293 | }
4294 |
4295 | // If we end up here, it’s not a continuation byte
4296 | throw Error('Invalid continuation byte');
4297 | }
4298 |
4299 | function decodeSymbol() {
4300 | var byte1;
4301 | var byte2;
4302 | var byte3;
4303 | var byte4;
4304 | var codePoint;
4305 |
4306 | if (byteIndex > byteCount) {
4307 | throw Error('Invalid byte index');
4308 | }
4309 |
4310 | if (byteIndex == byteCount) {
4311 | return false;
4312 | }
4313 |
4314 | // Read first byte
4315 | byte1 = byteArray[byteIndex] & 0xFF;
4316 | byteIndex++;
4317 |
4318 | // 1-byte sequence (no continuation bytes)
4319 | if ((byte1 & 0x80) == 0) {
4320 | return byte1;
4321 | }
4322 |
4323 | // 2-byte sequence
4324 | if ((byte1 & 0xE0) == 0xC0) {
4325 | var byte2 = readContinuationByte();
4326 | codePoint = ((byte1 & 0x1F) << 6) | byte2;
4327 | if (codePoint >= 0x80) {
4328 | return codePoint;
4329 | } else {
4330 | throw Error('Invalid continuation byte');
4331 | }
4332 | }
4333 |
4334 | // 3-byte sequence (may include unpaired surrogates)
4335 | if ((byte1 & 0xF0) == 0xE0) {
4336 | byte2 = readContinuationByte();
4337 | byte3 = readContinuationByte();
4338 | codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
4339 | if (codePoint >= 0x0800) {
4340 | return codePoint;
4341 | } else {
4342 | throw Error('Invalid continuation byte');
4343 | }
4344 | }
4345 |
4346 | // 4-byte sequence
4347 | if ((byte1 & 0xF8) == 0xF0) {
4348 | byte2 = readContinuationByte();
4349 | byte3 = readContinuationByte();
4350 | byte4 = readContinuationByte();
4351 | codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
4352 | (byte3 << 0x06) | byte4;
4353 | if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
4354 | return codePoint;
4355 | }
4356 | }
4357 |
4358 | throw Error('Invalid UTF-8 detected');
4359 | }
4360 |
4361 | var byteArray;
4362 | var byteCount;
4363 | var byteIndex;
4364 | function utf8decode(byteString) {
4365 | byteArray = ucs2decode(byteString);
4366 | byteCount = byteArray.length;
4367 | byteIndex = 0;
4368 | var codePoints = [];
4369 | var tmp;
4370 | while ((tmp = decodeSymbol()) !== false) {
4371 | codePoints.push(tmp);
4372 | }
4373 | return ucs2encode(codePoints);
4374 | }
4375 |
4376 | /*--------------------------------------------------------------------------*/
4377 |
4378 | var utf8 = {
4379 | 'version': '2.0.0',
4380 | 'encode': utf8encode,
4381 | 'decode': utf8decode
4382 | };
4383 |
4384 | // Some AMD build optimizers, like r.js, check for specific condition patterns
4385 | // like the following:
4386 | if (
4387 | typeof define == 'function' &&
4388 | typeof define.amd == 'object' &&
4389 | define.amd
4390 | ) {
4391 | define(function() {
4392 | return utf8;
4393 | });
4394 | } else if (freeExports && !freeExports.nodeType) {
4395 | if (freeModule) { // in Node.js or RingoJS v0.8.0+
4396 | freeModule.exports = utf8;
4397 | } else { // in Narwhal or RingoJS v0.7.0-
4398 | var object = {};
4399 | var hasOwnProperty = object.hasOwnProperty;
4400 | for (var key in utf8) {
4401 | hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
4402 | }
4403 | }
4404 | } else { // in Rhino or a web browser
4405 | root.utf8 = utf8;
4406 | }
4407 |
4408 | }(this));
4409 |
4410 | },{}],29:[function(require,module,exports){
4411 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
4412 | * JSON parse.
4413 | *
4414 | * @see Based on jQuery#parseJSON (MIT) and JSON2
4415 | * @api private
4416 | */
4417 |
4418 | var rvalidchars = /^[\],:{}\s]*$/;
4419 | var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
4420 | var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
4421 | var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
4422 | var rtrimLeft = /^\s+/;
4423 | var rtrimRight = /\s+$/;
4424 |
4425 | module.exports = function parsejson(data) {
4426 | if ('string' != typeof data || !data) {
4427 | return null;
4428 | }
4429 |
4430 | data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
4431 |
4432 | // Attempt to parse using the native JSON parser first
4433 | if (global.JSON && JSON.parse) {
4434 | return JSON.parse(data);
4435 | }
4436 |
4437 | if (rvalidchars.test(data.replace(rvalidescape, '@')
4438 | .replace(rvalidtokens, ']')
4439 | .replace(rvalidbraces, ''))) {
4440 | return (new Function('return ' + data))();
4441 | }
4442 | };
4443 | },{}],30:[function(require,module,exports){
4444 | /**
4445 | * Compiles a querystring
4446 | * Returns string representation of the object
4447 | *
4448 | * @param {Object}
4449 | * @api private
4450 | */
4451 |
4452 | exports.encode = function (obj) {
4453 | var str = '';
4454 |
4455 | for (var i in obj) {
4456 | if (obj.hasOwnProperty(i)) {
4457 | if (str.length) str += '&';
4458 | str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
4459 | }
4460 | }
4461 |
4462 | return str;
4463 | };
4464 |
4465 | /**
4466 | * Parses a simple querystring into an object
4467 | *
4468 | * @param {String} qs
4469 | * @api private
4470 | */
4471 |
4472 | exports.decode = function(qs){
4473 | var qry = {};
4474 | var pairs = qs.split('&');
4475 | for (var i = 0, l = pairs.length; i < l; i++) {
4476 | var pair = pairs[i].split('=');
4477 | qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
4478 | }
4479 | return qry;
4480 | };
4481 |
4482 | },{}],31:[function(require,module,exports){
4483 |
4484 | /**
4485 | * Module dependencies.
4486 | */
4487 |
4488 | var global = (function() { return this; })();
4489 |
4490 | /**
4491 | * WebSocket constructor.
4492 | */
4493 |
4494 | var WebSocket = global.WebSocket || global.MozWebSocket;
4495 |
4496 | /**
4497 | * Module exports.
4498 | */
4499 |
4500 | module.exports = WebSocket ? ws : null;
4501 |
4502 | /**
4503 | * WebSocket constructor.
4504 | *
4505 | * The third `opts` options object gets ignored in web browsers, since it's
4506 | * non-standard, and throws a TypeError if passed to the constructor.
4507 | * See: https://github.com/einaros/ws/issues/227
4508 | *
4509 | * @param {String} uri
4510 | * @param {Array} protocols (optional)
4511 | * @param {Object) opts (optional)
4512 | * @api public
4513 | */
4514 |
4515 | function ws(uri, protocols, opts) {
4516 | var instance;
4517 | if (protocols) {
4518 | instance = new WebSocket(uri, protocols);
4519 | } else {
4520 | instance = new WebSocket(uri);
4521 | }
4522 | return instance;
4523 | }
4524 |
4525 | if (WebSocket) ws.prototype = WebSocket.prototype;
4526 |
4527 | },{}],32:[function(require,module,exports){
4528 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/*
4529 | * Module requirements.
4530 | */
4531 |
4532 | var isArray = require('isarray');
4533 |
4534 | /**
4535 | * Module exports.
4536 | */
4537 |
4538 | module.exports = hasBinary;
4539 |
4540 | /**
4541 | * Checks for binary data.
4542 | *
4543 | * Right now only Buffer and ArrayBuffer are supported..
4544 | *
4545 | * @param {Object} anything
4546 | * @api public
4547 | */
4548 |
4549 | function hasBinary(data) {
4550 |
4551 | function recursiveCheckForBinary(obj) {
4552 | if (!obj) return false;
4553 |
4554 | if ( (global.Buffer && Buffer.isBuffer(obj)) ||
4555 | (global.ArrayBuffer && obj instanceof ArrayBuffer) ||
4556 | (global.Blob && obj instanceof Blob) ||
4557 | (global.File && obj instanceof File)
4558 | ) {
4559 | return true;
4560 | }
4561 |
4562 | if (isArray(obj)) {
4563 | for (var i = 0; i < obj.length; i++) {
4564 | if (recursiveCheckForBinary(obj[i])) {
4565 | return true;
4566 | }
4567 | }
4568 | } else if (obj && 'object' == typeof obj) {
4569 | if (obj.toJSON) {
4570 | obj = obj.toJSON();
4571 | }
4572 |
4573 | for (var key in obj) {
4574 | if (recursiveCheckForBinary(obj[key])) {
4575 | return true;
4576 | }
4577 | }
4578 | }
4579 |
4580 | return false;
4581 | }
4582 |
4583 | return recursiveCheckForBinary(data);
4584 | }
4585 |
4586 | },{"isarray":33}],33:[function(require,module,exports){
4587 | module.exports = Array.isArray || function (arr) {
4588 | return Object.prototype.toString.call(arr) == '[object Array]';
4589 | };
4590 |
4591 | },{}],34:[function(require,module,exports){
4592 |
4593 | /**
4594 | * Module dependencies.
4595 | */
4596 |
4597 | var global = require('global');
4598 |
4599 | /**
4600 | * Module exports.
4601 | *
4602 | * Logic borrowed from Modernizr:
4603 | *
4604 | * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
4605 | */
4606 |
4607 | try {
4608 | module.exports = 'XMLHttpRequest' in global &&
4609 | 'withCredentials' in new global.XMLHttpRequest();
4610 | } catch (err) {
4611 | // if XMLHttp support is disabled in IE then it will throw
4612 | // when trying to create
4613 | module.exports = false;
4614 | }
4615 |
4616 | },{"global":35}],35:[function(require,module,exports){
4617 |
4618 | /**
4619 | * Returns `this`. Execute this without a "context" (i.e. without it being
4620 | * attached to an object of the left-hand side), and `this` points to the
4621 | * "global" scope of the current JS execution.
4622 | */
4623 |
4624 | module.exports = (function () { return this; })();
4625 |
4626 | },{}],36:[function(require,module,exports){
4627 |
4628 | var indexOf = [].indexOf;
4629 |
4630 | module.exports = function(arr, obj){
4631 | if (indexOf) return arr.indexOf(obj);
4632 | for (var i = 0; i < arr.length; ++i) {
4633 | if (arr[i] === obj) return i;
4634 | }
4635 | return -1;
4636 | };
4637 | },{}],37:[function(require,module,exports){
4638 |
4639 | /**
4640 | * HOP ref.
4641 | */
4642 |
4643 | var has = Object.prototype.hasOwnProperty;
4644 |
4645 | /**
4646 | * Return own keys in `obj`.
4647 | *
4648 | * @param {Object} obj
4649 | * @return {Array}
4650 | * @api public
4651 | */
4652 |
4653 | exports.keys = Object.keys || function(obj){
4654 | var keys = [];
4655 | for (var key in obj) {
4656 | if (has.call(obj, key)) {
4657 | keys.push(key);
4658 | }
4659 | }
4660 | return keys;
4661 | };
4662 |
4663 | /**
4664 | * Return own values in `obj`.
4665 | *
4666 | * @param {Object} obj
4667 | * @return {Array}
4668 | * @api public
4669 | */
4670 |
4671 | exports.values = function(obj){
4672 | var vals = [];
4673 | for (var key in obj) {
4674 | if (has.call(obj, key)) {
4675 | vals.push(obj[key]);
4676 | }
4677 | }
4678 | return vals;
4679 | };
4680 |
4681 | /**
4682 | * Merge `b` into `a`.
4683 | *
4684 | * @param {Object} a
4685 | * @param {Object} b
4686 | * @return {Object} a
4687 | * @api public
4688 | */
4689 |
4690 | exports.merge = function(a, b){
4691 | for (var key in b) {
4692 | if (has.call(b, key)) {
4693 | a[key] = b[key];
4694 | }
4695 | }
4696 | return a;
4697 | };
4698 |
4699 | /**
4700 | * Return length of `obj`.
4701 | *
4702 | * @param {Object} obj
4703 | * @return {Number}
4704 | * @api public
4705 | */
4706 |
4707 | exports.length = function(obj){
4708 | return exports.keys(obj).length;
4709 | };
4710 |
4711 | /**
4712 | * Check if `obj` is empty.
4713 | *
4714 | * @param {Object} obj
4715 | * @return {Boolean}
4716 | * @api public
4717 | */
4718 |
4719 | exports.isEmpty = function(obj){
4720 | return 0 == exports.length(obj);
4721 | };
4722 | },{}],38:[function(require,module,exports){
4723 | /**
4724 | * Parses an URI
4725 | *
4726 | * @author Steven Levithan (MIT license)
4727 | * @api private
4728 | */
4729 |
4730 | var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
4731 |
4732 | var parts = [
4733 | 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
4734 | , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
4735 | ];
4736 |
4737 | module.exports = function parseuri(str) {
4738 | var m = re.exec(str || '')
4739 | , uri = {}
4740 | , i = 14;
4741 |
4742 | while (i--) {
4743 | uri[parts[i]] = m[i] || '';
4744 | }
4745 |
4746 | return uri;
4747 | };
4748 |
4749 | },{}],39:[function(require,module,exports){
4750 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
4751 | * Modle requirements
4752 | */
4753 |
4754 | var isArray = require('isarray');
4755 |
4756 | /**
4757 | * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder.
4758 | * Anything with blobs or files should be fed through removeBlobs before coming
4759 | * here.
4760 | *
4761 | * @param {Object} packet - socket.io event packet
4762 | * @return {Object} with deconstructed packet and list of buffers
4763 | * @api public
4764 | */
4765 |
4766 | exports.deconstructPacket = function(packet) {
4767 | var buffers = [];
4768 | var packetData = packet.data;
4769 |
4770 | function deconstructBinPackRecursive(data) {
4771 | if (!data) return data;
4772 |
4773 | if ((global.Buffer && Buffer.isBuffer(data)) ||
4774 | (global.ArrayBuffer && data instanceof ArrayBuffer)) { // replace binary
4775 | var placeholder = {_placeholder: true, num: buffers.length};
4776 | buffers.push(data);
4777 | return placeholder;
4778 | } else if (isArray(data)) {
4779 | var newData = new Array(data.length);
4780 | for (var i = 0; i < data.length; i++) {
4781 | newData[i] = deconstructBinPackRecursive(data[i]);
4782 | }
4783 | return newData;
4784 | } else if ('object' == typeof data && !(data instanceof Date)) {
4785 | var newData = {};
4786 | for (var key in data) {
4787 | newData[key] = deconstructBinPackRecursive(data[key]);
4788 | }
4789 | return newData;
4790 | }
4791 | return data;
4792 | }
4793 |
4794 | var pack = packet;
4795 | pack.data = deconstructBinPackRecursive(packetData);
4796 | pack.attachments = buffers.length; // number of binary 'attachments'
4797 | return {packet: pack, buffers: buffers};
4798 | }
4799 |
4800 | /**
4801 | * Reconstructs a binary packet from its placeholder packet and buffers
4802 | *
4803 | * @param {Object} packet - event packet with placeholders
4804 | * @param {Array} buffers - binary buffers to put in placeholder positions
4805 | * @return {Object} reconstructed packet
4806 | * @api public
4807 | */
4808 |
4809 | exports.reconstructPacket = function(packet, buffers) {
4810 | var curPlaceHolder = 0;
4811 |
4812 | function reconstructBinPackRecursive(data) {
4813 | if (data && data._placeholder) {
4814 | var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway)
4815 | return buf;
4816 | } else if (isArray(data)) {
4817 | for (var i = 0; i < data.length; i++) {
4818 | data[i] = reconstructBinPackRecursive(data[i]);
4819 | }
4820 | return data;
4821 | } else if (data && 'object' == typeof data) {
4822 | for (var key in data) {
4823 | data[key] = reconstructBinPackRecursive(data[key]);
4824 | }
4825 | return data;
4826 | }
4827 | return data;
4828 | }
4829 |
4830 | packet.data = reconstructBinPackRecursive(packet.data);
4831 | packet.attachments = undefined; // no longer useful
4832 | return packet;
4833 | }
4834 |
4835 | /**
4836 | * Asynchronously removes Blobs or Files from data via
4837 | * FileReader's readAsArrayBuffer method. Used before encoding
4838 | * data as msgpack. Calls callback with the blobless data.
4839 | *
4840 | * @param {Object} data
4841 | * @param {Function} callback
4842 | * @api private
4843 | */
4844 |
4845 | exports.removeBlobs = function(data, callback) {
4846 |
4847 | function removeBlobsRecursive(obj, curKey, containingObject) {
4848 | if (!obj) return obj;
4849 |
4850 | // convert any blob
4851 | if ((global.Blob && obj instanceof Blob) ||
4852 | (global.File && obj instanceof File)) {
4853 | pendingBlobs++;
4854 |
4855 | // async filereader
4856 | var fileReader = new FileReader();
4857 | fileReader.onload = function() { // this.result == arraybuffer
4858 | if (containingObject) {
4859 | containingObject[curKey] = this.result;
4860 | }
4861 | else {
4862 | bloblessData = this.result;
4863 | }
4864 |
4865 | // if nothing pending its callback time
4866 | if(! --pendingBlobs) {
4867 | callback(bloblessData);
4868 | }
4869 | };
4870 |
4871 | fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer
4872 | }
4873 |
4874 | if (isArray(obj)) { // handle array
4875 | for (var i = 0; i < obj.length; i++) {
4876 | removeBlobsRecursive(obj[i], i, obj);
4877 | }
4878 | } else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object
4879 | for (var key in obj) {
4880 | removeBlobsRecursive(obj[key], key, obj);
4881 | }
4882 | }
4883 | }
4884 |
4885 | var pendingBlobs = 0;
4886 | var bloblessData = data;
4887 | removeBlobsRecursive(bloblessData);
4888 | if (!pendingBlobs) {
4889 | callback(bloblessData);
4890 | }
4891 | }
4892 |
4893 | /**
4894 | * Returns true if obj is a buffer or an arraybuffer.
4895 | *
4896 | * @api private
4897 | */
4898 | function isBuf(obj) {
4899 | return (global.Buffer && Buffer.isBuffer(obj)) ||
4900 | (global.ArrayBuffer && obj instanceof ArrayBuffer);
4901 | }
4902 |
4903 | },{"isarray":41}],40:[function(require,module,exports){
4904 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
4905 | /**
4906 | * Module dependencies.
4907 | */
4908 |
4909 | var debug = require('debug')('socket.io-parser');
4910 | var json = require('json3');
4911 | var isArray = require('isarray');
4912 | var Emitter = require('emitter');
4913 | var binary = require('./binary');
4914 |
4915 | /**
4916 | * Protocol version.
4917 | *
4918 | * @api public
4919 | */
4920 |
4921 | exports.protocol = 3;
4922 |
4923 | /**
4924 | * Packet types.
4925 | *
4926 | * @api public
4927 | */
4928 |
4929 | exports.types = [
4930 | 'CONNECT',
4931 | 'DISCONNECT',
4932 | 'EVENT',
4933 | 'BINARY_EVENT',
4934 | 'ACK',
4935 | 'BINARY_ACK',
4936 | 'ERROR'
4937 | ];
4938 |
4939 | /**
4940 | * Packet type `connect`.
4941 | *
4942 | * @api public
4943 | */
4944 |
4945 | exports.CONNECT = 0;
4946 |
4947 | /**
4948 | * Packet type `disconnect`.
4949 | *
4950 | * @api public
4951 | */
4952 |
4953 | exports.DISCONNECT = 1;
4954 |
4955 | /**
4956 | * Packet type `event`.
4957 | *
4958 | * @api public
4959 | */
4960 |
4961 | exports.EVENT = 2;
4962 |
4963 | /**
4964 | * Packet type `ack`.
4965 | *
4966 | * @api public
4967 | */
4968 |
4969 | exports.ACK = 3;
4970 |
4971 | /**
4972 | * Packet type `error`.
4973 | *
4974 | * @api public
4975 | */
4976 |
4977 | exports.ERROR = 4;
4978 |
4979 | /**
4980 | * Packet type 'binary event'
4981 | *
4982 | * @api public
4983 | */
4984 |
4985 | exports.BINARY_EVENT = 5;
4986 |
4987 | /**
4988 | * Packet type `binary ack`. For acks with binary arguments.
4989 | *
4990 | * @api public
4991 | */
4992 |
4993 | exports.BINARY_ACK = 6;
4994 |
4995 | exports.Encoder = Encoder
4996 |
4997 | /**
4998 | * A socket.io Encoder instance
4999 | *
5000 | * @api public
5001 | */
5002 | function Encoder() {};
5003 |
5004 | /**
5005 | * Encode a packet as a single string if non-binary, or as a
5006 | * buffer sequence, depending on packet type.
5007 | *
5008 | * @param {Object} obj - packet object
5009 | * @param {Function} callback - function to handle encodings (likely engine.write)
5010 | * @return Calls callback with Array of encodings
5011 | * @api public
5012 | */
5013 |
5014 | Encoder.prototype.encode = function(obj, callback){
5015 | debug('encoding packet %j', obj);
5016 |
5017 | if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
5018 | encodeAsBinary(obj, callback);
5019 | }
5020 | else {
5021 | var encoding = encodeAsString(obj);
5022 | callback([encoding]);
5023 | }
5024 | };
5025 |
5026 | /**
5027 | * Encode packet as string.
5028 | *
5029 | * @param {Object} packet
5030 | * @return {String} encoded
5031 | * @api private
5032 | */
5033 |
5034 | function encodeAsString(obj) {
5035 | var str = '';
5036 | var nsp = false;
5037 |
5038 | // first is type
5039 | str += obj.type;
5040 |
5041 | // attachments if we have them
5042 | if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
5043 | str += obj.attachments;
5044 | str += '-';
5045 | }
5046 |
5047 | // if we have a namespace other than `/`
5048 | // we append it followed by a comma `,`
5049 | if (obj.nsp && '/' != obj.nsp) {
5050 | nsp = true;
5051 | str += obj.nsp;
5052 | }
5053 |
5054 | // immediately followed by the id
5055 | if (null != obj.id) {
5056 | if (nsp) {
5057 | str += ',';
5058 | nsp = false;
5059 | }
5060 | str += obj.id;
5061 | }
5062 |
5063 | // json data
5064 | if (null != obj.data) {
5065 | if (nsp) str += ',';
5066 | str += json.stringify(obj.data);
5067 | }
5068 |
5069 | debug('encoded %j as %s', obj, str);
5070 | return str;
5071 | }
5072 |
5073 | /**
5074 | * Encode packet as 'buffer sequence' by removing blobs, and
5075 | * deconstructing packet into object with placeholders and
5076 | * a list of buffers.
5077 | *
5078 | * @param {Object} packet
5079 | * @return {Buffer} encoded
5080 | * @api private
5081 | */
5082 |
5083 | function encodeAsBinary(obj, callback) {
5084 |
5085 | function writeEncoding(bloblessData) {
5086 | var deconstruction = binary.deconstructPacket(bloblessData);
5087 | var pack = encodeAsString(deconstruction.packet);
5088 | var buffers = deconstruction.buffers;
5089 |
5090 | buffers.unshift(pack); // add packet info to beginning of data list
5091 | callback(buffers); // write all the buffers
5092 | }
5093 |
5094 | binary.removeBlobs(obj, writeEncoding);
5095 | }
5096 |
5097 | exports.Decoder = Decoder
5098 |
5099 | /**
5100 | * A socket.io Decoder instance
5101 | *
5102 | * @return {Object} decoder
5103 | * @api public
5104 | */
5105 |
5106 | function Decoder() {
5107 | this.reconstructor = null;
5108 | }
5109 |
5110 | /**
5111 | * Mix in `Emitter` with Decoder.
5112 | */
5113 |
5114 | Emitter(Decoder.prototype);
5115 |
5116 | /**
5117 | * Decodes an ecoded packet string into packet JSON.
5118 | *
5119 | * @param {String} obj - encoded packet
5120 | * @return {Object} packet
5121 | * @api public
5122 | */
5123 |
5124 | Decoder.prototype.add = function(obj) {
5125 | var packet;
5126 | if ('string' == typeof obj) {
5127 | packet = decodeString(obj);
5128 | if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json
5129 | this.reconstructor = new BinaryReconstructor(packet);
5130 |
5131 | // no attachments, labeled binary but no binary data to follow
5132 | if (this.reconstructor.reconPack.attachments == 0) {
5133 | this.emit('decoded', packet);
5134 | }
5135 | } else { // non-binary full packet
5136 | this.emit('decoded', packet);
5137 | }
5138 | }
5139 | else if ((global.Buffer && Buffer.isBuffer(obj)) ||
5140 | (global.ArrayBuffer && obj instanceof ArrayBuffer) ||
5141 | obj.base64) { // raw binary data
5142 | if (!this.reconstructor) {
5143 | throw new Error('got binary data when not reconstructing a packet');
5144 | } else {
5145 | packet = this.reconstructor.takeBinaryData(obj);
5146 | if (packet) { // received final buffer
5147 | this.reconstructor = null;
5148 | this.emit('decoded', packet);
5149 | }
5150 | }
5151 | }
5152 | else {
5153 | throw new Error('Unknown type: ' + obj);
5154 | }
5155 | }
5156 |
5157 | /**
5158 | * Decode a packet String (JSON data)
5159 | *
5160 | * @param {String} str
5161 | * @return {Object} packet
5162 | * @api private
5163 | */
5164 |
5165 | function decodeString(str) {
5166 | var p = {};
5167 | var i = 0;
5168 |
5169 | // look up type
5170 | p.type = Number(str.charAt(0));
5171 | if (null == exports.types[p.type]) return error();
5172 |
5173 | // look up attachments if type binary
5174 | if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) {
5175 | p.attachments = '';
5176 | while (str.charAt(++i) != '-') {
5177 | p.attachments += str.charAt(i);
5178 | }
5179 | p.attachments = Number(p.attachments);
5180 | }
5181 |
5182 | // look up namespace (if any)
5183 | if ('/' == str.charAt(i + 1)) {
5184 | p.nsp = '';
5185 | while (++i) {
5186 | var c = str.charAt(i);
5187 | if (',' == c) break;
5188 | p.nsp += c;
5189 | if (i + 1 == str.length) break;
5190 | }
5191 | } else {
5192 | p.nsp = '/';
5193 | }
5194 |
5195 | // look up id
5196 | var next = str.charAt(i + 1);
5197 | if ('' != next && Number(next) == next) {
5198 | p.id = '';
5199 | while (++i) {
5200 | var c = str.charAt(i);
5201 | if (null == c || Number(c) != c) {
5202 | --i;
5203 | break;
5204 | }
5205 | p.id += str.charAt(i);
5206 | if (i + 1 == str.length) break;
5207 | }
5208 | p.id = Number(p.id);
5209 | }
5210 |
5211 | // look up json data
5212 | if (str.charAt(++i)) {
5213 | try {
5214 | p.data = json.parse(str.substr(i));
5215 | } catch(e){
5216 | return error();
5217 | }
5218 | }
5219 |
5220 | debug('decoded %s as %j', str, p);
5221 | return p;
5222 | };
5223 |
5224 | /**
5225 | * Deallocates a parser's resources
5226 | *
5227 | * @api public
5228 | */
5229 |
5230 | Decoder.prototype.destroy = function() {
5231 | if (this.reconstructor) {
5232 | this.reconstructor.finishedReconstruction();
5233 | }
5234 | }
5235 |
5236 | /**
5237 | * A manager of a binary event's 'buffer sequence'. Should
5238 | * be constructed whenever a packet of type BINARY_EVENT is
5239 | * decoded.
5240 | *
5241 | * @param {Object} packet
5242 | * @return {BinaryReconstructor} initialized reconstructor
5243 | * @api private
5244 | */
5245 |
5246 | function BinaryReconstructor(packet) {
5247 | this.reconPack = packet;
5248 | this.buffers = [];
5249 | }
5250 |
5251 | /**
5252 | * Method to be called when binary data received from connection
5253 | * after a BINARY_EVENT packet.
5254 | *
5255 | * @param {Buffer | ArrayBuffer} binData - the raw binary data received
5256 | * @return {null | Object} returns null if more binary data is expected or
5257 | * a reconstructed packet object if all buffers have been received.
5258 | * @api private
5259 | */
5260 |
5261 | BinaryReconstructor.prototype.takeBinaryData = function(binData) {
5262 | this.buffers.push(binData);
5263 | if (this.buffers.length == this.reconPack.attachments) { // done with buffer list
5264 | var packet = binary.reconstructPacket(this.reconPack, this.buffers);
5265 | this.finishedReconstruction();
5266 | return packet;
5267 | }
5268 | return null;
5269 | }
5270 |
5271 | /**
5272 | * Cleans up binary packet reconstruction variables.
5273 | *
5274 | * @api private
5275 | */
5276 |
5277 | BinaryReconstructor.prototype.finishedReconstruction = function() {
5278 | this.reconPack = null;
5279 | this.buffers = [];
5280 | }
5281 |
5282 | function error(data){
5283 | return {
5284 | type: exports.ERROR,
5285 | data: 'parser error'
5286 | };
5287 | }
5288 |
5289 | },{"./binary":39,"debug":9,"emitter":10,"isarray":41,"json3":42}],41:[function(require,module,exports){
5290 | module.exports=require(33)
5291 | },{}],42:[function(require,module,exports){
5292 | /*! JSON v3.2.6 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */
5293 | ;(function (window) {
5294 | // Convenience aliases.
5295 | var getClass = {}.toString, isProperty, forEach, undef;
5296 |
5297 | // Detect the `define` function exposed by asynchronous module loaders. The
5298 | // strict `define` check is necessary for compatibility with `r.js`.
5299 | var isLoader = typeof define === "function" && define.amd;
5300 |
5301 | // Detect native implementations.
5302 | var nativeJSON = typeof JSON == "object" && JSON;
5303 |
5304 | // Set up the JSON 3 namespace, preferring the CommonJS `exports` object if
5305 | // available.
5306 | var JSON3 = typeof exports == "object" && exports && !exports.nodeType && exports;
5307 |
5308 | if (JSON3 && nativeJSON) {
5309 | // Explicitly delegate to the native `stringify` and `parse`
5310 | // implementations in CommonJS environments.
5311 | JSON3.stringify = nativeJSON.stringify;
5312 | JSON3.parse = nativeJSON.parse;
5313 | } else {
5314 | // Export for web browsers, JavaScript engines, and asynchronous module
5315 | // loaders, using the global `JSON` object if available.
5316 | JSON3 = window.JSON = nativeJSON || {};
5317 | }
5318 |
5319 | // Test the `Date#getUTC*` methods. Based on work by @Yaffle.
5320 | var isExtended = new Date(-3509827334573292);
5321 | try {
5322 | // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
5323 | // results for certain dates in Opera >= 10.53.
5324 | isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
5325 | // Safari < 2.0.2 stores the internal millisecond time value correctly,
5326 | // but clips the values returned by the date methods to the range of
5327 | // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
5328 | isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
5329 | } catch (exception) {}
5330 |
5331 | // Internal: Determines whether the native `JSON.stringify` and `parse`
5332 | // implementations are spec-compliant. Based on work by Ken Snyder.
5333 | function has(name) {
5334 | if (has[name] !== undef) {
5335 | // Return cached feature test result.
5336 | return has[name];
5337 | }
5338 |
5339 | var isSupported;
5340 | if (name == "bug-string-char-index") {
5341 | // IE <= 7 doesn't support accessing string characters using square
5342 | // bracket notation. IE 8 only supports this for primitives.
5343 | isSupported = "a"[0] != "a";
5344 | } else if (name == "json") {
5345 | // Indicates whether both `JSON.stringify` and `JSON.parse` are
5346 | // supported.
5347 | isSupported = has("json-stringify") && has("json-parse");
5348 | } else {
5349 | var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
5350 | // Test `JSON.stringify`.
5351 | if (name == "json-stringify") {
5352 | var stringify = JSON3.stringify, stringifySupported = typeof stringify == "function" && isExtended;
5353 | if (stringifySupported) {
5354 | // A test function object with a custom `toJSON` method.
5355 | (value = function () {
5356 | return 1;
5357 | }).toJSON = value;
5358 | try {
5359 | stringifySupported =
5360 | // Firefox 3.1b1 and b2 serialize string, number, and boolean
5361 | // primitives as object literals.
5362 | stringify(0) === "0" &&
5363 | // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
5364 | // literals.
5365 | stringify(new Number()) === "0" &&
5366 | stringify(new String()) == '""' &&
5367 | // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
5368 | // does not define a canonical JSON representation (this applies to
5369 | // objects with `toJSON` properties as well, *unless* they are nested
5370 | // within an object or array).
5371 | stringify(getClass) === undef &&
5372 | // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
5373 | // FF 3.1b3 pass this test.
5374 | stringify(undef) === undef &&
5375 | // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
5376 | // respectively, if the value is omitted entirely.
5377 | stringify() === undef &&
5378 | // FF 3.1b1, 2 throw an error if the given value is not a number,
5379 | // string, array, object, Boolean, or `null` literal. This applies to
5380 | // objects with custom `toJSON` methods as well, unless they are nested
5381 | // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
5382 | // methods entirely.
5383 | stringify(value) === "1" &&
5384 | stringify([value]) == "[1]" &&
5385 | // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
5386 | // `"[null]"`.
5387 | stringify([undef]) == "[null]" &&
5388 | // YUI 3.0.0b1 fails to serialize `null` literals.
5389 | stringify(null) == "null" &&
5390 | // FF 3.1b1, 2 halts serialization if an array contains a function:
5391 | // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
5392 | // elides non-JSON values from objects and arrays, unless they
5393 | // define custom `toJSON` methods.
5394 | stringify([undef, getClass, null]) == "[null,null,null]" &&
5395 | // Simple serialization test. FF 3.1b1 uses Unicode escape sequences
5396 | // where character escape codes are expected (e.g., `\b` => `\u0008`).
5397 | stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
5398 | // FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
5399 | stringify(null, value) === "1" &&
5400 | stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
5401 | // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
5402 | // serialize extended years.
5403 | stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
5404 | // The milliseconds are optional in ES 5, but required in 5.1.
5405 | stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
5406 | // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
5407 | // four-digit years instead of six-digit years. Credits: @Yaffle.
5408 | stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
5409 | // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
5410 | // values less than 1000. Credits: @Yaffle.
5411 | stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
5412 | } catch (exception) {
5413 | stringifySupported = false;
5414 | }
5415 | }
5416 | isSupported = stringifySupported;
5417 | }
5418 | // Test `JSON.parse`.
5419 | if (name == "json-parse") {
5420 | var parse = JSON3.parse;
5421 | if (typeof parse == "function") {
5422 | try {
5423 | // FF 3.1b1, b2 will throw an exception if a bare literal is provided.
5424 | // Conforming implementations should also coerce the initial argument to
5425 | // a string prior to parsing.
5426 | if (parse("0") === 0 && !parse(false)) {
5427 | // Simple parsing test.
5428 | value = parse(serialized);
5429 | var parseSupported = value["a"].length == 5 && value["a"][0] === 1;
5430 | if (parseSupported) {
5431 | try {
5432 | // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
5433 | parseSupported = !parse('"\t"');
5434 | } catch (exception) {}
5435 | if (parseSupported) {
5436 | try {
5437 | // FF 4.0 and 4.0.1 allow leading `+` signs and leading
5438 | // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
5439 | // certain octal literals.
5440 | parseSupported = parse("01") !== 1;
5441 | } catch (exception) {}
5442 | }
5443 | if (parseSupported) {
5444 | try {
5445 | // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
5446 | // points. These environments, along with FF 3.1b1 and 2,
5447 | // also allow trailing commas in JSON objects and arrays.
5448 | parseSupported = parse("1.") !== 1;
5449 | } catch (exception) {}
5450 | }
5451 | }
5452 | }
5453 | } catch (exception) {
5454 | parseSupported = false;
5455 | }
5456 | }
5457 | isSupported = parseSupported;
5458 | }
5459 | }
5460 | return has[name] = !!isSupported;
5461 | }
5462 |
5463 | if (!has("json")) {
5464 | // Common `[[Class]]` name aliases.
5465 | var functionClass = "[object Function]";
5466 | var dateClass = "[object Date]";
5467 | var numberClass = "[object Number]";
5468 | var stringClass = "[object String]";
5469 | var arrayClass = "[object Array]";
5470 | var booleanClass = "[object Boolean]";
5471 |
5472 | // Detect incomplete support for accessing string characters by index.
5473 | var charIndexBuggy = has("bug-string-char-index");
5474 |
5475 | // Define additional utility methods if the `Date` methods are buggy.
5476 | if (!isExtended) {
5477 | var floor = Math.floor;
5478 | // A mapping between the months of the year and the number of days between
5479 | // January 1st and the first of the respective month.
5480 | var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
5481 | // Internal: Calculates the number of days between the Unix epoch and the
5482 | // first day of the given month.
5483 | var getDay = function (year, month) {
5484 | return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
5485 | };
5486 | }
5487 |
5488 | // Internal: Determines if a property is a direct property of the given
5489 | // object. Delegates to the native `Object#hasOwnProperty` method.
5490 | if (!(isProperty = {}.hasOwnProperty)) {
5491 | isProperty = function (property) {
5492 | var members = {}, constructor;
5493 | if ((members.__proto__ = null, members.__proto__ = {
5494 | // The *proto* property cannot be set multiple times in recent
5495 | // versions of Firefox and SeaMonkey.
5496 | "toString": 1
5497 | }, members).toString != getClass) {
5498 | // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
5499 | // supports the mutable *proto* property.
5500 | isProperty = function (property) {
5501 | // Capture and break the object's prototype chain (see section 8.6.2
5502 | // of the ES 5.1 spec). The parenthesized expression prevents an
5503 | // unsafe transformation by the Closure Compiler.
5504 | var original = this.__proto__, result = property in (this.__proto__ = null, this);
5505 | // Restore the original prototype chain.
5506 | this.__proto__ = original;
5507 | return result;
5508 | };
5509 | } else {
5510 | // Capture a reference to the top-level `Object` constructor.
5511 | constructor = members.constructor;
5512 | // Use the `constructor` property to simulate `Object#hasOwnProperty` in
5513 | // other environments.
5514 | isProperty = function (property) {
5515 | var parent = (this.constructor || constructor).prototype;
5516 | return property in this && !(property in parent && this[property] === parent[property]);
5517 | };
5518 | }
5519 | members = null;
5520 | return isProperty.call(this, property);
5521 | };
5522 | }
5523 |
5524 | // Internal: A set of primitive types used by `isHostType`.
5525 | var PrimitiveTypes = {
5526 | 'boolean': 1,
5527 | 'number': 1,
5528 | 'string': 1,
5529 | 'undefined': 1
5530 | };
5531 |
5532 | // Internal: Determines if the given object `property` value is a
5533 | // non-primitive.
5534 | var isHostType = function (object, property) {
5535 | var type = typeof object[property];
5536 | return type == 'object' ? !!object[property] : !PrimitiveTypes[type];
5537 | };
5538 |
5539 | // Internal: Normalizes the `for...in` iteration algorithm across
5540 | // environments. Each enumerated key is yielded to a `callback` function.
5541 | forEach = function (object, callback) {
5542 | var size = 0, Properties, members, property;
5543 |
5544 | // Tests for bugs in the current environment's `for...in` algorithm. The
5545 | // `valueOf` property inherits the non-enumerable flag from
5546 | // `Object.prototype` in older versions of IE, Netscape, and Mozilla.
5547 | (Properties = function () {
5548 | this.valueOf = 0;
5549 | }).prototype.valueOf = 0;
5550 |
5551 | // Iterate over a new instance of the `Properties` class.
5552 | members = new Properties();
5553 | for (property in members) {
5554 | // Ignore all properties inherited from `Object.prototype`.
5555 | if (isProperty.call(members, property)) {
5556 | size++;
5557 | }
5558 | }
5559 | Properties = members = null;
5560 |
5561 | // Normalize the iteration algorithm.
5562 | if (!size) {
5563 | // A list of non-enumerable properties inherited from `Object.prototype`.
5564 | members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
5565 | // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
5566 | // properties.
5567 | forEach = function (object, callback) {
5568 | var isFunction = getClass.call(object) == functionClass, property, length;
5569 | var hasProperty = !isFunction && typeof object.constructor != 'function' && isHostType(object, 'hasOwnProperty') ? object.hasOwnProperty : isProperty;
5570 | for (property in object) {
5571 | // Gecko <= 1.0 enumerates the `prototype` property of functions under
5572 | // certain conditions; IE does not.
5573 | if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
5574 | callback(property);
5575 | }
5576 | }
5577 | // Manually invoke the callback for each non-enumerable property.
5578 | for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));
5579 | };
5580 | } else if (size == 2) {
5581 | // Safari <= 2.0.4 enumerates shadowed properties twice.
5582 | forEach = function (object, callback) {
5583 | // Create a set of iterated properties.
5584 | var members = {}, isFunction = getClass.call(object) == functionClass, property;
5585 | for (property in object) {
5586 | // Store each property name to prevent double enumeration. The
5587 | // `prototype` property of functions is not enumerated due to cross-
5588 | // environment inconsistencies.
5589 | if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
5590 | callback(property);
5591 | }
5592 | }
5593 | };
5594 | } else {
5595 | // No bugs detected; use the standard `for...in` algorithm.
5596 | forEach = function (object, callback) {
5597 | var isFunction = getClass.call(object) == functionClass, property, isConstructor;
5598 | for (property in object) {
5599 | if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
5600 | callback(property);
5601 | }
5602 | }
5603 | // Manually invoke the callback for the `constructor` property due to
5604 | // cross-environment inconsistencies.
5605 | if (isConstructor || isProperty.call(object, (property = "constructor"))) {
5606 | callback(property);
5607 | }
5608 | };
5609 | }
5610 | return forEach(object, callback);
5611 | };
5612 |
5613 | // Public: Serializes a JavaScript `value` as a JSON string. The optional
5614 | // `filter` argument may specify either a function that alters how object and
5615 | // array members are serialized, or an array of strings and numbers that
5616 | // indicates which properties should be serialized. The optional `width`
5617 | // argument may be either a string or number that specifies the indentation
5618 | // level of the output.
5619 | if (!has("json-stringify")) {
5620 | // Internal: A map of control characters and their escaped equivalents.
5621 | var Escapes = {
5622 | 92: "\\\\",
5623 | 34: '\\"',
5624 | 8: "\\b",
5625 | 12: "\\f",
5626 | 10: "\\n",
5627 | 13: "\\r",
5628 | 9: "\\t"
5629 | };
5630 |
5631 | // Internal: Converts `value` into a zero-padded string such that its
5632 | // length is at least equal to `width`. The `width` must be <= 6.
5633 | var leadingZeroes = "000000";
5634 | var toPaddedString = function (width, value) {
5635 | // The `|| 0` expression is necessary to work around a bug in
5636 | // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
5637 | return (leadingZeroes + (value || 0)).slice(-width);
5638 | };
5639 |
5640 | // Internal: Double-quotes a string `value`, replacing all ASCII control
5641 | // characters (characters with code unit values between 0 and 31) with
5642 | // their escaped equivalents. This is an implementation of the
5643 | // `Quote(value)` operation defined in ES 5.1 section 15.12.3.
5644 | var unicodePrefix = "\\u00";
5645 | var quote = function (value) {
5646 | var result = '"', index = 0, length = value.length, isLarge = length > 10 && charIndexBuggy, symbols;
5647 | if (isLarge) {
5648 | symbols = value.split("");
5649 | }
5650 | for (; index < length; index++) {
5651 | var charCode = value.charCodeAt(index);
5652 | // If the character is a control character, append its Unicode or
5653 | // shorthand escape sequence; otherwise, append the character as-is.
5654 | switch (charCode) {
5655 | case 8: case 9: case 10: case 12: case 13: case 34: case 92:
5656 | result += Escapes[charCode];
5657 | break;
5658 | default:
5659 | if (charCode < 32) {
5660 | result += unicodePrefix + toPaddedString(2, charCode.toString(16));
5661 | break;
5662 | }
5663 | result += isLarge ? symbols[index] : charIndexBuggy ? value.charAt(index) : value[index];
5664 | }
5665 | }
5666 | return result + '"';
5667 | };
5668 |
5669 | // Internal: Recursively serializes an object. Implements the
5670 | // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
5671 | var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
5672 | var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
5673 | try {
5674 | // Necessary for host object support.
5675 | value = object[property];
5676 | } catch (exception) {}
5677 | if (typeof value == "object" && value) {
5678 | className = getClass.call(value);
5679 | if (className == dateClass && !isProperty.call(value, "toJSON")) {
5680 | if (value > -1 / 0 && value < 1 / 0) {
5681 | // Dates are serialized according to the `Date#toJSON` method
5682 | // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
5683 | // for the ISO 8601 date time string format.
5684 | if (getDay) {
5685 | // Manually compute the year, month, date, hours, minutes,
5686 | // seconds, and milliseconds if the `getUTC*` methods are
5687 | // buggy. Adapted from @Yaffle's `date-shim` project.
5688 | date = floor(value / 864e5);
5689 | for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
5690 | for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
5691 | date = 1 + date - getDay(year, month);
5692 | // The `time` value specifies the time within the day (see ES
5693 | // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
5694 | // to compute `A modulo B`, as the `%` operator does not
5695 | // correspond to the `modulo` operation for negative numbers.
5696 | time = (value % 864e5 + 864e5) % 864e5;
5697 | // The hours, minutes, seconds, and milliseconds are obtained by
5698 | // decomposing the time within the day. See section 15.9.1.10.
5699 | hours = floor(time / 36e5) % 24;
5700 | minutes = floor(time / 6e4) % 60;
5701 | seconds = floor(time / 1e3) % 60;
5702 | milliseconds = time % 1e3;
5703 | } else {
5704 | year = value.getUTCFullYear();
5705 | month = value.getUTCMonth();
5706 | date = value.getUTCDate();
5707 | hours = value.getUTCHours();
5708 | minutes = value.getUTCMinutes();
5709 | seconds = value.getUTCSeconds();
5710 | milliseconds = value.getUTCMilliseconds();
5711 | }
5712 | // Serialize extended years correctly.
5713 | value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
5714 | "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
5715 | // Months, dates, hours, minutes, and seconds should have two
5716 | // digits; milliseconds should have three.
5717 | "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
5718 | // Milliseconds are optional in ES 5.0, but required in 5.1.
5719 | "." + toPaddedString(3, milliseconds) + "Z";
5720 | } else {
5721 | value = null;
5722 | }
5723 | } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) {
5724 | // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
5725 | // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
5726 | // ignores all `toJSON` methods on these objects unless they are
5727 | // defined directly on an instance.
5728 | value = value.toJSON(property);
5729 | }
5730 | }
5731 | if (callback) {
5732 | // If a replacement function was provided, call it to obtain the value
5733 | // for serialization.
5734 | value = callback.call(object, property, value);
5735 | }
5736 | if (value === null) {
5737 | return "null";
5738 | }
5739 | className = getClass.call(value);
5740 | if (className == booleanClass) {
5741 | // Booleans are represented literally.
5742 | return "" + value;
5743 | } else if (className == numberClass) {
5744 | // JSON numbers must be finite. `Infinity` and `NaN` are serialized as
5745 | // `"null"`.
5746 | return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
5747 | } else if (className == stringClass) {
5748 | // Strings are double-quoted and escaped.
5749 | return quote("" + value);
5750 | }
5751 | // Recursively serialize objects and arrays.
5752 | if (typeof value == "object") {
5753 | // Check for cyclic structures. This is a linear search; performance
5754 | // is inversely proportional to the number of unique nested objects.
5755 | for (length = stack.length; length--;) {
5756 | if (stack[length] === value) {
5757 | // Cyclic structures cannot be serialized by `JSON.stringify`.
5758 | throw TypeError();
5759 | }
5760 | }
5761 | // Add the object to the stack of traversed objects.
5762 | stack.push(value);
5763 | results = [];
5764 | // Save the current indentation level and indent one additional level.
5765 | prefix = indentation;
5766 | indentation += whitespace;
5767 | if (className == arrayClass) {
5768 | // Recursively serialize array elements.
5769 | for (index = 0, length = value.length; index < length; index++) {
5770 | element = serialize(index, value, callback, properties, whitespace, indentation, stack);
5771 | results.push(element === undef ? "null" : element);
5772 | }
5773 | result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
5774 | } else {
5775 | // Recursively serialize object members. Members are selected from
5776 | // either a user-specified list of property names, or the object
5777 | // itself.
5778 | forEach(properties || value, function (property) {
5779 | var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
5780 | if (element !== undef) {
5781 | // According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
5782 | // is not the empty string, let `member` {quote(property) + ":"}
5783 | // be the concatenation of `member` and the `space` character."
5784 | // The "`space` character" refers to the literal space
5785 | // character, not the `space` {width} argument provided to
5786 | // `JSON.stringify`.
5787 | results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
5788 | }
5789 | });
5790 | result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
5791 | }
5792 | // Remove the object from the traversed object stack.
5793 | stack.pop();
5794 | return result;
5795 | }
5796 | };
5797 |
5798 | // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
5799 | JSON3.stringify = function (source, filter, width) {
5800 | var whitespace, callback, properties, className;
5801 | if (typeof filter == "function" || typeof filter == "object" && filter) {
5802 | if ((className = getClass.call(filter)) == functionClass) {
5803 | callback = filter;
5804 | } else if (className == arrayClass) {
5805 | // Convert the property names array into a makeshift set.
5806 | properties = {};
5807 | for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));
5808 | }
5809 | }
5810 | if (width) {
5811 | if ((className = getClass.call(width)) == numberClass) {
5812 | // Convert the `width` to an integer and create a string containing
5813 | // `width` number of space characters.
5814 | if ((width -= width % 1) > 0) {
5815 | for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
5816 | }
5817 | } else if (className == stringClass) {
5818 | whitespace = width.length <= 10 ? width : width.slice(0, 10);
5819 | }
5820 | }
5821 | // Opera <= 7.54u2 discards the values associated with empty string keys
5822 | // (`""`) only if they are used directly within an object member list
5823 | // (e.g., `!("" in { "": 1})`).
5824 | return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
5825 | };
5826 | }
5827 |
5828 | // Public: Parses a JSON source string.
5829 | if (!has("json-parse")) {
5830 | var fromCharCode = String.fromCharCode;
5831 |
5832 | // Internal: A map of escaped control characters and their unescaped
5833 | // equivalents.
5834 | var Unescapes = {
5835 | 92: "\\",
5836 | 34: '"',
5837 | 47: "/",
5838 | 98: "\b",
5839 | 116: "\t",
5840 | 110: "\n",
5841 | 102: "\f",
5842 | 114: "\r"
5843 | };
5844 |
5845 | // Internal: Stores the parser state.
5846 | var Index, Source;
5847 |
5848 | // Internal: Resets the parser state and throws a `SyntaxError`.
5849 | var abort = function() {
5850 | Index = Source = null;
5851 | throw SyntaxError();
5852 | };
5853 |
5854 | // Internal: Returns the next token, or `"$"` if the parser has reached
5855 | // the end of the source string. A token may be a string, number, `null`
5856 | // literal, or Boolean literal.
5857 | var lex = function () {
5858 | var source = Source, length = source.length, value, begin, position, isSigned, charCode;
5859 | while (Index < length) {
5860 | charCode = source.charCodeAt(Index);
5861 | switch (charCode) {
5862 | case 9: case 10: case 13: case 32:
5863 | // Skip whitespace tokens, including tabs, carriage returns, line
5864 | // feeds, and space characters.
5865 | Index++;
5866 | break;
5867 | case 123: case 125: case 91: case 93: case 58: case 44:
5868 | // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
5869 | // the current position.
5870 | value = charIndexBuggy ? source.charAt(Index) : source[Index];
5871 | Index++;
5872 | return value;
5873 | case 34:
5874 | // `"` delimits a JSON string; advance to the next character and
5875 | // begin parsing the string. String tokens are prefixed with the
5876 | // sentinel `@` character to distinguish them from punctuators and
5877 | // end-of-string tokens.
5878 | for (value = "@", Index++; Index < length;) {
5879 | charCode = source.charCodeAt(Index);
5880 | if (charCode < 32) {
5881 | // Unescaped ASCII control characters (those with a code unit
5882 | // less than the space character) are not permitted.
5883 | abort();
5884 | } else if (charCode == 92) {
5885 | // A reverse solidus (`\`) marks the beginning of an escaped
5886 | // control character (including `"`, `\`, and `/`) or Unicode
5887 | // escape sequence.
5888 | charCode = source.charCodeAt(++Index);
5889 | switch (charCode) {
5890 | case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
5891 | // Revive escaped control characters.
5892 | value += Unescapes[charCode];
5893 | Index++;
5894 | break;
5895 | case 117:
5896 | // `\u` marks the beginning of a Unicode escape sequence.
5897 | // Advance to the first character and validate the
5898 | // four-digit code point.
5899 | begin = ++Index;
5900 | for (position = Index + 4; Index < position; Index++) {
5901 | charCode = source.charCodeAt(Index);
5902 | // A valid sequence comprises four hexdigits (case-
5903 | // insensitive) that form a single hexadecimal value.
5904 | if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
5905 | // Invalid Unicode escape sequence.
5906 | abort();
5907 | }
5908 | }
5909 | // Revive the escaped character.
5910 | value += fromCharCode("0x" + source.slice(begin, Index));
5911 | break;
5912 | default:
5913 | // Invalid escape sequence.
5914 | abort();
5915 | }
5916 | } else {
5917 | if (charCode == 34) {
5918 | // An unescaped double-quote character marks the end of the
5919 | // string.
5920 | break;
5921 | }
5922 | charCode = source.charCodeAt(Index);
5923 | begin = Index;
5924 | // Optimize for the common case where a string is valid.
5925 | while (charCode >= 32 && charCode != 92 && charCode != 34) {
5926 | charCode = source.charCodeAt(++Index);
5927 | }
5928 | // Append the string as-is.
5929 | value += source.slice(begin, Index);
5930 | }
5931 | }
5932 | if (source.charCodeAt(Index) == 34) {
5933 | // Advance to the next character and return the revived string.
5934 | Index++;
5935 | return value;
5936 | }
5937 | // Unterminated string.
5938 | abort();
5939 | default:
5940 | // Parse numbers and literals.
5941 | begin = Index;
5942 | // Advance past the negative sign, if one is specified.
5943 | if (charCode == 45) {
5944 | isSigned = true;
5945 | charCode = source.charCodeAt(++Index);
5946 | }
5947 | // Parse an integer or floating-point value.
5948 | if (charCode >= 48 && charCode <= 57) {
5949 | // Leading zeroes are interpreted as octal literals.
5950 | if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
5951 | // Illegal octal literal.
5952 | abort();
5953 | }
5954 | isSigned = false;
5955 | // Parse the integer component.
5956 | for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
5957 | // Floats cannot contain a leading decimal point; however, this
5958 | // case is already accounted for by the parser.
5959 | if (source.charCodeAt(Index) == 46) {
5960 | position = ++Index;
5961 | // Parse the decimal component.
5962 | for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
5963 | if (position == Index) {
5964 | // Illegal trailing decimal.
5965 | abort();
5966 | }
5967 | Index = position;
5968 | }
5969 | // Parse exponents. The `e` denoting the exponent is
5970 | // case-insensitive.
5971 | charCode = source.charCodeAt(Index);
5972 | if (charCode == 101 || charCode == 69) {
5973 | charCode = source.charCodeAt(++Index);
5974 | // Skip past the sign following the exponent, if one is
5975 | // specified.
5976 | if (charCode == 43 || charCode == 45) {
5977 | Index++;
5978 | }
5979 | // Parse the exponential component.
5980 | for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
5981 | if (position == Index) {
5982 | // Illegal empty exponent.
5983 | abort();
5984 | }
5985 | Index = position;
5986 | }
5987 | // Coerce the parsed value to a JavaScript number.
5988 | return +source.slice(begin, Index);
5989 | }
5990 | // A negative sign may only precede numbers.
5991 | if (isSigned) {
5992 | abort();
5993 | }
5994 | // `true`, `false`, and `null` literals.
5995 | if (source.slice(Index, Index + 4) == "true") {
5996 | Index += 4;
5997 | return true;
5998 | } else if (source.slice(Index, Index + 5) == "false") {
5999 | Index += 5;
6000 | return false;
6001 | } else if (source.slice(Index, Index + 4) == "null") {
6002 | Index += 4;
6003 | return null;
6004 | }
6005 | // Unrecognized token.
6006 | abort();
6007 | }
6008 | }
6009 | // Return the sentinel `$` character if the parser has reached the end
6010 | // of the source string.
6011 | return "$";
6012 | };
6013 |
6014 | // Internal: Parses a JSON `value` token.
6015 | var get = function (value) {
6016 | var results, hasMembers;
6017 | if (value == "$") {
6018 | // Unexpected end of input.
6019 | abort();
6020 | }
6021 | if (typeof value == "string") {
6022 | if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
6023 | // Remove the sentinel `@` character.
6024 | return value.slice(1);
6025 | }
6026 | // Parse object and array literals.
6027 | if (value == "[") {
6028 | // Parses a JSON array, returning a new JavaScript array.
6029 | results = [];
6030 | for (;; hasMembers || (hasMembers = true)) {
6031 | value = lex();
6032 | // A closing square bracket marks the end of the array literal.
6033 | if (value == "]") {
6034 | break;
6035 | }
6036 | // If the array literal contains elements, the current token
6037 | // should be a comma separating the previous element from the
6038 | // next.
6039 | if (hasMembers) {
6040 | if (value == ",") {
6041 | value = lex();
6042 | if (value == "]") {
6043 | // Unexpected trailing `,` in array literal.
6044 | abort();
6045 | }
6046 | } else {
6047 | // A `,` must separate each array element.
6048 | abort();
6049 | }
6050 | }
6051 | // Elisions and leading commas are not permitted.
6052 | if (value == ",") {
6053 | abort();
6054 | }
6055 | results.push(get(value));
6056 | }
6057 | return results;
6058 | } else if (value == "{") {
6059 | // Parses a JSON object, returning a new JavaScript object.
6060 | results = {};
6061 | for (;; hasMembers || (hasMembers = true)) {
6062 | value = lex();
6063 | // A closing curly brace marks the end of the object literal.
6064 | if (value == "}") {
6065 | break;
6066 | }
6067 | // If the object literal contains members, the current token
6068 | // should be a comma separator.
6069 | if (hasMembers) {
6070 | if (value == ",") {
6071 | value = lex();
6072 | if (value == "}") {
6073 | // Unexpected trailing `,` in object literal.
6074 | abort();
6075 | }
6076 | } else {
6077 | // A `,` must separate each object member.
6078 | abort();
6079 | }
6080 | }
6081 | // Leading commas are not permitted, object property names must be
6082 | // double-quoted strings, and a `:` must separate each property
6083 | // name and value.
6084 | if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
6085 | abort();
6086 | }
6087 | results[value.slice(1)] = get(lex());
6088 | }
6089 | return results;
6090 | }
6091 | // Unexpected token encountered.
6092 | abort();
6093 | }
6094 | return value;
6095 | };
6096 |
6097 | // Internal: Updates a traversed object member.
6098 | var update = function(source, property, callback) {
6099 | var element = walk(source, property, callback);
6100 | if (element === undef) {
6101 | delete source[property];
6102 | } else {
6103 | source[property] = element;
6104 | }
6105 | };
6106 |
6107 | // Internal: Recursively traverses a parsed JSON object, invoking the
6108 | // `callback` function for each value. This is an implementation of the
6109 | // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
6110 | var walk = function (source, property, callback) {
6111 | var value = source[property], length;
6112 | if (typeof value == "object" && value) {
6113 | // `forEach` can't be used to traverse an array in Opera <= 8.54
6114 | // because its `Object#hasOwnProperty` implementation returns `false`
6115 | // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
6116 | if (getClass.call(value) == arrayClass) {
6117 | for (length = value.length; length--;) {
6118 | update(value, length, callback);
6119 | }
6120 | } else {
6121 | forEach(value, function (property) {
6122 | update(value, property, callback);
6123 | });
6124 | }
6125 | }
6126 | return callback.call(source, property, value);
6127 | };
6128 |
6129 | // Public: `JSON.parse`. See ES 5.1 section 15.12.2.
6130 | JSON3.parse = function (source, callback) {
6131 | var result, value;
6132 | Index = 0;
6133 | Source = "" + source;
6134 | result = get(lex());
6135 | // If a JSON string contains multiple tokens, it is invalid.
6136 | if (lex() != "$") {
6137 | abort();
6138 | }
6139 | // Reset the parser state.
6140 | Index = Source = null;
6141 | return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
6142 | };
6143 | }
6144 | }
6145 |
6146 | // Export for asynchronous module loaders.
6147 | if (isLoader) {
6148 | define(function () {
6149 | return JSON3;
6150 | });
6151 | }
6152 | }(this));
6153 |
6154 | },{}],43:[function(require,module,exports){
6155 | module.exports = toArray
6156 |
6157 | function toArray(list, index) {
6158 | var array = []
6159 |
6160 | index = index || 0
6161 |
6162 | for (var i = index || 0; i < list.length; i++) {
6163 | array[i - index] = list[i]
6164 | }
6165 |
6166 | return array
6167 | }
6168 |
6169 | },{}]},{},[1])
6170 | (1)
6171 | });
6172 | ;
6173 |
--------------------------------------------------------------------------------
/template/socket_client.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 | var socket = new io();
4 |
5 | socket.on('reload', function(msg){
6 | location.reload();
7 | });
8 |
9 | socket.on('die', function(msg) {
10 | window.open('', '_self', '');
11 | window.close();
12 |
13 | var firefoxWarning =
14 | "Oops!
" +
15 | "Firefox doesn't allow windows to self-close.
" +
16 | "If you want the preview window to close automatically like in other browsers, go to about:config and set dom.allow_scripts_to_close_windows to true.
"
17 | document.body.innerHTML = firefoxWarning;
18 | });
19 | socket.on('cssReload', function(msg){
20 | cssLinks = document.getElementsByTagName('link');
21 |
22 | for(var i=0; i < cssLinks.length; i++ ){
23 | if(cssLinks[i].rel=='stylesheet' && cssLinks[i].href.indexOf(msg) > -1){
24 | d = new Date();
25 | // https://groups.google.com/forum/#!topic/mimosajs/A7Kbf6plBd0
26 | if (typeof window.chrome != 'undefined'){
27 | // break the url to force update in chrome
28 | console.log("chrome");
29 | // cssLinks[i].href = '#asdf';
30 | }
31 | cssLinks[i].href = cssLinks[i].href.replace(/\?.*|$/,'?v= '+ d.getTime() )
32 | }
33 | }
34 | });
35 |
36 | })();
37 |
--------------------------------------------------------------------------------
/testCurl.sh:
--------------------------------------------------------------------------------
1 | curl -X PUT localhost:8092/index.html
2 |
--------------------------------------------------------------------------------