2017-02-23 23:10:36 -05:00
( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
function Color ( h , s , l , a )
{
verifyRange ( h , s , l ) ;
if ( a === undefined ) a = 1 ;
else verifyRange ( a ) ;
Object . defineProperties ( this , {
"hue" : { value : h , enumerable : true } ,
"sat" : { value : s , enumerable : true } ,
"lum" : { value : l , enumerable : true } ,
"alpha" : { value : a , enumerable : true } ,
} ) ;
}
function verifyRange ( )
{
for ( var i = 0 ; i < arguments . length ; i ++ )
{
if ( arguments [ i ] < 0 || arguments [ i ] > 1 )
throw new RangeError ( "H, S, L, and A parameters must be between the range [0, 1]" ) ;
}
}
2017-02-24 19:57:13 -05:00
Color . prototype . interpolateToString = function ( color , amount )
{
var rgbThis = hslToRgb ( this . hue , this . sat , this . lum ) ;
var rgbThat = hslToRgb ( color . hue , color . sat , color . lum ) ;
var rgb = [ ] ;
for ( var i = 0 ; i < 3 ; i ++ )
rgb [ i ] = Math . floor ( ( rgbThat [ i ] - rgbThis [ i ] ) * amount + rgbThis [ i ] ) ;
return { rgbString : function ( ) { return 'rgb(' + rgb [ 0 ] + ', ' + rgb [ 1 ] + ', ' + rgb [ 2 ] + ')' } } ;
}
2017-02-23 23:10:36 -05:00
Color . prototype . deriveLumination = function ( amount )
{
var lum = this . lum + amount ;
lum = Math . min ( Math . max ( lum , 0 ) , 1 ) ;
return new Color ( this . hue , this . sat , lum , this . alpha ) ;
} ;
Color . prototype . deriveHue = function ( amount )
{
var hue = this . hue - amount ;
return new Color ( hue - Math . floor ( hue ) , this . sat , this . lum , this . alpha ) ;
} ;
Color . prototype . deriveSaturation = function ( amount )
{
var sat = this . sat + amount ;
sat = Math . min ( Math . max ( sat , 0 ) , 1 ) ;
return new Color ( this . hue , sat , this . lum , this . alpha ) ;
} ;
Color . prototype . deriveAlpha = function ( newAlpha )
{
verifyRange ( newAlpha ) ;
return new Color ( this . hue , this . sat , this . lum , newAlpha ) ;
} ;
Color . prototype . rgbString = function ( ) {
var rgb = hslToRgb ( this . hue , this . sat , this . lum ) ;
rgb [ 3 ] = this . a ;
return 'rgba(' + rgb [ 0 ] + ', ' + rgb [ 1 ] + ', ' + rgb [ 2 ] + ', ' + this . alpha + ')' ;
} ;
//http://stackoverflow.com/a/9493060/7344257
function hslToRgb ( h , s , l ) {
var r , g , b ;
if ( s == 0 ) {
r = g = b = l ; // achromatic
} else {
var hue2rgb = function hue2rgb ( p , q , t ) {
if ( t < 0 ) t += 1 ;
if ( t > 1 ) t -= 1 ;
if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t ;
if ( t < 1 / 2 ) return q ;
if ( t < 2 / 3 ) return p + ( q - p ) * ( 2 / 3 - t ) * 6 ;
return p ;
} ;
var q = l < 0.5 ? l * ( 1 + s ) : l + s - l * s ;
var p = 2 * l - q ;
r = hue2rgb ( p , q , h + 1 / 3 ) ;
g = hue2rgb ( p , q , h ) ;
b = hue2rgb ( p , q , h - 1 / 3 ) ;
}
return [ Math . round ( r * 255 ) , Math . round ( g * 255 ) , Math . round ( b * 255 ) ] ;
}
module . exports = Color ;
2017-02-25 23:25:06 -05:00
} , { } ] , 2 : [ function ( require , module , exports ) {
2017-02-25 18:52:52 -05:00
/* global $ */
2017-02-23 23:10:36 -05:00
var Player = require ( "./player.js" ) ;
2017-02-25 18:52:52 -05:00
var renderer = require ( "./game-renderer.js" ) ;
var consts = require ( "./game-consts.js" ) ;
2017-02-26 02:31:30 -05:00
var core = require ( "./game-core.js" ) ;
2017-02-25 18:52:52 -05:00
2017-02-25 21:36:44 -05:00
var GRID _SIZE = consts . GRID _SIZE ;
var CELL _WIDTH = consts . CELL _WIDTH ;
renderer . allowAnimation = true ;
2017-02-23 23:10:36 -05:00
/ * *
* Provides requestAnimationFrame in a cross browser way .
* @ author paulirish / http : //paulirish.com/
* /
// window.requestAnimationFrame = function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
// window.setTimeout( callback, 1000 / 60 );
// };
if ( ! window . requestAnimationFrame ) {
window . requestAnimationFrame = ( function ( ) {
return window . webkitRequestAnimationFrame ||
window . mozRequestAnimationFrame ||
window . oRequestAnimationFrame ||
window . msRequestAnimationFrame ||
function ( /* function FrameRequestCallback */ callback , /* DOMElement Element */ element ) {
window . setTimeout ( callback , 1000 / 60 ) ;
} ;
} ) ( ) ;
}
2017-02-25 21:36:44 -05:00
var user , socket , frame ;
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
//Event listeners
$ ( document ) . keydown ( function ( e ) {
if ( user . dead )
return ;
var newHeading = - 1 ;
switch ( e . which )
2017-02-23 23:10:36 -05:00
{
2017-02-25 21:36:44 -05:00
case 37 : newHeading = 3 ; break ; //LEFT
case 38 : newHeading = 0 ; break ; //UP
case 39 : newHeading = 1 ; break ; //RIGHT
case 40 : newHeading = 2 ; break ; //DOWN
default : return ; //exit handler for other keys.
2017-02-23 23:10:36 -05:00
}
2017-02-25 21:36:44 -05:00
if ( newHeading === user . currentHeading || ( ( newHeading % 2 === 0 ) ^
( user . currentHeading % 2 === 0 ) ) )
2017-02-23 23:10:36 -05:00
{
2017-02-25 21:36:44 -05:00
user . heading = newHeading ;
if ( socket )
socket . emit ( "frame" , {
frame : frame ,
heading : newHeading
} , function ( success , msg ) {
if ( ! success )
{
//TODO: restore frames.
console . error ( msg ) ;
}
} ) ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 21:36:44 -05:00
e . preventDefault ( ) ;
} ) ;
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
$ ( function ( ) {
var grid = renderer . grid ;
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
//Socket connection.
2017-02-25 23:25:06 -05:00
socket = require ( 'socket.io-client' ) ( 'localhost:8081' ) ;
2017-02-25 21:36:44 -05:00
socket . on ( 'connect' , function ( ) {
console . info ( "Connected to server." ) ;
socket . emit ( 'hello' , {
name : 'Test player' ,
type : 0 , //Free-for-all
gameid : - 1 //Requested game-id, or -1 for anyone.
} , function ( success ) {
if ( success ) console . info ( "Connected to game!" ) ;
else console . error ( "Unable to connect to game." ) ;
} ) ;
} ) ;
2017-02-25 23:25:06 -05:00
socket . on ( 'game' , function ( data ) {
2017-02-25 21:36:44 -05:00
//Initialize game.
//TODO: display data.gameid --- game id #
2017-02-26 02:31:30 -05:00
frame = data . frame ;
renderer . reset ( ) ;
//Load players.
data . players . forEach ( function ( p ) {
var pl = new Player ( true , grid , p ) ;
renderer . addPlayer ( pl ) ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-26 02:31:30 -05:00
user = renderer . getPlayerFromNum ( data . num ) ;
renderer . setUser ( user ) ;
//Load grid.
var gridData = new Uint8Array ( data . grid ) ;
for ( var r = 0 ; r < grid . size ; r ++ )
for ( var c = 0 ; c < grid . size ; c ++ )
{
var ind = gridData [ r * grid . size + c ] - 1 ;
grid . set ( r , c , ind === - 1 ? null : renderer . getPlayer ( ind ) ) ;
}
paintLoop ( ) ;
frame = data . frame ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-23 23:10:36 -05:00
2017-02-25 23:25:06 -05:00
socket . on ( 'notifyFrame' , function ( data , fn ) {
2017-02-25 21:36:44 -05:00
if ( data . frame - 1 !== frame )
{
console . error ( "Frames don't match up!" ) ;
socket . emit ( 'requestFrame' ) ; //Restore data.
return ;
}
frame ++ ;
2017-02-25 23:25:06 -05:00
requestAnimationFrame ( function ( ) {
if ( data . newPlayers )
{
data . newPlayers . forEach ( function ( p ) {
2017-02-26 02:31:30 -05:00
if ( p . num === user . num )
return ;
var pl = new Player ( true , grid , p ) ;
renderer . addPlayer ( pl ) ;
core . initPlayer ( grid , pl ) ;
2017-02-25 23:25:06 -05:00
} ) ;
}
data . moves . forEach ( function ( val , i ) {
2017-02-26 02:31:30 -05:00
renderer . getPlayer ( i ) . heading = val . heading ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-25 23:25:06 -05:00
paintLoop ( ) ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-25 23:25:06 -05:00
fn ( ) ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-25 18:52:52 -05:00
2017-02-25 21:36:44 -05:00
socket . on ( 'disconnect' , function ( ) {
console . info ( "Server has disconnected. Creating new game." ) ;
2017-02-26 02:31:30 -05:00
socket . disconnect ( ) ;
user . die ( ) ;
paintLoop ( ) ;
2017-02-25 21:36:44 -05:00
} ) ;
2017-02-25 18:52:52 -05:00
2017-02-25 21:36:44 -05:00
var deadFrames = 0 ;
function paintLoop ( )
{
renderer . paint ( ) ;
renderer . update ( ) ;
if ( user . dead )
2017-02-23 23:10:36 -05:00
{
2017-02-25 23:25:06 -05:00
if ( deadFrames === 60 ) //One second of frames
{
deadFrames = 0 ;
return ;
}
2017-02-25 21:36:44 -05:00
socket . disconnect ( ) ;
deadFrames ++ ;
requestAnimationFrame ( paintLoop ) ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 21:36:44 -05:00
}
} ) ;
2017-02-26 02:31:30 -05:00
} , { "./game-consts.js" : 3 , "./game-core.js" : 4 , "./game-renderer.js" : 5 , "./player.js" : 56 , "socket.io-client" : 42 } ] , 3 : [ function ( require , module , exports ) {
2017-02-25 18:52:52 -05:00
function constant ( val )
{
return {
value : val ,
enumerable : true
} ;
}
var consts = {
GRID _SIZE : constant ( 80 ) ,
CELL _WIDTH : constant ( 40 ) ,
SPEED : constant ( 5 ) ,
2017-02-25 21:36:44 -05:00
BORDER _WIDTH : constant ( 20 ) ,
MAX _PLAYERS : constant ( 255 )
2017-02-25 18:52:52 -05:00
} ;
Object . defineProperties ( module . exports , consts ) ;
2017-02-25 23:25:06 -05:00
} , { } ] , 4 : [ function ( require , module , exports ) {
2017-02-25 18:52:52 -05:00
var ANIMATE _FRAMES = 24 ;
var CELL _WIDTH = 40 ;
exports . initPlayer = function ( grid , player )
{
for ( var dr = - 1 ; dr <= 1 ; dr ++ )
for ( var dc = - 1 ; dc <= 1 ; dc ++ )
if ( ! grid . isOutOfBounds ( dr + player . row , dc + player . col ) )
grid . set ( dr + player . row , dc + player . col , player ) ;
} ;
exports . updateFrame = function ( grid , players , newPlayerFrames , dead , notifyKill )
{
var adead = [ ] ;
if ( dead instanceof Array )
2017-02-26 02:31:30 -05:00
adead = dead ;
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
var kill ;
if ( ! notifyKill )
kill = function ( ) { } ;
else
kill = function ( killer , other ) { if ( ! removing [ other ] ) notifyKill ( killer , other ) ; } ;
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
//Move players.
var tmp = players . filter ( function ( val ) {
if ( ! newPlayerFrames [ val . num ] )
newPlayerFrames [ val . num ] = 0 ;
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
if ( newPlayerFrames [ val . num ] < ANIMATE _FRAMES )
newPlayerFrames [ val . num ] ++ ;
else
val . move ( ) ;
2017-02-26 02:31:30 -05:00
2017-02-25 18:52:52 -05:00
if ( val . dead )
adead . push ( val ) ;
return ! val . dead ;
} ) ;
//Remove players with collisions.
var removing = new Array ( players . length ) ;
for ( var i = 0 ; i < players . length ; i ++ )
{
for ( var j = i ; j < players . length ; j ++ )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
//Remove those players when other players have hit their tail.
if ( ! removing [ j ] && players [ j ] . tail . hitsTail ( players [ i ] ) )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
kill ( i , j ) ;
removing [ j ] = true ;
}
if ( ! removing [ i ] && players [ i ] . tail . hitsTail ( players [ j ] ) )
{
kill ( j , i ) ;
removing [ i ] = true ;
}
//Remove players with collisons...
if ( i !== j && squaresIntersect ( players [ i ] . posX , players [ j ] . posX ) &&
squaresIntersect ( players [ i ] . posY , players [ j ] . posY ) )
{
//...if one player is own his own territory, the other is out.
if ( grid . get ( players [ i ] . row , players [ i ] . col ) === players [ i ] )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
kill ( i , j ) ;
removing [ j ] = true ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 18:52:52 -05:00
else if ( grid . get ( players [ j ] . row , players [ j ] . col ) === players [ j ] )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
kill ( j , i ) ;
removing [ i ] = true ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 18:52:52 -05:00
else
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
//...otherwise, the one that sustains most of the collision will be removed.
var areaI = area ( players [ i ] ) ;
var areaJ = area ( players [ j ] ) ;
if ( areaI === areaJ )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
kill ( i , j ) ;
kill ( j , i ) ;
removing [ i ] = removing [ j ] = true ;
}
else if ( areaI > areaJ )
{
kill ( j , i ) ;
removing [ i ] = true ;
}
else
{
kill ( i , j ) ;
removing [ j ] = true ;
2017-02-23 23:10:36 -05:00
}
}
}
}
}
2017-02-25 18:52:52 -05:00
tmp = tmp . filter ( function ( val , i ) {
if ( removing [ i ] )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
adead . push ( val ) ;
val . die ( ) ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 18:52:52 -05:00
return ! removing [ i ] ;
} ) ;
players . length = tmp . length ;
for ( var i = 0 ; i < tmp . length ; i ++ )
players [ i ] = tmp [ i ] ;
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
//Remove dead squares.
for ( var r = 0 ; r < grid . size ; r ++ )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
for ( var c = 0 ; c < grid . size ; c ++ )
2017-02-23 23:10:36 -05:00
{
2017-02-25 18:52:52 -05:00
if ( adead . indexOf ( grid . get ( r , c ) ) !== - 1 )
grid . set ( r , c , null ) ;
2017-02-23 23:10:36 -05:00
}
}
2017-02-25 18:52:52 -05:00
} ;
function squaresIntersect ( a , b )
{
if ( a < b )
return b < a + CELL _WIDTH ;
else
return a < b + CELL _WIDTH ;
}
function area ( player )
{
var xDest = player . col * CELL _WIDTH ;
var yDest = player . row * CELL _WIDTH ;
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
if ( player . posX === xDest )
return Math . abs ( player . posY - yDest ) ;
else
return Math . abs ( player . posX - xDest ) ;
}
2017-02-25 23:25:06 -05:00
} , { } ] , 5 : [ function ( require , module , exports ) {
2017-02-25 18:52:52 -05:00
/* global $ */
var Color = require ( "./color.js" ) ;
var Grid = require ( "./grid.js" ) ;
var consts = require ( "./game-consts.js" ) ;
var core = require ( "./game-core.js" ) ;
var GRID _SIZE = consts . GRID _SIZE ;
var CELL _WIDTH = consts . CELL _WIDTH ;
var SPEED = consts . SPEED ;
var BORDER _WIDTH = consts . BORDER _WIDTH ;
var SHADOW _OFFSET = 5 ;
var ANIMATE _FRAMES = 24 ;
var BOUNCE _FRAMES = [ 8 , 4 ] ;
var DROP _HEIGHT = 24 ;
var DROP _SPEED = 2 ;
var MIN _BAR _WIDTH = 65 ;
var BAR _HEIGHT = SHADOW _OFFSET + CELL _WIDTH ;
var BAR _WIDTH = 400 ;
var canvasWidth , canvasHeight , gameWidth , gameHeight , ctx , offctx , offscreenCanvas ;
$ ( function ( ) {
var canvas = $ ( "#main-ui" ) [ 0 ] ;
ctx = canvas . getContext ( '2d' ) ;
offscreenCanvas = document . createElement ( "canvas" ) ;
offctx = offscreenCanvas . getContext ( '2d' ) ;
canvasWidth = offscreenCanvas . width = canvas . width = window . innerWidth ;
canvasHeight = offscreenCanvas . height = canvas . height = window . innerHeight - 20 ;
canvas . style . marginTop = 20 / 2 ;
gameWidth = canvasWidth ;
gameHeight = canvasHeight - BAR _HEIGHT ;
} ) ;
2017-02-25 21:36:44 -05:00
2017-02-25 18:52:52 -05:00
var allowAnimation = true ;
2017-02-25 21:36:44 -05:00
var animateGrid , players , allPlayers , newPlayerFrames , playerPortion , grid ,
animateTo , offset , user , lagPortion , portionSpeed , zoom , kills , showedDead ;
grid = new Grid ( GRID _SIZE , function ( row , col , before , after ) {
2017-02-25 18:52:52 -05:00
//Keep track of areas.
if ( before )
playerPortion [ before . num ] -- ;
if ( after )
playerPortion [ after . num ] ++ ;
//Queue animation
if ( before === after || ! allowAnimation )
return ;
animateGrid . set ( row , col , {
before : before ,
after : after ,
frame : 0
} ) ;
} ) ;
2017-02-25 21:36:44 -05:00
function init ( ) {
animateGrid = new Grid ( GRID _SIZE ) ;
grid . reset ( ) ;
players = [ ] ;
allPlayers = [ ] ;
newPlayerFrames = [ ] ;
playerPortion = [ ] ;
animateTo = [ 0 , 0 ] ;
offset = [ 0 , 0 ] ;
user = null ;
lagPortion = 0 ;
portionSpeed = 0 ;
zoom = 1 ;
kills = 0 ;
showedDead = false ;
}
2017-02-25 18:52:52 -05:00
2017-02-25 21:36:44 -05:00
init ( ) ;
2017-02-25 18:52:52 -05:00
//Paint methods.
function paintGridBorder ( ctx )
{
ctx . fillStyle = 'lightgray' ;
var gridWidth = CELL _WIDTH * GRID _SIZE ;
ctx . fillRect ( - BORDER _WIDTH , 0 , BORDER _WIDTH , gridWidth ) ;
ctx . fillRect ( - BORDER _WIDTH , - BORDER _WIDTH , gridWidth + BORDER _WIDTH * 2 , BORDER _WIDTH ) ;
ctx . fillRect ( gridWidth , 0 , BORDER _WIDTH , gridWidth ) ;
ctx . fillRect ( - BORDER _WIDTH , gridWidth , gridWidth + BORDER _WIDTH * 2 , BORDER _WIDTH ) ;
}
2017-02-23 23:10:36 -05:00
2017-02-25 18:52:52 -05:00
function paintGridLines ( ctx )
{
ctx . fillStyle = 'lightgray' ;
ctx . beginPath ( ) ;
for ( var x = modRotate ( - offset [ 0 ] , CELL _WIDTH ) ; x < gameWidth ; x += CELL _WIDTH )
{
ctx . moveTo ( x , 0 ) ;
ctx . lineTo ( x , gameHeight ) ;
}
for ( var y = modRotate ( - offset [ 1 ] , CELL _WIDTH ) ; y < gameHeight ; y += CELL _WIDTH )
{
ctx . moveTo ( 0 , y ) ;
ctx . lineTo ( gameWidth , y ) ;
}
ctx . stroke ( ) ;
}
function paintGrid ( ctx )
{
//Paint background.
ctx . fillStyle = "#e2ebf3" ;
ctx . fillRect ( 0 , 0 , CELL _WIDTH * GRID _SIZE , CELL _WIDTH * GRID _SIZE ) ;
paintGridBorder ( ctx ) ;
//paintGridLines(ctx);
//Get viewing limits
var offsetX = ( offset [ 0 ] - BORDER _WIDTH ) ;
var offsetY = ( offset [ 1 ] - BORDER _WIDTH ) ;
var minRow = Math . max ( Math . floor ( offsetY / CELL _WIDTH ) , 0 ) ;
var minCol = Math . max ( Math . floor ( offsetX / CELL _WIDTH ) , 0 ) ;
var maxRow = Math . min ( Math . ceil ( ( offsetY + gameHeight / zoom ) / CELL _WIDTH ) , grid . size ) ;
var maxCol = Math . min ( Math . ceil ( ( offsetX + gameWidth / zoom ) / CELL _WIDTH ) , grid . size ) ;
//Paint occupied areas. (and fading ones).
for ( var r = minRow ; r < maxRow ; r ++ )
{
for ( var c = minCol ; c < maxCol ; c ++ )
{
var p = grid . get ( r , c ) ;
var x = c * CELL _WIDTH , y = r * CELL _WIDTH , baseColor , shadowColor ;
var animateSpec = animateGrid . get ( r , c ) ;
if ( allowAnimation && animateSpec )
{
if ( animateSpec . before ) //fading animation
{
var frac = ( animateSpec . frame / ANIMATE _FRAMES ) ;
var back = new Color ( . 58 , . 41 , . 92 , 1 ) ;
baseColor = animateSpec . before . baseColor . interpolateToString ( back , frac ) ;
shadowColor = animateSpec . before . shadowColor . interpolateToString ( back , frac ) ;
}
else
continue ;
}
else if ( p )
{
baseColor = p . baseColor ;
shadowColor = p . shadowColor ;
}
else //No animation nor is this player owned.
continue ;
var hasBottom = ! grid . isOutOfBounds ( r + 1 , c ) ;
var bottomAnimate = hasBottom && animateGrid . get ( r + 1 , c ) ;
var totalStatic = ! bottomAnimate && ! animateSpec ;
var bottomEmpty = totalStatic ? ( hasBottom && ! grid . get ( r + 1 , c ) ) :
( ! bottomAnimate || ( bottomAnimate . after && bottomAnimate . before ) ) ;
if ( hasBottom && ( ( ! ! bottomAnimate ^ ! ! animateSpec ) || bottomEmpty ) )
{
ctx . fillStyle = shadowColor . rgbString ( ) ;
ctx . fillRect ( x , y + CELL _WIDTH , CELL _WIDTH + 1 , SHADOW _OFFSET ) ;
}
ctx . fillStyle = baseColor . rgbString ( ) ;
ctx . fillRect ( x , y , CELL _WIDTH + 1 , CELL _WIDTH + 1 ) ;
}
}
if ( ! allowAnimation )
return ;
//Paint squares with drop in animation.
for ( var r = 0 ; r < grid . size ; r ++ )
{
for ( var c = 0 ; c < grid . size ; c ++ )
{
animateSpec = animateGrid . get ( r , c ) ;
x = c * CELL _WIDTH , y = r * CELL _WIDTH ;
if ( animateSpec && allowAnimation )
{
var viewable = r >= minRow && r < maxRow && c >= minCol && c < maxCol ;
if ( animateSpec . after && viewable )
{
//Bouncing the squares.
var offsetBounce = getBounceOffset ( animateSpec . frame ) ;
y -= offsetBounce ;
shadowColor = animateSpec . after . shadowColor ;
baseColor = animateSpec . after . baseColor . deriveLumination ( - ( offsetBounce / DROP _HEIGHT ) * . 1 ) ;
ctx . fillStyle = shadowColor . rgbString ( ) ;
ctx . fillRect ( x , y + CELL _WIDTH , CELL _WIDTH , SHADOW _OFFSET ) ;
ctx . fillStyle = baseColor . rgbString ( ) ;
ctx . fillRect ( x , y , CELL _WIDTH + 1 , CELL _WIDTH + 1 ) ;
}
animateSpec . frame ++ ;
if ( animateSpec . frame >= ANIMATE _FRAMES )
animateGrid . set ( r , c , null ) ;
}
}
}
}
function paintUIBar ( ctx )
{
//UI Bar background
ctx . fillStyle = "#24422c" ;
ctx . fillRect ( 0 , 0 , canvasWidth , BAR _HEIGHT ) ;
var barOffset ;
ctx . fillStyle = "white" ;
ctx . font = "24px Changa" ;
2017-02-25 21:36:44 -05:00
barOffset = ctx . measureText ( user ? user . name : "" ) . width + 20 ;
ctx . fillText ( user ? user . name : "" , 5 , CELL _WIDTH - 5 ) ;
2017-02-25 18:52:52 -05:00
//Draw filled bar.
ctx . fillStyle = "rgba(180, 180, 180, .3)" ;
ctx . fillRect ( barOffset , 0 , BAR _WIDTH , BAR _HEIGHT ) ;
var barSize = Math . ceil ( ( BAR _WIDTH - MIN _BAR _WIDTH ) * lagPortion + MIN _BAR _WIDTH ) ;
2017-02-25 21:36:44 -05:00
ctx . fillStyle = user ? user . baseColor . rgbString ( ) : "" ;
2017-02-25 18:52:52 -05:00
ctx . fillRect ( barOffset , 0 , barSize , CELL _WIDTH ) ;
2017-02-25 21:36:44 -05:00
ctx . fillStyle = user ? user . shadowColor . rgbString ( ) : "" ;
2017-02-25 18:52:52 -05:00
ctx . fillRect ( barOffset , CELL _WIDTH , barSize , SHADOW _OFFSET ) ;
//Percentage
ctx . fillStyle = "white" ;
ctx . font = "18px Changa" ;
ctx . fillText ( ( lagPortion * 100 ) . toFixed ( 3 ) + "%" , 5 + barOffset , CELL _WIDTH - 5 ) ;
//Number of kills
var killsText = "Kills: " + kills ;
var killsOffset = 20 + BAR _WIDTH + barOffset ;
ctx . fillText ( killsText , killsOffset , CELL _WIDTH - 5 ) ;
//Calcuate rank
var sorted = [ ] ;
players . forEach ( function ( val ) {
sorted . push ( { player : val , portion : playerPortion [ val . num ] } ) ;
} ) ;
sorted . sort ( function ( a , b ) {
if ( a . portion === b . portion ) return a . player . num - b . player . num ;
else return b . portion - a . portion ;
} ) ;
var rank = sorted . findIndex ( function ( val ) { return val . player === user } ) ;
ctx . fillText ( "Rank: " + ( rank === - 1 ? "--" : rank + 1 ) + " of " + sorted . length ,
ctx . measureText ( killsText ) . width + killsOffset + 20 , CELL _WIDTH - 5 ) ;
}
function paint ( ctx )
{
ctx . fillStyle = 'whitesmoke' ;
ctx . fillRect ( 0 , 0 , canvasWidth , canvasHeight ) ;
//Move grid to viewport as said with the offsets, below the stats
ctx . save ( ) ;
ctx . translate ( 0 , BAR _HEIGHT ) ;
ctx . beginPath ( ) ;
ctx . rect ( 0 , 0 , gameWidth , gameHeight ) ;
ctx . clip ( ) ;
//Zoom in/out based on player stats.
ctx . scale ( zoom , zoom ) ;
ctx . translate ( - offset [ 0 ] + BORDER _WIDTH , - offset [ 1 ] + BORDER _WIDTH ) ;
paintGrid ( ctx ) ;
players . forEach ( function ( p ) {
var fr = newPlayerFrames [ p . num ] || 0 ;
if ( fr < ANIMATE _FRAMES )
p . render ( ctx , fr / ANIMATE _FRAMES ) ;
else
p . render ( ctx ) ;
} ) ;
//Reset transform to paint fixed UI elements
ctx . restore ( ) ;
paintUIBar ( ctx ) ;
2017-02-25 21:36:44 -05:00
if ( ( ! user || user . dead ) && ! showedDead )
2017-02-25 18:52:52 -05:00
{
showedDead = true ;
console . log ( "You died!" ) ;
//return;
}
}
function paintDoubleBuff ( )
{
2017-02-26 02:31:30 -05:00
paint ( ctx ) ;
//paint(offctx);
//ctx.drawImage(offscreenCanvas, 0, 0);
2017-02-25 18:52:52 -05:00
}
function update ( ) {
//Change grid offsets.
for ( var i = 0 ; i <= 1 ; i ++ )
{
if ( animateTo [ i ] !== offset [ i ] )
{
var delta = animateTo [ i ] - offset [ i ] ;
var dir = Math . sign ( delta ) ;
var mag = Math . min ( SPEED , Math . abs ( delta ) ) ;
offset [ i ] += dir * mag ;
}
}
//Change area percentage
2017-02-25 21:36:44 -05:00
var userPortion ;
if ( user ) userPortion = playerPortion [ user . num ] / ( GRID _SIZE * GRID _SIZE ) ;
else userPortion = 0 ;
2017-02-25 18:52:52 -05:00
if ( lagPortion !== userPortion )
{
delta = userPortion - lagPortion ;
dir = Math . sign ( delta ) ;
mag = Math . min ( Math . abs ( portionSpeed ) , Math . abs ( delta ) ) ;
lagPortion += dir * mag ;
}
//Zoom goes from 1 to .5, decreasing as portion goes up. TODO: maybe can modify this?
zoom = 1 / ( lagPortion + 1 ) ;
//Update user's portions and top ranks.
portionSpeed = Math . abs ( userPortion - lagPortion ) / ANIMATE _FRAMES ;
var dead = [ ] ;
core . updateFrame ( grid , players , newPlayerFrames , dead , function addKill ( killer , other )
{
if ( players [ killer ] === user && killer !== other )
kills ++ ;
} ) ;
dead . forEach ( function ( val ) {
console . log ( val . name + " is dead" ) ;
allPlayers [ val . num ] = undefined ;
} ) ;
2017-02-25 21:36:44 -05:00
2017-02-25 18:52:52 -05:00
//TODO: animate player is dead. (maybe explosion?), and tail rewinds itself.
//TODO: show when this player is dead
2017-02-25 21:36:44 -05:00
if ( user ) centerOnPlayer ( user , animateTo ) ;
2017-02-25 18:52:52 -05:00
}
//Helper methods.
function modRotate ( val , mod )
{
var res = val % mod ;
if ( res >= 0 )
return res ;
else
return mod + res ;
}
function centerOnPlayer ( player , pos )
{
var xOff = Math . floor ( player . posX - ( gameWidth / zoom - CELL _WIDTH ) / 2 ) ;
var yOff = Math . floor ( player . posY - ( gameHeight / zoom - CELL _WIDTH ) / 2 ) ;
pos [ 0 ] = Math . max ( Math . min ( xOff , grid . size * CELL _WIDTH + BORDER _WIDTH * 2 - gameWidth / zoom ) , 0 ) ;
pos [ 1 ] = Math . max ( Math . min ( yOff , grid . size * CELL _WIDTH + BORDER _WIDTH * 2 - gameHeight / zoom ) , 0 ) ;
}
function getBounceOffset ( frame )
{
var offsetBounce = ANIMATE _FRAMES ;
var bounceNum = BOUNCE _FRAMES . length - 1 ;
while ( bounceNum >= 0 && frame < offsetBounce - BOUNCE _FRAMES [ bounceNum ] )
{
offsetBounce -= BOUNCE _FRAMES [ bounceNum ] ;
bounceNum -- ;
}
if ( bounceNum === - 1 )
{
return ( offsetBounce - frame ) * DROP _SPEED ;
}
else
{
offsetBounce -= BOUNCE _FRAMES [ bounceNum ] ;
frame = frame - offsetBounce ;
var midFrame = BOUNCE _FRAMES [ bounceNum ] / 2 ;
if ( frame >= midFrame )
return ( BOUNCE _FRAMES [ bounceNum ] - frame ) * DROP _SPEED ;
else
return frame * DROP _SPEED ;
}
}
module . exports = exports = {
addPlayer : function ( player ) {
2017-02-25 21:36:44 -05:00
if ( allPlayers [ player . num ] )
return ; //Already added.
2017-02-25 18:52:52 -05:00
allPlayers [ player . num ] = players [ players . length ] = player ;
newPlayerFrames [ player . num ] = 0 ;
playerPortion [ player . num ] = 0 ;
return players . length - 1 ;
} ,
getPlayer : function ( ind ) {
return players [ ind ] ;
} ,
2017-02-25 21:36:44 -05:00
getPlayerFromNum : function ( num ) {
return allPlayers [ num ] ;
} ,
playerSize : function ( ) {
2017-02-25 18:52:52 -05:00
return players . length ;
} ,
2017-02-25 21:36:44 -05:00
setUser : function ( player ) {
2017-02-25 18:52:52 -05:00
user = player ;
centerOnPlayer ( user , offset ) ;
} ,
incrementKill : function ( ) {
kills ++ ;
} ,
2017-02-25 21:36:44 -05:00
reset : function ( ) {
init ( ) ;
} ,
2017-02-25 18:52:52 -05:00
paint : paintDoubleBuff ,
update : update
} ;
Object . defineProperties ( exports , {
allowAnimation : {
get : function ( ) { return allowAnimation ; } ,
set : function ( val ) { allowAnimation = ! ! val ; } ,
enumerable : true
} ,
grid : {
get : function ( ) { return grid ; } ,
enumerable : true
}
} ) ;
2017-02-25 23:25:06 -05:00
} , { "./color.js" : 1 , "./game-consts.js" : 3 , "./game-core.js" : 4 , "./grid.js" : 6 } ] , 6 : [ function ( require , module , exports ) {
2017-02-23 23:10:36 -05:00
function Grid ( size , changeCallback )
{
var grid = new Array ( size ) ;
2017-02-25 21:36:44 -05:00
var modified = false ;
2017-02-23 23:10:36 -05:00
var data = {
grid : grid ,
size : size
} ;
this . get = function ( row , col )
{
if ( isOutOfBounds ( data , row , col ) )
throw new RangeError ( "Row or Column value out of bounds" ) ;
return grid [ row ] && grid [ row ] [ col ] ;
}
this . set = function ( row , col , value )
{
if ( isOutOfBounds ( data , row , col ) )
throw new RangeError ( "Row or Column value out of bounds" ) ;
if ( ! grid [ row ] )
grid [ row ] = new Array ( size ) ;
var before = grid [ row ] [ col ] ;
grid [ row ] [ col ] = value ;
if ( typeof changeCallback === "function" )
changeCallback ( row , col , before , value ) ;
2017-02-25 21:36:44 -05:00
modified = true ;
2017-02-23 23:10:36 -05:00
return before ;
}
2017-02-25 21:36:44 -05:00
this . reset = function ( ) {
if ( modified )
{
grid = new Array ( size ) ;
modified = false ;
}
}
2017-02-23 23:10:36 -05:00
this . isOutOfBounds = isOutOfBounds . bind ( this , data ) ;
Object . defineProperty ( this , "size" , {
get : function ( ) { return size ; } ,
enumerable : true
} ) ;
}
function isOutOfBounds ( data , row , col )
{
return row < 0 || row >= data . size || col < 0 || col >= data . size ;
}
module . exports = Grid ;
2017-02-25 23:25:06 -05:00
} , { } ] , 7 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = after
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
function after ( count , callback , err _cb ) {
var bail = false
err _cb = err _cb || noop
proxy . count = count
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
return ( count === 0 ) ? callback ( ) : proxy
2017-02-23 23:10:36 -05:00
2017-02-25 21:36:44 -05:00
function proxy ( err , result ) {
if ( proxy . count <= 0 ) {
throw new Error ( 'after called too many times' )
}
-- proxy . count
// after first error, rest are passed to err_cb
if ( err ) {
bail = true
callback ( err )
// future error callbacks will go to error handler
callback = err _cb
} else if ( proxy . count === 0 && ! bail ) {
callback ( null , result )
}
}
2017-02-23 23:10:36 -05:00
}
2017-02-25 21:36:44 -05:00
function noop ( ) { }
2017-02-23 23:10:36 -05:00
2017-02-25 23:25:06 -05:00
} , { } ] , 8 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* An abstraction for slicing an arraybuffer even when
* ArrayBuffer . prototype . slice is not supported
*
* @ api public
* /
module . exports = function ( arraybuffer , start , end ) {
var bytes = arraybuffer . byteLength ;
start = start || 0 ;
end = end || bytes ;
if ( arraybuffer . slice ) { return arraybuffer . slice ( start , end ) ; }
if ( start < 0 ) { start += bytes ; }
if ( end < 0 ) { end += bytes ; }
if ( end > bytes ) { end = bytes ; }
if ( start >= bytes || start >= end || bytes === 0 ) {
return new ArrayBuffer ( 0 ) ;
}
var abv = new Uint8Array ( arraybuffer ) ;
var result = new Uint8Array ( end - start ) ;
for ( var i = start , ii = 0 ; i < end ; i ++ , ii ++ ) {
result [ ii ] = abv [ i ] ;
}
return result . buffer ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 9 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Expose ` Backoff ` .
* /
module . exports = Backoff ;
/ * *
* Initialize backoff timer with ` opts ` .
*
* - ` min ` initial timeout in milliseconds [ 100 ]
* - ` max ` max timeout [ 10000 ]
* - ` jitter ` [ 0 ]
* - ` factor ` [ 2 ]
*
* @ param { Object } opts
* @ api public
* /
function Backoff ( opts ) {
opts = opts || { } ;
this . ms = opts . min || 100 ;
this . max = opts . max || 10000 ;
this . factor = opts . factor || 2 ;
this . jitter = opts . jitter > 0 && opts . jitter <= 1 ? opts . jitter : 0 ;
this . attempts = 0 ;
2017-02-23 23:10:36 -05:00
}
2017-02-25 21:36:44 -05:00
/ * *
* Return the backoff duration .
*
* @ return { Number }
* @ api public
* /
Backoff . prototype . duration = function ( ) {
var ms = this . ms * Math . pow ( this . factor , this . attempts ++ ) ;
if ( this . jitter ) {
var rand = Math . random ( ) ;
var deviation = Math . floor ( rand * this . jitter * ms ) ;
ms = ( Math . floor ( rand * 10 ) & 1 ) == 0 ? ms - deviation : ms + deviation ;
}
return Math . min ( ms , this . max ) | 0 ;
} ;
/ * *
* Reset the number of attempts .
*
* @ api public
* /
Backoff . prototype . reset = function ( ) {
this . attempts = 0 ;
} ;
/ * *
* Set the minimum duration
*
* @ api public
* /
Backoff . prototype . setMin = function ( min ) {
this . ms = min ;
} ;
/ * *
* Set the maximum duration
*
* @ api public
* /
Backoff . prototype . setMax = function ( max ) {
this . max = max ;
} ;
/ * *
* Set the jitter
*
* @ api public
* /
Backoff . prototype . setJitter = function ( jitter ) {
this . jitter = jitter ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 10 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ *
* base64 - arraybuffer
* https : //github.com/niklasvh/base64-arraybuffer
*
* Copyright ( c ) 2012 Niklas von Hertzen
* Licensed under the MIT license .
* /
( function ( ) {
"use strict" ;
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
// Use a lookup table to find the index.
var lookup = new Uint8Array ( 256 ) ;
for ( var i = 0 ; i < chars . length ; i ++ ) {
lookup [ chars . charCodeAt ( i ) ] = i ;
}
exports . encode = function ( arraybuffer ) {
var bytes = new Uint8Array ( arraybuffer ) ,
i , len = bytes . length , base64 = "" ;
for ( i = 0 ; i < len ; i += 3 ) {
base64 += chars [ bytes [ i ] >> 2 ] ;
base64 += chars [ ( ( bytes [ i ] & 3 ) << 4 ) | ( bytes [ i + 1 ] >> 4 ) ] ;
base64 += chars [ ( ( bytes [ i + 1 ] & 15 ) << 2 ) | ( bytes [ i + 2 ] >> 6 ) ] ;
base64 += chars [ bytes [ i + 2 ] & 63 ] ;
}
if ( ( len % 3 ) === 2 ) {
base64 = base64 . substring ( 0 , base64 . length - 1 ) + "=" ;
} else if ( len % 3 === 1 ) {
base64 = base64 . substring ( 0 , base64 . length - 2 ) + "==" ;
}
return base64 ;
2017-02-23 23:10:36 -05:00
} ;
2017-02-25 21:36:44 -05:00
exports . decode = function ( base64 ) {
var bufferLength = base64 . length * 0.75 ,
len = base64 . length , i , p = 0 ,
encoded1 , encoded2 , encoded3 , encoded4 ;
if ( base64 [ base64 . length - 1 ] === "=" ) {
bufferLength -- ;
if ( base64 [ base64 . length - 2 ] === "=" ) {
bufferLength -- ;
}
}
var arraybuffer = new ArrayBuffer ( bufferLength ) ,
bytes = new Uint8Array ( arraybuffer ) ;
for ( i = 0 ; i < len ; i += 4 ) {
encoded1 = lookup [ base64 . charCodeAt ( i ) ] ;
encoded2 = lookup [ base64 . charCodeAt ( i + 1 ) ] ;
encoded3 = lookup [ base64 . charCodeAt ( i + 2 ) ] ;
encoded4 = lookup [ base64 . charCodeAt ( i + 3 ) ] ;
bytes [ p ++ ] = ( encoded1 << 2 ) | ( encoded2 >> 4 ) ;
bytes [ p ++ ] = ( ( encoded2 & 15 ) << 4 ) | ( encoded3 >> 2 ) ;
bytes [ p ++ ] = ( ( encoded3 & 3 ) << 6 ) | ( encoded4 & 63 ) ;
}
return arraybuffer ;
} ;
} ) ( ) ;
2017-02-25 23:25:06 -05:00
} , { } ] , 11 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Create a blob builder even when vendor prefixes exist
* /
var BlobBuilder = global . BlobBuilder
|| global . WebKitBlobBuilder
|| global . MSBlobBuilder
|| global . MozBlobBuilder ;
/ * *
* Check if Blob constructor is supported
* /
var blobSupported = ( function ( ) {
try {
var a = new Blob ( [ 'hi' ] ) ;
return a . size === 2 ;
} catch ( e ) {
return false ;
}
} ) ( ) ;
/ * *
* Check if Blob constructor supports ArrayBufferViews
* Fails in Safari 6 , so we need to map to ArrayBuffers there .
* /
var blobSupportsArrayBufferView = blobSupported && ( function ( ) {
try {
var b = new Blob ( [ new Uint8Array ( [ 1 , 2 ] ) ] ) ;
return b . size === 2 ;
} catch ( e ) {
return false ;
}
} ) ( ) ;
/ * *
* Check if BlobBuilder is supported
* /
var blobBuilderSupported = BlobBuilder
&& BlobBuilder . prototype . append
&& BlobBuilder . prototype . getBlob ;
/ * *
* Helper function that maps ArrayBufferViews to ArrayBuffers
* Used by BlobBuilder constructor and old browsers that didn ' t
* support it in the Blob constructor .
* /
function mapArrayBufferViews ( ary ) {
for ( var i = 0 ; i < ary . length ; i ++ ) {
var chunk = ary [ i ] ;
if ( chunk . buffer instanceof ArrayBuffer ) {
var buf = chunk . buffer ;
// if this is a subarray, make a copy so we only
// include the subarray region from the underlying buffer
if ( chunk . byteLength !== buf . byteLength ) {
var copy = new Uint8Array ( chunk . byteLength ) ;
copy . set ( new Uint8Array ( buf , chunk . byteOffset , chunk . byteLength ) ) ;
buf = copy . buffer ;
}
ary [ i ] = buf ;
}
2017-02-23 23:10:36 -05:00
}
}
2017-02-25 21:36:44 -05:00
function BlobBuilderConstructor ( ary , options ) {
options = options || { } ;
var bb = new BlobBuilder ( ) ;
mapArrayBufferViews ( ary ) ;
for ( var i = 0 ; i < ary . length ; i ++ ) {
bb . append ( ary [ i ] ) ;
}
return ( options . type ) ? bb . getBlob ( options . type ) : bb . getBlob ( ) ;
} ;
function BlobConstructor ( ary , options ) {
mapArrayBufferViews ( ary ) ;
return new Blob ( ary , options || { } ) ;
} ;
module . exports = ( function ( ) {
if ( blobSupported ) {
return blobSupportsArrayBufferView ? global . Blob : BlobConstructor ;
} else if ( blobBuilderSupported ) {
return BlobBuilderConstructor ;
} else {
return undefined ;
}
} ) ( ) ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { } ] , 12 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Slice reference .
* /
var slice = [ ] . slice ;
/ * *
* Bind ` obj ` to ` fn ` .
*
* @ param { Object } obj
* @ param { Function | String } fn or string
* @ return { Function }
* @ api public
* /
module . exports = function ( obj , fn ) {
if ( 'string' == typeof fn ) fn = obj [ fn ] ;
if ( 'function' != typeof fn ) throw new Error ( 'bind() requires a function' ) ;
var args = slice . call ( arguments , 2 ) ;
return function ( ) {
return fn . apply ( obj , args . concat ( slice . call ( arguments ) ) ) ;
}
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 13 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Expose ` Emitter ` .
* /
module . exports = Emitter ;
/ * *
* Initialize a new ` Emitter ` .
*
* @ api public
* /
function Emitter ( obj ) {
if ( obj ) return mixin ( obj ) ;
} ;
/ * *
* Mixin the emitter properties .
*
* @ param { Object } obj
* @ return { Object }
* @ api private
* /
function mixin ( obj ) {
for ( var key in Emitter . prototype ) {
obj [ key ] = Emitter . prototype [ key ] ;
}
return obj ;
}
/ * *
* Listen on the given ` event ` with ` fn ` .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . on =
Emitter . prototype . addEventListener = function ( event , fn ) {
this . _callbacks = this . _callbacks || { } ;
( this . _callbacks [ event ] = this . _callbacks [ event ] || [ ] )
. push ( fn ) ;
return this ;
} ;
/ * *
* Adds an ` event ` listener that will be invoked a single
* time then automatically removed .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . once = function ( event , fn ) {
var self = this ;
this . _callbacks = this . _callbacks || { } ;
function on ( ) {
self . off ( event , on ) ;
fn . apply ( this , arguments ) ;
}
on . fn = fn ;
this . on ( event , on ) ;
return this ;
} ;
/ * *
* Remove the given callback for ` event ` or all
* registered callbacks .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . off =
Emitter . prototype . removeListener =
Emitter . prototype . removeAllListeners =
Emitter . prototype . removeEventListener = function ( event , fn ) {
this . _callbacks = this . _callbacks || { } ;
// all
if ( 0 == arguments . length ) {
this . _callbacks = { } ;
return this ;
}
// specific event
var callbacks = this . _callbacks [ event ] ;
if ( ! callbacks ) return this ;
// remove all handlers
if ( 1 == arguments . length ) {
delete this . _callbacks [ event ] ;
return this ;
}
// remove specific handler
var cb ;
for ( var i = 0 ; i < callbacks . length ; i ++ ) {
cb = callbacks [ i ] ;
if ( cb === fn || cb . fn === fn ) {
callbacks . splice ( i , 1 ) ;
break ;
}
}
return this ;
} ;
/ * *
* Emit ` event ` with the given args .
*
* @ param { String } event
* @ param { Mixed } ...
* @ return { Emitter }
* /
Emitter . prototype . emit = function ( event ) {
this . _callbacks = this . _callbacks || { } ;
var args = [ ] . slice . call ( arguments , 1 )
, callbacks = this . _callbacks [ event ] ;
if ( callbacks ) {
callbacks = callbacks . slice ( 0 ) ;
for ( var i = 0 , len = callbacks . length ; i < len ; ++ i ) {
callbacks [ i ] . apply ( this , args ) ;
}
}
return this ;
} ;
/ * *
* Return array of callbacks for ` event ` .
*
* @ param { String } event
* @ return { Array }
* @ api public
* /
Emitter . prototype . listeners = function ( event ) {
this . _callbacks = this . _callbacks || { } ;
return this . _callbacks [ event ] || [ ] ;
} ;
/ * *
* Check if this emitter has ` event ` handlers .
*
* @ param { String } event
* @ return { Boolean }
* @ api public
* /
Emitter . prototype . hasListeners = function ( event ) {
return ! ! this . listeners ( event ) . length ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 14 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = function ( a , b ) {
var fn = function ( ) { } ;
fn . prototype = b . prototype ;
a . prototype = new fn ;
a . prototype . constructor = a ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 15 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* This is the web browser implementation of ` debug() ` .
*
* Expose ` debug() ` as the module .
* /
exports = module . exports = require ( './debug' ) ;
exports . log = log ;
exports . formatArgs = formatArgs ;
exports . save = save ;
exports . load = load ;
exports . useColors = useColors ;
exports . storage = 'undefined' != typeof chrome
&& 'undefined' != typeof chrome . storage
? chrome . storage . local
: localstorage ( ) ;
/ * *
* Colors .
* /
exports . colors = [
'lightseagreen' ,
'forestgreen' ,
'goldenrod' ,
'dodgerblue' ,
'darkorchid' ,
'crimson'
] ;
/ * *
* Currently only WebKit - based Web Inspectors , Firefox >= v31 ,
* and the Firebug extension ( any Firefox version ) are known
* to support "%c" CSS customizations .
*
* TODO : add a ` localStorage ` variable to explicitly enable / disable colors
* /
function useColors ( ) {
// is webkit? http://stackoverflow.com/a/16459606/376773
return ( 'WebkitAppearance' in document . documentElement . style ) ||
// is firebug? http://stackoverflow.com/a/398120/376773
( window . console && ( console . firebug || ( console . exception && console . table ) ) ) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
( navigator . userAgent . toLowerCase ( ) . match ( /firefox\/(\d+)/ ) && parseInt ( RegExp . $1 , 10 ) >= 31 ) ;
}
/ * *
* Map % j to ` JSON.stringify() ` , since no Web Inspectors do that by default .
* /
exports . formatters . j = function ( v ) {
return JSON . stringify ( v ) ;
} ;
/ * *
* Colorize log arguments if enabled .
*
* @ api public
* /
function formatArgs ( ) {
var args = arguments ;
var useColors = this . useColors ;
args [ 0 ] = ( useColors ? '%c' : '' )
+ this . namespace
+ ( useColors ? ' %c' : ' ' )
+ args [ 0 ]
+ ( useColors ? '%c ' : ' ' )
+ '+' + exports . humanize ( this . diff ) ;
if ( ! useColors ) return args ;
var c = 'color: ' + this . color ;
args = [ args [ 0 ] , c , 'color: inherit' ] . concat ( Array . prototype . slice . call ( args , 1 ) ) ;
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
var index = 0 ;
var lastC = 0 ;
args [ 0 ] . replace ( /%[a-z%]/g , function ( match ) {
if ( '%%' === match ) return ;
index ++ ;
if ( '%c' === match ) {
// we only are interested in the *last* %c
// (the user may have provided their own)
lastC = index ;
}
} ) ;
args . splice ( lastC , 0 , c ) ;
return args ;
}
/ * *
* Invokes ` console.log() ` when available .
* No - op when ` console.log ` is not a "function" .
*
* @ api public
* /
function log ( ) {
// this hackery is required for IE8/9, where
// the `console.log` function doesn't have 'apply'
return 'object' === typeof console
&& console . log
&& Function . prototype . apply . call ( console . log , console , arguments ) ;
}
/ * *
* Save ` namespaces ` .
*
* @ param { String } namespaces
* @ api private
* /
function save ( namespaces ) {
try {
if ( null == namespaces ) {
exports . storage . removeItem ( 'debug' ) ;
} else {
exports . storage . debug = namespaces ;
}
} catch ( e ) { }
}
/ * *
* Load ` namespaces ` .
*
* @ return { String } returns the previously persisted debug modes
* @ api private
* /
function load ( ) {
var r ;
try {
r = exports . storage . debug ;
} catch ( e ) { }
return r ;
}
/ * *
* Enable namespaces listed in ` localStorage.debug ` initially .
* /
exports . enable ( load ( ) ) ;
/ * *
* Localstorage attempts to return the localstorage .
*
* This is necessary because safari throws
* when a user disables cookies / localstorage
* and you attempt to access it .
*
* @ return { LocalStorage }
* @ api private
* /
function localstorage ( ) {
try {
return window . localStorage ;
} catch ( e ) { }
}
2017-02-25 23:25:06 -05:00
} , { "./debug" : 16 } ] , 16 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* This is the common logic for both the Node . js and web browser
* implementations of ` debug() ` .
*
* Expose ` debug() ` as the module .
* /
exports = module . exports = debug ;
exports . coerce = coerce ;
exports . disable = disable ;
exports . enable = enable ;
exports . enabled = enabled ;
exports . humanize = require ( 'ms' ) ;
/ * *
* The currently active debug mode names , and names to skip .
* /
exports . names = [ ] ;
exports . skips = [ ] ;
/ * *
* Map of special "%n" handling functions , for the debug "format" argument .
*
* Valid key names are a single , lowercased letter , i . e . "n" .
* /
exports . formatters = { } ;
/ * *
* Previously assigned color .
* /
var prevColor = 0 ;
/ * *
* Previous log timestamp .
* /
var prevTime ;
/ * *
* Select a color .
*
* @ return { Number }
* @ api private
* /
function selectColor ( ) {
return exports . colors [ prevColor ++ % exports . colors . length ] ;
}
/ * *
* Create a debugger with the given ` namespace ` .
*
* @ param { String } namespace
* @ return { Function }
* @ api public
* /
function debug ( namespace ) {
// define the `disabled` version
function disabled ( ) {
}
disabled . enabled = false ;
// define the `enabled` version
function enabled ( ) {
var self = enabled ;
// set `diff` timestamp
var curr = + new Date ( ) ;
var ms = curr - ( prevTime || curr ) ;
self . diff = ms ;
self . prev = prevTime ;
self . curr = curr ;
prevTime = curr ;
// add the `color` if not set
if ( null == self . useColors ) self . useColors = exports . useColors ( ) ;
if ( null == self . color && self . useColors ) self . color = selectColor ( ) ;
var args = Array . prototype . slice . call ( arguments ) ;
args [ 0 ] = exports . coerce ( args [ 0 ] ) ;
if ( 'string' !== typeof args [ 0 ] ) {
// anything else let's inspect with %o
args = [ '%o' ] . concat ( args ) ;
}
// apply any `formatters` transformations
var index = 0 ;
args [ 0 ] = args [ 0 ] . replace ( /%([a-z%])/g , function ( match , format ) {
// if we encounter an escaped % then don't increase the array index
if ( match === '%%' ) return match ;
index ++ ;
var formatter = exports . formatters [ format ] ;
if ( 'function' === typeof formatter ) {
var val = args [ index ] ;
match = formatter . call ( self , val ) ;
// now we need to remove `args[index]` since it's inlined in the `format`
args . splice ( index , 1 ) ;
index -- ;
}
return match ;
} ) ;
if ( 'function' === typeof exports . formatArgs ) {
args = exports . formatArgs . apply ( self , args ) ;
}
var logFn = enabled . log || exports . log || console . log . bind ( console ) ;
logFn . apply ( self , args ) ;
}
enabled . enabled = true ;
var fn = exports . enabled ( namespace ) ? enabled : disabled ;
fn . namespace = namespace ;
return fn ;
}
/ * *
* Enables a debug mode by namespaces . This can include modes
* separated by a colon and wildcards .
*
* @ param { String } namespaces
* @ api public
* /
function enable ( namespaces ) {
exports . save ( namespaces ) ;
var split = ( namespaces || '' ) . split ( /[\s,]+/ ) ;
var len = split . length ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( ! split [ i ] ) continue ; // ignore empty strings
namespaces = split [ i ] . replace ( /\*/g , '.*?' ) ;
if ( namespaces [ 0 ] === '-' ) {
exports . skips . push ( new RegExp ( '^' + namespaces . substr ( 1 ) + '$' ) ) ;
} else {
exports . names . push ( new RegExp ( '^' + namespaces + '$' ) ) ;
}
}
}
/ * *
* Disable debug output .
*
* @ api public
* /
function disable ( ) {
exports . enable ( '' ) ;
}
/ * *
* Returns true if the given mode name is enabled , false otherwise .
*
* @ param { String } name
* @ return { Boolean }
* @ api public
* /
function enabled ( name ) {
var i , len ;
for ( i = 0 , len = exports . skips . length ; i < len ; i ++ ) {
if ( exports . skips [ i ] . test ( name ) ) {
return false ;
}
}
for ( i = 0 , len = exports . names . length ; i < len ; i ++ ) {
if ( exports . names [ i ] . test ( name ) ) {
return true ;
}
}
return false ;
}
/ * *
* Coerce ` val ` .
*
* @ param { Mixed } val
* @ return { Mixed }
* @ api private
* /
function coerce ( val ) {
if ( val instanceof Error ) return val . stack || val . message ;
return val ;
}
2017-02-25 23:25:06 -05:00
} , { "ms" : 17 } ] , 17 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Helpers .
* /
var s = 1000 ;
var m = s * 60 ;
var h = m * 60 ;
var d = h * 24 ;
var y = d * 365.25 ;
/ * *
* Parse or format the given ` val ` .
*
* Options :
*
* - ` long ` verbose formatting [ false ]
*
* @ param { String | Number } val
* @ param { Object } options
* @ return { String | Number }
* @ api public
* /
module . exports = function ( val , options ) {
options = options || { } ;
if ( 'string' == typeof val ) return parse ( val ) ;
return options . long
? long ( val )
: short ( val ) ;
} ;
/ * *
* Parse the given ` str ` and return milliseconds .
*
* @ param { String } str
* @ return { Number }
* @ api private
* /
function parse ( str ) {
str = '' + str ;
if ( str . length > 10000 ) return ;
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i . exec ( str ) ;
if ( ! match ) return ;
var n = parseFloat ( match [ 1 ] ) ;
var type = ( match [ 2 ] || 'ms' ) . toLowerCase ( ) ;
switch ( type ) {
case 'years' :
case 'year' :
case 'yrs' :
case 'yr' :
case 'y' :
return n * y ;
case 'days' :
case 'day' :
case 'd' :
return n * d ;
case 'hours' :
case 'hour' :
case 'hrs' :
case 'hr' :
case 'h' :
return n * h ;
case 'minutes' :
case 'minute' :
case 'mins' :
case 'min' :
case 'm' :
return n * m ;
case 'seconds' :
case 'second' :
case 'secs' :
case 'sec' :
case 's' :
return n * s ;
case 'milliseconds' :
case 'millisecond' :
case 'msecs' :
case 'msec' :
case 'ms' :
return n ;
}
}
/ * *
* Short format for ` ms ` .
*
* @ param { Number } ms
* @ return { String }
* @ api private
* /
function short ( ms ) {
if ( ms >= d ) return Math . round ( ms / d ) + 'd' ;
if ( ms >= h ) return Math . round ( ms / h ) + 'h' ;
if ( ms >= m ) return Math . round ( ms / m ) + 'm' ;
if ( ms >= s ) return Math . round ( ms / s ) + 's' ;
return ms + 'ms' ;
}
/ * *
* Long format for ` ms ` .
*
* @ param { Number } ms
* @ return { String }
* @ api private
* /
function long ( ms ) {
return plural ( ms , d , 'day' )
|| plural ( ms , h , 'hour' )
|| plural ( ms , m , 'minute' )
|| plural ( ms , s , 'second' )
|| ms + ' ms' ;
}
/ * *
* Pluralization helper .
* /
function plural ( ms , n , name ) {
if ( ms < n ) return ;
if ( ms < n * 1.5 ) return Math . floor ( ms / n ) + ' ' + name ;
return Math . ceil ( ms / n ) + ' ' + name + 's' ;
}
2017-02-25 23:25:06 -05:00
} , { } ] , 18 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = require ( './lib/index' ) ;
2017-02-25 23:25:06 -05:00
} , { "./lib/index" : 19 } ] , 19 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = require ( './socket' ) ;
/ * *
* Exports parser
*
* @ api public
*
* /
module . exports . parser = require ( 'engine.io-parser' ) ;
2017-02-25 23:25:06 -05:00
} , { "./socket" : 20 , "engine.io-parser" : 31 } ] , 20 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module dependencies .
* /
var transports = require ( './transports/index' ) ;
var Emitter = require ( 'component-emitter' ) ;
var debug = require ( 'debug' ) ( 'engine.io-client:socket' ) ;
var index = require ( 'indexof' ) ;
var parser = require ( 'engine.io-parser' ) ;
var parseuri = require ( 'parseuri' ) ;
var parsejson = require ( 'parsejson' ) ;
var parseqs = require ( 'parseqs' ) ;
/ * *
* Module exports .
* /
module . exports = Socket ;
/ * *
* Socket constructor .
*
* @ param { String | Object } uri or options
* @ param { Object } options
* @ api public
* /
function Socket ( uri , opts ) {
if ( ! ( this instanceof Socket ) ) return new Socket ( uri , opts ) ;
opts = opts || { } ;
if ( uri && 'object' === typeof uri ) {
opts = uri ;
uri = null ;
}
if ( uri ) {
uri = parseuri ( uri ) ;
opts . hostname = uri . host ;
opts . secure = uri . protocol === 'https' || uri . protocol === 'wss' ;
opts . port = uri . port ;
if ( uri . query ) opts . query = uri . query ;
} else if ( opts . host ) {
opts . hostname = parseuri ( opts . host ) . host ;
}
this . secure = null != opts . secure ? opts . secure
: ( global . location && 'https:' === location . protocol ) ;
if ( opts . hostname && ! opts . port ) {
// if no port is specified manually, use the protocol default
opts . port = this . secure ? '443' : '80' ;
}
this . agent = opts . agent || false ;
this . hostname = opts . hostname ||
( global . location ? location . hostname : 'localhost' ) ;
this . port = opts . port || ( global . location && location . port
? location . port
: ( this . secure ? 443 : 80 ) ) ;
this . query = opts . query || { } ;
if ( 'string' === typeof this . query ) this . query = parseqs . decode ( this . query ) ;
this . upgrade = false !== opts . upgrade ;
this . path = ( opts . path || '/engine.io' ) . replace ( /\/$/ , '' ) + '/' ;
this . forceJSONP = ! ! opts . forceJSONP ;
this . jsonp = false !== opts . jsonp ;
this . forceBase64 = ! ! opts . forceBase64 ;
this . enablesXDR = ! ! opts . enablesXDR ;
this . timestampParam = opts . timestampParam || 't' ;
this . timestampRequests = opts . timestampRequests ;
this . transports = opts . transports || [ 'polling' , 'websocket' ] ;
this . readyState = '' ;
this . writeBuffer = [ ] ;
this . prevBufferLen = 0 ;
this . policyPort = opts . policyPort || 843 ;
this . rememberUpgrade = opts . rememberUpgrade || false ;
this . binaryType = null ;
this . onlyBinaryUpgrades = opts . onlyBinaryUpgrades ;
this . perMessageDeflate = false !== opts . perMessageDeflate ? ( opts . perMessageDeflate || { } ) : false ;
if ( true === this . perMessageDeflate ) this . perMessageDeflate = { } ;
if ( this . perMessageDeflate && null == this . perMessageDeflate . threshold ) {
this . perMessageDeflate . threshold = 1024 ;
}
// SSL options for Node.js client
this . pfx = opts . pfx || null ;
this . key = opts . key || null ;
this . passphrase = opts . passphrase || null ;
this . cert = opts . cert || null ;
this . ca = opts . ca || null ;
this . ciphers = opts . ciphers || null ;
this . rejectUnauthorized = opts . rejectUnauthorized === undefined ? null : opts . rejectUnauthorized ;
this . forceNode = ! ! opts . forceNode ;
// other options for Node.js client
var freeGlobal = typeof global === 'object' && global ;
if ( freeGlobal . global === freeGlobal ) {
if ( opts . extraHeaders && Object . keys ( opts . extraHeaders ) . length > 0 ) {
this . extraHeaders = opts . extraHeaders ;
}
if ( opts . localAddress ) {
this . localAddress = opts . localAddress ;
}
}
// set on handshake
this . id = null ;
this . upgrades = null ;
this . pingInterval = null ;
this . pingTimeout = null ;
// set on heartbeat
this . pingIntervalTimer = null ;
this . pingTimeoutTimer = null ;
this . open ( ) ;
}
Socket . priorWebsocketSuccess = false ;
/ * *
* Mix in ` Emitter ` .
* /
Emitter ( Socket . prototype ) ;
/ * *
* Protocol version .
*
* @ api public
* /
Socket . protocol = parser . protocol ; // this is an int
/ * *
* Expose deps for legacy compatibility
* and standalone browser access .
* /
Socket . Socket = Socket ;
Socket . Transport = require ( './transport' ) ;
Socket . transports = require ( './transports/index' ) ;
Socket . parser = require ( 'engine.io-parser' ) ;
/ * *
* Creates transport of the given type .
*
* @ param { String } transport name
* @ return { Transport }
* @ api private
* /
Socket . prototype . createTransport = function ( name ) {
debug ( 'creating transport "%s"' , name ) ;
var query = clone ( this . query ) ;
// append engine.io protocol identifier
query . EIO = parser . protocol ;
// transport name
query . transport = name ;
// session id if we already have one
if ( this . id ) query . sid = this . id ;
var transport = new transports [ name ] ( {
agent : this . agent ,
hostname : this . hostname ,
port : this . port ,
secure : this . secure ,
path : this . path ,
query : query ,
forceJSONP : this . forceJSONP ,
jsonp : this . jsonp ,
forceBase64 : this . forceBase64 ,
enablesXDR : this . enablesXDR ,
timestampRequests : this . timestampRequests ,
timestampParam : this . timestampParam ,
policyPort : this . policyPort ,
socket : this ,
pfx : this . pfx ,
key : this . key ,
passphrase : this . passphrase ,
cert : this . cert ,
ca : this . ca ,
ciphers : this . ciphers ,
rejectUnauthorized : this . rejectUnauthorized ,
perMessageDeflate : this . perMessageDeflate ,
extraHeaders : this . extraHeaders ,
forceNode : this . forceNode ,
localAddress : this . localAddress
} ) ;
return transport ;
} ;
function clone ( obj ) {
var o = { } ;
for ( var i in obj ) {
if ( obj . hasOwnProperty ( i ) ) {
o [ i ] = obj [ i ] ;
}
}
return o ;
}
/ * *
* Initializes transport to use and starts probe .
*
* @ api private
* /
Socket . prototype . open = function ( ) {
var transport ;
if ( this . rememberUpgrade && Socket . priorWebsocketSuccess && this . transports . indexOf ( 'websocket' ) !== - 1 ) {
transport = 'websocket' ;
} else if ( 0 === this . transports . length ) {
// Emit error on next tick so it can be listened to
var self = this ;
setTimeout ( function ( ) {
self . emit ( 'error' , 'No transports available' ) ;
} , 0 ) ;
return ;
} else {
transport = this . transports [ 0 ] ;
}
this . readyState = 'opening' ;
// Retry with the next transport if the transport is disabled (jsonp: false)
try {
transport = this . createTransport ( transport ) ;
} catch ( e ) {
this . transports . shift ( ) ;
this . open ( ) ;
return ;
}
transport . open ( ) ;
this . setTransport ( transport ) ;
} ;
/ * *
* Sets the current transport . Disables the existing one ( if any ) .
*
* @ api private
* /
Socket . prototype . setTransport = function ( transport ) {
debug ( 'setting transport %s' , transport . name ) ;
var self = this ;
if ( this . transport ) {
debug ( 'clearing existing transport %s' , this . transport . name ) ;
this . transport . removeAllListeners ( ) ;
}
// set up transport
this . transport = transport ;
// set up transport listeners
transport
. on ( 'drain' , function ( ) {
self . onDrain ( ) ;
} )
. on ( 'packet' , function ( packet ) {
self . onPacket ( packet ) ;
} )
. on ( 'error' , function ( e ) {
self . onError ( e ) ;
} )
. on ( 'close' , function ( ) {
self . onClose ( 'transport close' ) ;
} ) ;
} ;
/ * *
* Probes a transport .
*
* @ param { String } transport name
* @ api private
* /
Socket . prototype . probe = function ( name ) {
debug ( 'probing transport "%s"' , name ) ;
var transport = this . createTransport ( name , { probe : 1 } ) ;
var failed = false ;
var self = this ;
Socket . priorWebsocketSuccess = false ;
function onTransportOpen ( ) {
if ( self . onlyBinaryUpgrades ) {
var upgradeLosesBinary = ! this . supportsBinary && self . transport . supportsBinary ;
failed = failed || upgradeLosesBinary ;
}
if ( failed ) return ;
debug ( 'probe transport "%s" opened' , name ) ;
transport . send ( [ { type : 'ping' , data : 'probe' } ] ) ;
transport . once ( 'packet' , function ( msg ) {
if ( failed ) return ;
if ( 'pong' === msg . type && 'probe' === msg . data ) {
debug ( 'probe transport "%s" pong' , name ) ;
self . upgrading = true ;
self . emit ( 'upgrading' , transport ) ;
if ( ! transport ) return ;
Socket . priorWebsocketSuccess = 'websocket' === transport . name ;
debug ( 'pausing current transport "%s"' , self . transport . name ) ;
self . transport . pause ( function ( ) {
if ( failed ) return ;
if ( 'closed' === self . readyState ) return ;
debug ( 'changing transport and sending upgrade packet' ) ;
cleanup ( ) ;
self . setTransport ( transport ) ;
transport . send ( [ { type : 'upgrade' } ] ) ;
self . emit ( 'upgrade' , transport ) ;
transport = null ;
self . upgrading = false ;
self . flush ( ) ;
} ) ;
} else {
debug ( 'probe transport "%s" failed' , name ) ;
var err = new Error ( 'probe error' ) ;
err . transport = transport . name ;
self . emit ( 'upgradeError' , err ) ;
}
} ) ;
}
function freezeTransport ( ) {
if ( failed ) return ;
// Any callback called by transport should be ignored since now
failed = true ;
cleanup ( ) ;
transport . close ( ) ;
transport = null ;
}
// Handle any error that happens while probing
function onerror ( err ) {
var error = new Error ( 'probe error: ' + err ) ;
error . transport = transport . name ;
freezeTransport ( ) ;
debug ( 'probe transport "%s" failed because of error: %s' , name , err ) ;
self . emit ( 'upgradeError' , error ) ;
}
function onTransportClose ( ) {
onerror ( 'transport closed' ) ;
}
// When the socket is closed while we're probing
function onclose ( ) {
onerror ( 'socket closed' ) ;
}
// When the socket is upgraded while we're probing
function onupgrade ( to ) {
if ( transport && to . name !== transport . name ) {
debug ( '"%s" works - aborting "%s"' , to . name , transport . name ) ;
freezeTransport ( ) ;
}
}
// Remove all listeners on the transport and on self
function cleanup ( ) {
transport . removeListener ( 'open' , onTransportOpen ) ;
transport . removeListener ( 'error' , onerror ) ;
transport . removeListener ( 'close' , onTransportClose ) ;
self . removeListener ( 'close' , onclose ) ;
self . removeListener ( 'upgrading' , onupgrade ) ;
}
transport . once ( 'open' , onTransportOpen ) ;
transport . once ( 'error' , onerror ) ;
transport . once ( 'close' , onTransportClose ) ;
this . once ( 'close' , onclose ) ;
this . once ( 'upgrading' , onupgrade ) ;
transport . open ( ) ;
} ;
/ * *
* Called when connection is deemed open .
*
* @ api public
* /
Socket . prototype . onOpen = function ( ) {
debug ( 'socket open' ) ;
this . readyState = 'open' ;
Socket . priorWebsocketSuccess = 'websocket' === this . transport . name ;
this . emit ( 'open' ) ;
this . flush ( ) ;
// we check for `readyState` in case an `open`
// listener already closed the socket
if ( 'open' === this . readyState && this . upgrade && this . transport . pause ) {
debug ( 'starting upgrade probes' ) ;
for ( var i = 0 , l = this . upgrades . length ; i < l ; i ++ ) {
this . probe ( this . upgrades [ i ] ) ;
}
}
} ;
/ * *
* Handles a packet .
*
* @ api private
* /
Socket . prototype . onPacket = function ( packet ) {
if ( 'opening' === this . readyState || 'open' === this . readyState ||
'closing' === this . readyState ) {
debug ( 'socket receive: type "%s", data "%s"' , packet . type , packet . data ) ;
this . emit ( 'packet' , packet ) ;
// Socket is live - any packet counts
this . emit ( 'heartbeat' ) ;
switch ( packet . type ) {
case 'open' :
this . onHandshake ( parsejson ( packet . data ) ) ;
break ;
case 'pong' :
this . setPing ( ) ;
this . emit ( 'pong' ) ;
break ;
case 'error' :
var err = new Error ( 'server error' ) ;
err . code = packet . data ;
this . onError ( err ) ;
break ;
case 'message' :
this . emit ( 'data' , packet . data ) ;
this . emit ( 'message' , packet . data ) ;
break ;
}
} else {
debug ( 'packet received with socket readyState "%s"' , this . readyState ) ;
}
} ;
/ * *
* Called upon handshake completion .
*
* @ param { Object } handshake obj
* @ api private
* /
Socket . prototype . onHandshake = function ( data ) {
this . emit ( 'handshake' , data ) ;
this . id = data . sid ;
this . transport . query . sid = data . sid ;
this . upgrades = this . filterUpgrades ( data . upgrades ) ;
this . pingInterval = data . pingInterval ;
this . pingTimeout = data . pingTimeout ;
this . onOpen ( ) ;
// In case open handler closes socket
if ( 'closed' === this . readyState ) return ;
this . setPing ( ) ;
// Prolong liveness of socket on heartbeat
this . removeListener ( 'heartbeat' , this . onHeartbeat ) ;
this . on ( 'heartbeat' , this . onHeartbeat ) ;
} ;
/ * *
* Resets ping timeout .
*
* @ api private
* /
Socket . prototype . onHeartbeat = function ( timeout ) {
clearTimeout ( this . pingTimeoutTimer ) ;
var self = this ;
self . pingTimeoutTimer = setTimeout ( function ( ) {
if ( 'closed' === self . readyState ) return ;
self . onClose ( 'ping timeout' ) ;
} , timeout || ( self . pingInterval + self . pingTimeout ) ) ;
} ;
/ * *
* Pings server every ` this.pingInterval ` and expects response
* within ` this.pingTimeout ` or closes connection .
*
* @ api private
* /
Socket . prototype . setPing = function ( ) {
var self = this ;
clearTimeout ( self . pingIntervalTimer ) ;
self . pingIntervalTimer = setTimeout ( function ( ) {
debug ( 'writing ping packet - expecting pong within %sms' , self . pingTimeout ) ;
self . ping ( ) ;
self . onHeartbeat ( self . pingTimeout ) ;
} , self . pingInterval ) ;
} ;
/ * *
* Sends a ping packet .
*
* @ api private
* /
Socket . prototype . ping = function ( ) {
var self = this ;
this . sendPacket ( 'ping' , function ( ) {
self . emit ( 'ping' ) ;
} ) ;
} ;
/ * *
* Called on ` drain ` event
*
* @ api private
* /
Socket . prototype . onDrain = function ( ) {
this . writeBuffer . splice ( 0 , this . prevBufferLen ) ;
// setting prevBufferLen = 0 is very important
// for example, when upgrading, upgrade packet is sent over,
// and a nonzero prevBufferLen could cause problems on `drain`
this . prevBufferLen = 0 ;
if ( 0 === this . writeBuffer . length ) {
this . emit ( 'drain' ) ;
} else {
this . flush ( ) ;
}
} ;
/ * *
* Flush write buffers .
*
* @ api private
* /
Socket . prototype . flush = function ( ) {
if ( 'closed' !== this . readyState && this . transport . writable &&
! this . upgrading && this . writeBuffer . length ) {
debug ( 'flushing %d packets in socket' , this . writeBuffer . length ) ;
this . transport . send ( this . writeBuffer ) ;
// keep track of current length of writeBuffer
// splice writeBuffer and callbackBuffer on `drain`
this . prevBufferLen = this . writeBuffer . length ;
this . emit ( 'flush' ) ;
}
} ;
/ * *
* Sends a message .
*
* @ param { String } message .
* @ param { Function } callback function .
* @ param { Object } options .
* @ return { Socket } for chaining .
* @ api public
* /
Socket . prototype . write =
Socket . prototype . send = function ( msg , options , fn ) {
this . sendPacket ( 'message' , msg , options , fn ) ;
return this ;
} ;
/ * *
* Sends a packet .
*
* @ param { String } packet type .
* @ param { String } data .
* @ param { Object } options .
* @ param { Function } callback function .
* @ api private
* /
Socket . prototype . sendPacket = function ( type , data , options , fn ) {
if ( 'function' === typeof data ) {
fn = data ;
data = undefined ;
}
if ( 'function' === typeof options ) {
fn = options ;
options = null ;
}
if ( 'closing' === this . readyState || 'closed' === this . readyState ) {
return ;
}
options = options || { } ;
options . compress = false !== options . compress ;
var packet = {
type : type ,
data : data ,
options : options
} ;
this . emit ( 'packetCreate' , packet ) ;
this . writeBuffer . push ( packet ) ;
if ( fn ) this . once ( 'flush' , fn ) ;
this . flush ( ) ;
} ;
/ * *
* Closes the connection .
*
* @ api private
* /
Socket . prototype . close = function ( ) {
if ( 'opening' === this . readyState || 'open' === this . readyState ) {
this . readyState = 'closing' ;
var self = this ;
if ( this . writeBuffer . length ) {
this . once ( 'drain' , function ( ) {
if ( this . upgrading ) {
waitForUpgrade ( ) ;
} else {
close ( ) ;
}
} ) ;
} else if ( this . upgrading ) {
waitForUpgrade ( ) ;
} else {
close ( ) ;
}
}
function close ( ) {
self . onClose ( 'forced close' ) ;
debug ( 'socket closing - telling transport to close' ) ;
self . transport . close ( ) ;
}
function cleanupAndClose ( ) {
self . removeListener ( 'upgrade' , cleanupAndClose ) ;
self . removeListener ( 'upgradeError' , cleanupAndClose ) ;
close ( ) ;
}
function waitForUpgrade ( ) {
// wait for upgrade to finish since we can't send packets while pausing a transport
self . once ( 'upgrade' , cleanupAndClose ) ;
self . once ( 'upgradeError' , cleanupAndClose ) ;
}
return this ;
} ;
/ * *
* Called upon transport error
*
* @ api private
* /
Socket . prototype . onError = function ( err ) {
debug ( 'socket error %j' , err ) ;
Socket . priorWebsocketSuccess = false ;
this . emit ( 'error' , err ) ;
this . onClose ( 'transport error' , err ) ;
} ;
/ * *
* Called upon transport close .
*
* @ api private
* /
Socket . prototype . onClose = function ( reason , desc ) {
if ( 'opening' === this . readyState || 'open' === this . readyState || 'closing' === this . readyState ) {
debug ( 'socket close with reason: "%s"' , reason ) ;
var self = this ;
// clear timers
clearTimeout ( this . pingIntervalTimer ) ;
clearTimeout ( this . pingTimeoutTimer ) ;
// stop event from firing again for transport
this . transport . removeAllListeners ( 'close' ) ;
// ensure transport won't stay open
this . transport . close ( ) ;
// ignore further transport communication
this . transport . removeAllListeners ( ) ;
// set ready state
this . readyState = 'closed' ;
// clear session id
this . id = null ;
// emit close event
this . emit ( 'close' , reason , desc ) ;
// clean buffers after, so users can still
// grab the buffers on `close` event
self . writeBuffer = [ ] ;
self . prevBufferLen = 0 ;
}
} ;
/ * *
* Filters upgrades , returning only those matching client transports .
*
* @ param { Array } server upgrades
* @ api private
*
* /
Socket . prototype . filterUpgrades = function ( upgrades ) {
var filteredUpgrades = [ ] ;
for ( var i = 0 , j = upgrades . length ; i < j ; i ++ ) {
if ( ~ index ( this . transports , upgrades [ i ] ) ) filteredUpgrades . push ( upgrades [ i ] ) ;
}
return filteredUpgrades ;
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./transport" : 21 , "./transports/index" : 22 , "component-emitter" : 28 , "debug" : 29 , "engine.io-parser" : 31 , "indexof" : 35 , "parsejson" : 39 , "parseqs" : 40 , "parseuri" : 41 } ] , 21 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var parser = require ( 'engine.io-parser' ) ;
var Emitter = require ( 'component-emitter' ) ;
/ * *
* Module exports .
* /
module . exports = Transport ;
/ * *
* Transport abstract constructor .
*
* @ param { Object } options .
* @ api private
* /
function Transport ( opts ) {
this . path = opts . path ;
this . hostname = opts . hostname ;
this . port = opts . port ;
this . secure = opts . secure ;
this . query = opts . query ;
this . timestampParam = opts . timestampParam ;
this . timestampRequests = opts . timestampRequests ;
this . readyState = '' ;
this . agent = opts . agent || false ;
this . socket = opts . socket ;
this . enablesXDR = opts . enablesXDR ;
// SSL options for Node.js client
this . pfx = opts . pfx ;
this . key = opts . key ;
this . passphrase = opts . passphrase ;
this . cert = opts . cert ;
this . ca = opts . ca ;
this . ciphers = opts . ciphers ;
this . rejectUnauthorized = opts . rejectUnauthorized ;
this . forceNode = opts . forceNode ;
// other options for Node.js client
this . extraHeaders = opts . extraHeaders ;
this . localAddress = opts . localAddress ;
}
/ * *
* Mix in ` Emitter ` .
* /
Emitter ( Transport . prototype ) ;
/ * *
* Emits an error .
*
* @ param { String } str
* @ return { Transport } for chaining
* @ api public
* /
Transport . prototype . onError = function ( msg , desc ) {
var err = new Error ( msg ) ;
err . type = 'TransportError' ;
err . description = desc ;
this . emit ( 'error' , err ) ;
return this ;
} ;
/ * *
* Opens the transport .
*
* @ api public
* /
Transport . prototype . open = function ( ) {
if ( 'closed' === this . readyState || '' === this . readyState ) {
this . readyState = 'opening' ;
this . doOpen ( ) ;
}
return this ;
} ;
/ * *
* Closes the transport .
*
* @ api private
* /
Transport . prototype . close = function ( ) {
if ( 'opening' === this . readyState || 'open' === this . readyState ) {
this . doClose ( ) ;
this . onClose ( ) ;
}
return this ;
} ;
/ * *
* Sends multiple packets .
*
* @ param { Array } packets
* @ api private
* /
Transport . prototype . send = function ( packets ) {
if ( 'open' === this . readyState ) {
this . write ( packets ) ;
} else {
throw new Error ( 'Transport not open' ) ;
}
} ;
/ * *
* Called upon open
*
* @ api private
* /
Transport . prototype . onOpen = function ( ) {
this . readyState = 'open' ;
this . writable = true ;
this . emit ( 'open' ) ;
} ;
/ * *
* Called with data .
*
* @ param { String } data
* @ api private
* /
Transport . prototype . onData = function ( data ) {
var packet = parser . decodePacket ( data , this . socket . binaryType ) ;
this . onPacket ( packet ) ;
} ;
/ * *
* Called with a decoded packet .
* /
Transport . prototype . onPacket = function ( packet ) {
this . emit ( 'packet' , packet ) ;
} ;
/ * *
* Called upon close .
*
* @ api private
* /
Transport . prototype . onClose = function ( ) {
this . readyState = 'closed' ;
this . emit ( 'close' ) ;
} ;
2017-02-25 23:25:06 -05:00
} , { "component-emitter" : 28 , "engine.io-parser" : 31 } ] , 22 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module dependencies
* /
var XMLHttpRequest = require ( 'xmlhttprequest-ssl' ) ;
var XHR = require ( './polling-xhr' ) ;
var JSONP = require ( './polling-jsonp' ) ;
var websocket = require ( './websocket' ) ;
/ * *
* Export transports .
* /
exports . polling = polling ;
exports . websocket = websocket ;
/ * *
* Polling transport polymorphic constructor .
* Decides on xhr vs jsonp based on feature detection .
*
* @ api private
* /
function polling ( opts ) {
var xhr ;
var xd = false ;
var xs = false ;
var jsonp = false !== opts . jsonp ;
if ( global . location ) {
var isSSL = 'https:' === location . protocol ;
var port = location . port ;
// some user agents have empty `location.port`
if ( ! port ) {
port = isSSL ? 443 : 80 ;
}
xd = opts . hostname !== location . hostname || port !== opts . port ;
xs = opts . secure !== isSSL ;
}
opts . xdomain = xd ;
opts . xscheme = xs ;
xhr = new XMLHttpRequest ( opts ) ;
if ( 'open' in xhr && ! opts . forceJSONP ) {
return new XHR ( opts ) ;
} else {
if ( ! jsonp ) throw new Error ( 'JSONP disabled' ) ;
return new JSONP ( opts ) ;
}
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./polling-jsonp" : 23 , "./polling-xhr" : 24 , "./websocket" : 26 , "xmlhttprequest-ssl" : 27 } ] , 23 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module requirements .
* /
var Polling = require ( './polling' ) ;
var inherit = require ( 'component-inherit' ) ;
/ * *
* Module exports .
* /
module . exports = JSONPPolling ;
/ * *
* Cached regular expressions .
* /
var rNewline = /\n/g ;
var rEscapedNewline = /\\n/g ;
/ * *
* Global JSONP callbacks .
* /
var callbacks ;
/ * *
* Noop .
* /
function empty ( ) { }
/ * *
* JSONP Polling constructor .
*
* @ param { Object } opts .
* @ api public
* /
function JSONPPolling ( opts ) {
Polling . call ( this , opts ) ;
this . query = this . query || { } ;
// define global callbacks array if not present
// we do this here (lazily) to avoid unneeded global pollution
if ( ! callbacks ) {
// we need to consider multiple engines in the same page
if ( ! global . _ _ _eio ) global . _ _ _eio = [ ] ;
callbacks = global . _ _ _eio ;
}
// callback identifier
this . index = callbacks . length ;
// add callback to jsonp global
var self = this ;
callbacks . push ( function ( msg ) {
self . onData ( msg ) ;
} ) ;
// append to query string
this . query . j = this . index ;
// prevent spurious errors from being emitted when the window is unloaded
if ( global . document && global . addEventListener ) {
global . addEventListener ( 'beforeunload' , function ( ) {
if ( self . script ) self . script . onerror = empty ;
} , false ) ;
}
}
/ * *
* Inherits from Polling .
* /
inherit ( JSONPPolling , Polling ) ;
/ *
* JSONP only supports binary as base64 encoded strings
* /
JSONPPolling . prototype . supportsBinary = false ;
/ * *
* Closes the socket .
*
* @ api private
* /
JSONPPolling . prototype . doClose = function ( ) {
if ( this . script ) {
this . script . parentNode . removeChild ( this . script ) ;
this . script = null ;
}
if ( this . form ) {
this . form . parentNode . removeChild ( this . form ) ;
this . form = null ;
this . iframe = null ;
}
Polling . prototype . doClose . call ( this ) ;
} ;
/ * *
* Starts a poll cycle .
*
* @ api private
* /
JSONPPolling . prototype . doPoll = function ( ) {
var self = this ;
var script = document . createElement ( 'script' ) ;
if ( this . script ) {
this . script . parentNode . removeChild ( this . script ) ;
this . script = null ;
}
script . async = true ;
script . src = this . uri ( ) ;
script . onerror = function ( e ) {
self . onError ( 'jsonp poll error' , e ) ;
} ;
var insertAt = document . getElementsByTagName ( 'script' ) [ 0 ] ;
if ( insertAt ) {
insertAt . parentNode . insertBefore ( script , insertAt ) ;
} else {
( document . head || document . body ) . appendChild ( script ) ;
}
this . script = script ;
var isUAgecko = 'undefined' !== typeof navigator && /gecko/i . test ( navigator . userAgent ) ;
if ( isUAgecko ) {
setTimeout ( function ( ) {
var iframe = document . createElement ( 'iframe' ) ;
document . body . appendChild ( iframe ) ;
document . body . removeChild ( iframe ) ;
} , 100 ) ;
}
} ;
/ * *
* Writes with a hidden iframe .
*
* @ param { String } data to send
* @ param { Function } called upon flush .
* @ api private
* /
JSONPPolling . prototype . doWrite = function ( data , fn ) {
var self = this ;
if ( ! this . form ) {
var form = document . createElement ( 'form' ) ;
var area = document . createElement ( 'textarea' ) ;
var id = this . iframeId = 'eio_iframe_' + this . index ;
var iframe ;
form . className = 'socketio' ;
form . style . position = 'absolute' ;
form . style . top = '-1000px' ;
form . style . left = '-1000px' ;
form . target = id ;
form . method = 'POST' ;
form . setAttribute ( 'accept-charset' , 'utf-8' ) ;
area . name = 'd' ;
form . appendChild ( area ) ;
document . body . appendChild ( form ) ;
this . form = form ;
this . area = area ;
}
this . form . action = this . uri ( ) ;
function complete ( ) {
initIframe ( ) ;
fn ( ) ;
}
function initIframe ( ) {
if ( self . iframe ) {
try {
self . form . removeChild ( self . iframe ) ;
} catch ( e ) {
self . onError ( 'jsonp polling iframe removal error' , e ) ;
}
}
try {
// ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
var html = '<iframe src="javascript:0" name="' + self . iframeId + '">' ;
iframe = document . createElement ( html ) ;
} catch ( e ) {
iframe = document . createElement ( 'iframe' ) ;
iframe . name = self . iframeId ;
iframe . src = 'javascript:0' ;
}
iframe . id = self . iframeId ;
self . form . appendChild ( iframe ) ;
self . iframe = iframe ;
}
initIframe ( ) ;
// escape \n to prevent it from being converted into \r\n by some UAs
// double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
data = data . replace ( rEscapedNewline , '\\\n' ) ;
this . area . value = data . replace ( rNewline , '\\n' ) ;
try {
this . form . submit ( ) ;
} catch ( e ) { }
if ( this . iframe . attachEvent ) {
this . iframe . onreadystatechange = function ( ) {
if ( self . iframe . readyState === 'complete' ) {
complete ( ) ;
}
} ;
} else {
this . iframe . onload = complete ;
}
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./polling" : 25 , "component-inherit" : 14 } ] , 24 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module requirements .
* /
var XMLHttpRequest = require ( 'xmlhttprequest-ssl' ) ;
var Polling = require ( './polling' ) ;
var Emitter = require ( 'component-emitter' ) ;
var inherit = require ( 'component-inherit' ) ;
var debug = require ( 'debug' ) ( 'engine.io-client:polling-xhr' ) ;
/ * *
* Module exports .
* /
module . exports = XHR ;
module . exports . Request = Request ;
/ * *
* Empty function
* /
function empty ( ) { }
/ * *
* XHR Polling constructor .
*
* @ param { Object } opts
* @ api public
* /
function XHR ( opts ) {
Polling . call ( this , opts ) ;
this . requestTimeout = opts . requestTimeout ;
if ( global . location ) {
var isSSL = 'https:' === location . protocol ;
var port = location . port ;
// some user agents have empty `location.port`
if ( ! port ) {
port = isSSL ? 443 : 80 ;
}
this . xd = opts . hostname !== global . location . hostname ||
port !== opts . port ;
this . xs = opts . secure !== isSSL ;
} else {
this . extraHeaders = opts . extraHeaders ;
}
}
/ * *
* Inherits from Polling .
* /
inherit ( XHR , Polling ) ;
/ * *
* XHR supports binary
* /
XHR . prototype . supportsBinary = true ;
/ * *
* Creates a request .
*
* @ param { String } method
* @ api private
* /
XHR . prototype . request = function ( opts ) {
opts = opts || { } ;
opts . uri = this . uri ( ) ;
opts . xd = this . xd ;
opts . xs = this . xs ;
opts . agent = this . agent || false ;
opts . supportsBinary = this . supportsBinary ;
opts . enablesXDR = this . enablesXDR ;
// SSL options for Node.js client
opts . pfx = this . pfx ;
opts . key = this . key ;
opts . passphrase = this . passphrase ;
opts . cert = this . cert ;
opts . ca = this . ca ;
opts . ciphers = this . ciphers ;
opts . rejectUnauthorized = this . rejectUnauthorized ;
opts . requestTimeout = this . requestTimeout ;
// other options for Node.js client
opts . extraHeaders = this . extraHeaders ;
return new Request ( opts ) ;
} ;
/ * *
* Sends data .
*
* @ param { String } data to send .
* @ param { Function } called upon flush .
* @ api private
* /
XHR . prototype . doWrite = function ( data , fn ) {
var isBinary = typeof data !== 'string' && data !== undefined ;
var req = this . request ( { method : 'POST' , data : data , isBinary : isBinary } ) ;
var self = this ;
req . on ( 'success' , fn ) ;
req . on ( 'error' , function ( err ) {
self . onError ( 'xhr post error' , err ) ;
} ) ;
this . sendXhr = req ;
} ;
/ * *
* Starts a poll cycle .
*
* @ api private
* /
XHR . prototype . doPoll = function ( ) {
debug ( 'xhr poll' ) ;
var req = this . request ( ) ;
var self = this ;
req . on ( 'data' , function ( data ) {
self . onData ( data ) ;
} ) ;
req . on ( 'error' , function ( err ) {
self . onError ( 'xhr poll error' , err ) ;
} ) ;
this . pollXhr = req ;
} ;
/ * *
* Request constructor
*
* @ param { Object } options
* @ api public
* /
function Request ( opts ) {
this . method = opts . method || 'GET' ;
this . uri = opts . uri ;
this . xd = ! ! opts . xd ;
this . xs = ! ! opts . xs ;
this . async = false !== opts . async ;
this . data = undefined !== opts . data ? opts . data : null ;
this . agent = opts . agent ;
this . isBinary = opts . isBinary ;
this . supportsBinary = opts . supportsBinary ;
this . enablesXDR = opts . enablesXDR ;
this . requestTimeout = opts . requestTimeout ;
// SSL options for Node.js client
this . pfx = opts . pfx ;
this . key = opts . key ;
this . passphrase = opts . passphrase ;
this . cert = opts . cert ;
this . ca = opts . ca ;
this . ciphers = opts . ciphers ;
this . rejectUnauthorized = opts . rejectUnauthorized ;
// other options for Node.js client
this . extraHeaders = opts . extraHeaders ;
this . create ( ) ;
}
/ * *
* Mix in ` Emitter ` .
* /
Emitter ( Request . prototype ) ;
/ * *
* Creates the XHR object and sends the request .
*
* @ api private
* /
Request . prototype . create = function ( ) {
var opts = { agent : this . agent , xdomain : this . xd , xscheme : this . xs , enablesXDR : this . enablesXDR } ;
// SSL options for Node.js client
opts . pfx = this . pfx ;
opts . key = this . key ;
opts . passphrase = this . passphrase ;
opts . cert = this . cert ;
opts . ca = this . ca ;
opts . ciphers = this . ciphers ;
opts . rejectUnauthorized = this . rejectUnauthorized ;
var xhr = this . xhr = new XMLHttpRequest ( opts ) ;
var self = this ;
try {
debug ( 'xhr open %s: %s' , this . method , this . uri ) ;
xhr . open ( this . method , this . uri , this . async ) ;
try {
if ( this . extraHeaders ) {
xhr . setDisableHeaderCheck ( true ) ;
for ( var i in this . extraHeaders ) {
if ( this . extraHeaders . hasOwnProperty ( i ) ) {
xhr . setRequestHeader ( i , this . extraHeaders [ i ] ) ;
}
}
}
} catch ( e ) { }
if ( this . supportsBinary ) {
// This has to be done after open because Firefox is stupid
// http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
xhr . responseType = 'arraybuffer' ;
}
if ( 'POST' === this . method ) {
try {
if ( this . isBinary ) {
xhr . setRequestHeader ( 'Content-type' , 'application/octet-stream' ) ;
} else {
xhr . setRequestHeader ( 'Content-type' , 'text/plain;charset=UTF-8' ) ;
}
} catch ( e ) { }
}
try {
xhr . setRequestHeader ( 'Accept' , '*/*' ) ;
} catch ( e ) { }
// ie6 check
if ( 'withCredentials' in xhr ) {
xhr . withCredentials = true ;
}
if ( this . requestTimeout ) {
xhr . timeout = this . requestTimeout ;
}
if ( this . hasXDR ( ) ) {
xhr . onload = function ( ) {
self . onLoad ( ) ;
} ;
xhr . onerror = function ( ) {
self . onError ( xhr . responseText ) ;
} ;
} else {
xhr . onreadystatechange = function ( ) {
if ( 4 !== xhr . readyState ) return ;
if ( 200 === xhr . status || 1223 === xhr . status ) {
self . onLoad ( ) ;
} else {
// make sure the `error` event handler that's user-set
// does not throw in the same tick and gets caught here
setTimeout ( function ( ) {
self . onError ( xhr . status ) ;
} , 0 ) ;
}
} ;
}
debug ( 'xhr data %s' , this . data ) ;
xhr . send ( this . data ) ;
} catch ( e ) {
// Need to defer since .create() is called directly fhrom the constructor
// and thus the 'error' event can only be only bound *after* this exception
// occurs. Therefore, also, we cannot throw here at all.
setTimeout ( function ( ) {
self . onError ( e ) ;
} , 0 ) ;
return ;
}
if ( global . document ) {
this . index = Request . requestsCount ++ ;
Request . requests [ this . index ] = this ;
}
} ;
/ * *
* Called upon successful response .
*
* @ api private
* /
Request . prototype . onSuccess = function ( ) {
this . emit ( 'success' ) ;
this . cleanup ( ) ;
} ;
/ * *
* Called if we have data .
*
* @ api private
* /
Request . prototype . onData = function ( data ) {
this . emit ( 'data' , data ) ;
this . onSuccess ( ) ;
} ;
/ * *
* Called upon error .
*
* @ api private
* /
Request . prototype . onError = function ( err ) {
this . emit ( 'error' , err ) ;
this . cleanup ( true ) ;
} ;
/ * *
* Cleans up house .
*
* @ api private
* /
Request . prototype . cleanup = function ( fromError ) {
if ( 'undefined' === typeof this . xhr || null === this . xhr ) {
return ;
}
// xmlhttprequest
if ( this . hasXDR ( ) ) {
this . xhr . onload = this . xhr . onerror = empty ;
} else {
this . xhr . onreadystatechange = empty ;
}
if ( fromError ) {
try {
this . xhr . abort ( ) ;
} catch ( e ) { }
}
if ( global . document ) {
delete Request . requests [ this . index ] ;
}
this . xhr = null ;
} ;
/ * *
* Called upon load .
*
* @ api private
* /
Request . prototype . onLoad = function ( ) {
var data ;
try {
var contentType ;
try {
contentType = this . xhr . getResponseHeader ( 'Content-Type' ) . split ( ';' ) [ 0 ] ;
} catch ( e ) { }
if ( contentType === 'application/octet-stream' ) {
data = this . xhr . response || this . xhr . responseText ;
} else {
if ( ! this . supportsBinary ) {
data = this . xhr . responseText ;
} else {
try {
data = String . fromCharCode . apply ( null , new Uint8Array ( this . xhr . response ) ) ;
} catch ( e ) {
var ui8Arr = new Uint8Array ( this . xhr . response ) ;
var dataArray = [ ] ;
for ( var idx = 0 , length = ui8Arr . length ; idx < length ; idx ++ ) {
dataArray . push ( ui8Arr [ idx ] ) ;
}
data = String . fromCharCode . apply ( null , dataArray ) ;
}
}
}
} catch ( e ) {
this . onError ( e ) ;
}
if ( null != data ) {
this . onData ( data ) ;
}
} ;
/ * *
* Check if it has XDomainRequest .
*
* @ api private
* /
Request . prototype . hasXDR = function ( ) {
return 'undefined' !== typeof global . XDomainRequest && ! this . xs && this . enablesXDR ;
} ;
/ * *
* Aborts the request .
*
* @ api public
* /
Request . prototype . abort = function ( ) {
this . cleanup ( ) ;
} ;
/ * *
* Aborts pending requests when unloading the window . This is needed to prevent
* memory leaks ( e . g . when using IE ) and to ensure that no spurious error is
* emitted .
* /
Request . requestsCount = 0 ;
Request . requests = { } ;
if ( global . document ) {
if ( global . attachEvent ) {
global . attachEvent ( 'onunload' , unloadHandler ) ;
} else if ( global . addEventListener ) {
global . addEventListener ( 'beforeunload' , unloadHandler , false ) ;
}
}
function unloadHandler ( ) {
for ( var i in Request . requests ) {
if ( Request . requests . hasOwnProperty ( i ) ) {
Request . requests [ i ] . abort ( ) ;
}
}
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./polling" : 25 , "component-emitter" : 28 , "component-inherit" : 14 , "debug" : 29 , "xmlhttprequest-ssl" : 27 } ] , 25 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var Transport = require ( '../transport' ) ;
var parseqs = require ( 'parseqs' ) ;
var parser = require ( 'engine.io-parser' ) ;
var inherit = require ( 'component-inherit' ) ;
var yeast = require ( 'yeast' ) ;
var debug = require ( 'debug' ) ( 'engine.io-client:polling' ) ;
/ * *
* Module exports .
* /
module . exports = Polling ;
/ * *
* Is XHR2 supported ?
* /
var hasXHR2 = ( function ( ) {
var XMLHttpRequest = require ( 'xmlhttprequest-ssl' ) ;
var xhr = new XMLHttpRequest ( { xdomain : false } ) ;
return null != xhr . responseType ;
} ) ( ) ;
/ * *
* Polling interface .
*
* @ param { Object } opts
* @ api private
* /
function Polling ( opts ) {
var forceBase64 = ( opts && opts . forceBase64 ) ;
if ( ! hasXHR2 || forceBase64 ) {
this . supportsBinary = false ;
}
Transport . call ( this , opts ) ;
}
/ * *
* Inherits from Transport .
* /
inherit ( Polling , Transport ) ;
/ * *
* Transport name .
* /
Polling . prototype . name = 'polling' ;
/ * *
* Opens the socket ( triggers polling ) . We write a PING message to determine
* when the transport is open .
*
* @ api private
* /
Polling . prototype . doOpen = function ( ) {
this . poll ( ) ;
} ;
/ * *
* Pauses polling .
*
* @ param { Function } callback upon buffers are flushed and transport is paused
* @ api private
* /
Polling . prototype . pause = function ( onPause ) {
var self = this ;
this . readyState = 'pausing' ;
function pause ( ) {
debug ( 'paused' ) ;
self . readyState = 'paused' ;
onPause ( ) ;
}
if ( this . polling || ! this . writable ) {
var total = 0 ;
if ( this . polling ) {
debug ( 'we are currently polling - waiting to pause' ) ;
total ++ ;
this . once ( 'pollComplete' , function ( ) {
debug ( 'pre-pause polling complete' ) ;
-- total || pause ( ) ;
} ) ;
}
if ( ! this . writable ) {
debug ( 'we are currently writing - waiting to pause' ) ;
total ++ ;
this . once ( 'drain' , function ( ) {
debug ( 'pre-pause writing complete' ) ;
-- total || pause ( ) ;
} ) ;
}
} else {
pause ( ) ;
}
} ;
/ * *
* Starts polling cycle .
*
* @ api public
* /
Polling . prototype . poll = function ( ) {
debug ( 'polling' ) ;
this . polling = true ;
this . doPoll ( ) ;
this . emit ( 'poll' ) ;
} ;
/ * *
* Overloads onData to detect payloads .
*
* @ api private
* /
Polling . prototype . onData = function ( data ) {
var self = this ;
debug ( 'polling got data %s' , data ) ;
var callback = function ( packet , index , total ) {
// if its the first message we consider the transport open
if ( 'opening' === self . readyState ) {
self . onOpen ( ) ;
}
// if its a close packet, we close the ongoing requests
if ( 'close' === packet . type ) {
self . onClose ( ) ;
return false ;
}
// otherwise bypass onData and handle the message
self . onPacket ( packet ) ;
} ;
// decode payload
parser . decodePayload ( data , this . socket . binaryType , callback ) ;
// if an event did not trigger closing
if ( 'closed' !== this . readyState ) {
// if we got data we're not polling
this . polling = false ;
this . emit ( 'pollComplete' ) ;
if ( 'open' === this . readyState ) {
this . poll ( ) ;
} else {
debug ( 'ignoring poll - transport state "%s"' , this . readyState ) ;
}
}
} ;
/ * *
* For polling , send a close packet .
*
* @ api private
* /
Polling . prototype . doClose = function ( ) {
var self = this ;
function close ( ) {
debug ( 'writing close packet' ) ;
self . write ( [ { type : 'close' } ] ) ;
}
if ( 'open' === this . readyState ) {
debug ( 'transport open - closing' ) ;
close ( ) ;
} else {
// in case we're trying to close while
// handshaking is in progress (GH-164)
debug ( 'transport not open - deferring close' ) ;
this . once ( 'open' , close ) ;
}
} ;
/ * *
* Writes a packets payload .
*
* @ param { Array } data packets
* @ param { Function } drain callback
* @ api private
* /
Polling . prototype . write = function ( packets ) {
var self = this ;
this . writable = false ;
var callbackfn = function ( ) {
self . writable = true ;
self . emit ( 'drain' ) ;
} ;
parser . encodePayload ( packets , this . supportsBinary , function ( data ) {
self . doWrite ( data , callbackfn ) ;
} ) ;
} ;
/ * *
* Generates uri for connection .
*
* @ api private
* /
Polling . prototype . uri = function ( ) {
var query = this . query || { } ;
var schema = this . secure ? 'https' : 'http' ;
var port = '' ;
// cache busting is forced
if ( false !== this . timestampRequests ) {
query [ this . timestampParam ] = yeast ( ) ;
}
if ( ! this . supportsBinary && ! query . sid ) {
query . b64 = 1 ;
}
query = parseqs . encode ( query ) ;
// avoid port if default for schema
if ( this . port && ( ( 'https' === schema && Number ( this . port ) !== 443 ) ||
( 'http' === schema && Number ( this . port ) !== 80 ) ) ) {
port = ':' + this . port ;
}
// prepend ? to query
if ( query . length ) {
query = '?' + query ;
}
var ipv6 = this . hostname . indexOf ( ':' ) !== - 1 ;
return schema + '://' + ( ipv6 ? '[' + this . hostname + ']' : this . hostname ) + port + this . path + query ;
} ;
2017-02-25 23:25:06 -05:00
} , { "../transport" : 21 , "component-inherit" : 14 , "debug" : 29 , "engine.io-parser" : 31 , "parseqs" : 40 , "xmlhttprequest-ssl" : 27 , "yeast" : 55 } ] , 26 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module dependencies .
* /
var Transport = require ( '../transport' ) ;
var parser = require ( 'engine.io-parser' ) ;
var parseqs = require ( 'parseqs' ) ;
var inherit = require ( 'component-inherit' ) ;
var yeast = require ( 'yeast' ) ;
var debug = require ( 'debug' ) ( 'engine.io-client:websocket' ) ;
var BrowserWebSocket = global . WebSocket || global . MozWebSocket ;
var NodeWebSocket ;
if ( typeof window === 'undefined' ) {
try {
NodeWebSocket = require ( 'ws' ) ;
} catch ( e ) { }
}
/ * *
* Get either the ` WebSocket ` or ` MozWebSocket ` globals
* in the browser or try to resolve WebSocket - compatible
* interface exposed by ` ws ` for Node - like environment .
* /
var WebSocket = BrowserWebSocket ;
if ( ! WebSocket && typeof window === 'undefined' ) {
WebSocket = NodeWebSocket ;
}
/ * *
* Module exports .
* /
module . exports = WS ;
/ * *
* WebSocket transport constructor .
*
* @ api { Object } connection options
* @ api public
* /
function WS ( opts ) {
var forceBase64 = ( opts && opts . forceBase64 ) ;
if ( forceBase64 ) {
this . supportsBinary = false ;
}
this . perMessageDeflate = opts . perMessageDeflate ;
this . usingBrowserWebSocket = BrowserWebSocket && ! opts . forceNode ;
if ( ! this . usingBrowserWebSocket ) {
WebSocket = NodeWebSocket ;
}
Transport . call ( this , opts ) ;
}
/ * *
* Inherits from Transport .
* /
inherit ( WS , Transport ) ;
/ * *
* Transport name .
*
* @ api public
* /
WS . prototype . name = 'websocket' ;
/ *
* WebSockets support binary
* /
WS . prototype . supportsBinary = true ;
/ * *
* Opens socket .
*
* @ api private
* /
WS . prototype . doOpen = function ( ) {
if ( ! this . check ( ) ) {
// let probe timeout
return ;
}
var uri = this . uri ( ) ;
var protocols = void ( 0 ) ;
var opts = {
agent : this . agent ,
perMessageDeflate : this . perMessageDeflate
} ;
// SSL options for Node.js client
opts . pfx = this . pfx ;
opts . key = this . key ;
opts . passphrase = this . passphrase ;
opts . cert = this . cert ;
opts . ca = this . ca ;
opts . ciphers = this . ciphers ;
opts . rejectUnauthorized = this . rejectUnauthorized ;
if ( this . extraHeaders ) {
opts . headers = this . extraHeaders ;
}
if ( this . localAddress ) {
opts . localAddress = this . localAddress ;
}
try {
this . ws = this . usingBrowserWebSocket ? new WebSocket ( uri ) : new WebSocket ( uri , protocols , opts ) ;
} catch ( err ) {
return this . emit ( 'error' , err ) ;
}
if ( this . ws . binaryType === undefined ) {
this . supportsBinary = false ;
}
if ( this . ws . supports && this . ws . supports . binary ) {
this . supportsBinary = true ;
this . ws . binaryType = 'nodebuffer' ;
} else {
this . ws . binaryType = 'arraybuffer' ;
}
this . addEventListeners ( ) ;
} ;
/ * *
* Adds event listeners to the socket
*
* @ api private
* /
WS . prototype . addEventListeners = function ( ) {
var self = this ;
this . ws . onopen = function ( ) {
self . onOpen ( ) ;
} ;
this . ws . onclose = function ( ) {
self . onClose ( ) ;
} ;
this . ws . onmessage = function ( ev ) {
self . onData ( ev . data ) ;
} ;
this . ws . onerror = function ( e ) {
self . onError ( 'websocket error' , e ) ;
} ;
} ;
/ * *
* Writes data to socket .
*
* @ param { Array } array of packets .
* @ api private
* /
WS . prototype . write = function ( packets ) {
var self = this ;
this . writable = false ;
// encodePacket efficient as it uses WS framing
// no need for encodePayload
var total = packets . length ;
for ( var i = 0 , l = total ; i < l ; i ++ ) {
( function ( packet ) {
parser . encodePacket ( packet , self . supportsBinary , function ( data ) {
if ( ! self . usingBrowserWebSocket ) {
// always create a new object (GH-437)
var opts = { } ;
if ( packet . options ) {
opts . compress = packet . options . compress ;
}
if ( self . perMessageDeflate ) {
var len = 'string' === typeof data ? global . Buffer . byteLength ( data ) : data . length ;
if ( len < self . perMessageDeflate . threshold ) {
opts . compress = false ;
}
}
}
// Sometimes the websocket has already been closed but the browser didn't
// have a chance of informing us about it yet, in that case send will
// throw an error
try {
if ( self . usingBrowserWebSocket ) {
// TypeError is thrown when passing the second argument on Safari
self . ws . send ( data ) ;
} else {
self . ws . send ( data , opts ) ;
}
} catch ( e ) {
debug ( 'websocket closed before onclose event' ) ;
}
-- total || done ( ) ;
} ) ;
} ) ( packets [ i ] ) ;
}
function done ( ) {
self . emit ( 'flush' ) ;
// fake drain
// defer to next tick to allow Socket to clear writeBuffer
setTimeout ( function ( ) {
self . writable = true ;
self . emit ( 'drain' ) ;
} , 0 ) ;
}
} ;
/ * *
* Called upon close
*
* @ api private
* /
WS . prototype . onClose = function ( ) {
Transport . prototype . onClose . call ( this ) ;
} ;
/ * *
* Closes socket .
*
* @ api private
* /
WS . prototype . doClose = function ( ) {
if ( typeof this . ws !== 'undefined' ) {
this . ws . close ( ) ;
}
} ;
/ * *
* Generates uri for connection .
*
* @ api private
* /
WS . prototype . uri = function ( ) {
var query = this . query || { } ;
var schema = this . secure ? 'wss' : 'ws' ;
var port = '' ;
// avoid port if default for schema
if ( this . port && ( ( 'wss' === schema && Number ( this . port ) !== 443 ) ||
( 'ws' === schema && Number ( this . port ) !== 80 ) ) ) {
port = ':' + this . port ;
}
// append timestamp to URI
if ( this . timestampRequests ) {
query [ this . timestampParam ] = yeast ( ) ;
}
// communicate binary support capabilities
if ( ! this . supportsBinary ) {
query . b64 = 1 ;
}
query = parseqs . encode ( query ) ;
// prepend ? to query
if ( query . length ) {
query = '?' + query ;
}
var ipv6 = this . hostname . indexOf ( ':' ) !== - 1 ;
return schema + '://' + ( ipv6 ? '[' + this . hostname + ']' : this . hostname ) + port + this . path + query ;
} ;
/ * *
* Feature detection for WebSocket .
*
* @ return { Boolean } whether this transport is available .
* @ api public
* /
WS . prototype . check = function ( ) {
return ! ! WebSocket && ! ( '__initialize' in WebSocket && this . name === WS . prototype . name ) ;
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "../transport" : 21 , "component-inherit" : 14 , "debug" : 29 , "engine.io-parser" : 31 , "parseqs" : 40 , "ws" : 58 , "yeast" : 55 } ] , 27 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
// browser shim for xmlhttprequest module
var hasCORS = require ( 'has-cors' ) ;
module . exports = function ( opts ) {
var xdomain = opts . xdomain ;
// scheme must be same when usign XDomainRequest
// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
var xscheme = opts . xscheme ;
// XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
// https://github.com/Automattic/engine.io-client/pull/217
var enablesXDR = opts . enablesXDR ;
// XMLHttpRequest can be disabled on IE
try {
if ( 'undefined' !== typeof XMLHttpRequest && ( ! xdomain || hasCORS ) ) {
return new XMLHttpRequest ( ) ;
}
} catch ( e ) { }
// Use XDomainRequest for IE8 if enablesXDR is true
// because loading bar keeps flashing when using jsonp-polling
// https://github.com/yujiosaka/socke.io-ie8-loading-example
try {
if ( 'undefined' !== typeof XDomainRequest && ! xscheme && enablesXDR ) {
return new XDomainRequest ( ) ;
}
} catch ( e ) { }
if ( ! xdomain ) {
try {
return new global [ [ 'Active' ] . concat ( 'Object' ) . join ( 'X' ) ] ( 'Microsoft.XMLHTTP' ) ;
} catch ( e ) { }
}
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "has-cors" : 34 } ] , 28 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Expose ` Emitter ` .
* /
if ( typeof module !== 'undefined' ) {
module . exports = Emitter ;
}
/ * *
* Initialize a new ` Emitter ` .
*
* @ api public
* /
function Emitter ( obj ) {
if ( obj ) return mixin ( obj ) ;
} ;
/ * *
* Mixin the emitter properties .
*
* @ param { Object } obj
* @ return { Object }
* @ api private
* /
function mixin ( obj ) {
for ( var key in Emitter . prototype ) {
obj [ key ] = Emitter . prototype [ key ] ;
}
return obj ;
}
/ * *
* Listen on the given ` event ` with ` fn ` .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . on =
Emitter . prototype . addEventListener = function ( event , fn ) {
this . _callbacks = this . _callbacks || { } ;
( this . _callbacks [ '$' + event ] = this . _callbacks [ '$' + event ] || [ ] )
. push ( fn ) ;
return this ;
} ;
/ * *
* Adds an ` event ` listener that will be invoked a single
* time then automatically removed .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . once = function ( event , fn ) {
function on ( ) {
this . off ( event , on ) ;
fn . apply ( this , arguments ) ;
}
on . fn = fn ;
this . on ( event , on ) ;
return this ;
} ;
/ * *
* Remove the given callback for ` event ` or all
* registered callbacks .
*
* @ param { String } event
* @ param { Function } fn
* @ return { Emitter }
* @ api public
* /
Emitter . prototype . off =
Emitter . prototype . removeListener =
Emitter . prototype . removeAllListeners =
Emitter . prototype . removeEventListener = function ( event , fn ) {
this . _callbacks = this . _callbacks || { } ;
// all
if ( 0 == arguments . length ) {
this . _callbacks = { } ;
return this ;
}
// specific event
var callbacks = this . _callbacks [ '$' + event ] ;
if ( ! callbacks ) return this ;
// remove all handlers
if ( 1 == arguments . length ) {
delete this . _callbacks [ '$' + event ] ;
return this ;
}
// remove specific handler
var cb ;
for ( var i = 0 ; i < callbacks . length ; i ++ ) {
cb = callbacks [ i ] ;
if ( cb === fn || cb . fn === fn ) {
callbacks . splice ( i , 1 ) ;
break ;
}
}
return this ;
} ;
/ * *
* Emit ` event ` with the given args .
*
* @ param { String } event
* @ param { Mixed } ...
* @ return { Emitter }
* /
Emitter . prototype . emit = function ( event ) {
this . _callbacks = this . _callbacks || { } ;
var args = [ ] . slice . call ( arguments , 1 )
, callbacks = this . _callbacks [ '$' + event ] ;
if ( callbacks ) {
callbacks = callbacks . slice ( 0 ) ;
for ( var i = 0 , len = callbacks . length ; i < len ; ++ i ) {
callbacks [ i ] . apply ( this , args ) ;
}
}
return this ;
} ;
/ * *
* Return array of callbacks for ` event ` .
*
* @ param { String } event
* @ return { Array }
* @ api public
* /
Emitter . prototype . listeners = function ( event ) {
this . _callbacks = this . _callbacks || { } ;
return this . _callbacks [ '$' + event ] || [ ] ;
} ;
/ * *
* Check if this emitter has ` event ` handlers .
*
* @ param { String } event
* @ return { Boolean }
* @ api public
* /
Emitter . prototype . hasListeners = function ( event ) {
return ! ! this . listeners ( event ) . length ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 29 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( process ) {
/ * *
* This is the web browser implementation of ` debug() ` .
*
* Expose ` debug() ` as the module .
* /
exports = module . exports = require ( './debug' ) ;
exports . log = log ;
exports . formatArgs = formatArgs ;
exports . save = save ;
exports . load = load ;
exports . useColors = useColors ;
exports . storage = 'undefined' != typeof chrome
&& 'undefined' != typeof chrome . storage
? chrome . storage . local
: localstorage ( ) ;
/ * *
* Colors .
* /
exports . colors = [
'lightseagreen' ,
'forestgreen' ,
'goldenrod' ,
'dodgerblue' ,
'darkorchid' ,
'crimson'
] ;
/ * *
* Currently only WebKit - based Web Inspectors , Firefox >= v31 ,
* and the Firebug extension ( any Firefox version ) are known
* to support "%c" CSS customizations .
*
* TODO : add a ` localStorage ` variable to explicitly enable / disable colors
* /
function useColors ( ) {
// is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
return ( typeof document !== 'undefined' && 'WebkitAppearance' in document . documentElement . style ) ||
// is firebug? http://stackoverflow.com/a/398120/376773
( window . console && ( console . firebug || ( console . exception && console . table ) ) ) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
( navigator . userAgent . toLowerCase ( ) . match ( /firefox\/(\d+)/ ) && parseInt ( RegExp . $1 , 10 ) >= 31 ) ;
}
/ * *
* Map % j to ` JSON.stringify() ` , since no Web Inspectors do that by default .
* /
exports . formatters . j = function ( v ) {
try {
return JSON . stringify ( v ) ;
} catch ( err ) {
return '[UnexpectedJSONParseError]: ' + err . message ;
}
} ;
/ * *
* Colorize log arguments if enabled .
*
* @ api public
* /
function formatArgs ( ) {
var args = arguments ;
var useColors = this . useColors ;
args [ 0 ] = ( useColors ? '%c' : '' )
+ this . namespace
+ ( useColors ? ' %c' : ' ' )
+ args [ 0 ]
+ ( useColors ? '%c ' : ' ' )
+ '+' + exports . humanize ( this . diff ) ;
if ( ! useColors ) return args ;
var c = 'color: ' + this . color ;
args = [ args [ 0 ] , c , 'color: inherit' ] . concat ( Array . prototype . slice . call ( args , 1 ) ) ;
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
var index = 0 ;
var lastC = 0 ;
args [ 0 ] . replace ( /%[a-z%]/g , function ( match ) {
if ( '%%' === match ) return ;
index ++ ;
if ( '%c' === match ) {
// we only are interested in the *last* %c
// (the user may have provided their own)
lastC = index ;
}
} ) ;
args . splice ( lastC , 0 , c ) ;
return args ;
}
/ * *
* Invokes ` console.log() ` when available .
* No - op when ` console.log ` is not a "function" .
*
* @ api public
* /
function log ( ) {
// this hackery is required for IE8/9, where
// the `console.log` function doesn't have 'apply'
return 'object' === typeof console
&& console . log
&& Function . prototype . apply . call ( console . log , console , arguments ) ;
}
/ * *
* Save ` namespaces ` .
*
* @ param { String } namespaces
* @ api private
* /
function save ( namespaces ) {
try {
if ( null == namespaces ) {
exports . storage . removeItem ( 'debug' ) ;
} else {
exports . storage . debug = namespaces ;
}
} catch ( e ) { }
}
/ * *
* Load ` namespaces ` .
*
* @ return { String } returns the previously persisted debug modes
* @ api private
* /
function load ( ) {
var r ;
try {
return exports . storage . debug ;
} catch ( e ) { }
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
if ( typeof process !== 'undefined' && 'env' in process ) {
return process . env . DEBUG ;
}
}
/ * *
* Enable namespaces listed in ` localStorage.debug ` initially .
* /
exports . enable ( load ( ) ) ;
/ * *
* Localstorage attempts to return the localstorage .
*
* This is necessary because safari throws
* when a user disables cookies / localstorage
* and you attempt to access it .
*
* @ return { LocalStorage }
* @ api private
* /
function localstorage ( ) {
try {
return window . localStorage ;
} catch ( e ) { }
}
} ) . call ( this , require ( '_process' ) )
2017-02-25 23:25:06 -05:00
} , { "./debug" : 30 , "_process" : 59 } ] , 30 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* This is the common logic for both the Node . js and web browser
* implementations of ` debug() ` .
*
* Expose ` debug() ` as the module .
* /
exports = module . exports = debug . debug = debug ;
exports . coerce = coerce ;
exports . disable = disable ;
exports . enable = enable ;
exports . enabled = enabled ;
exports . humanize = require ( 'ms' ) ;
/ * *
* The currently active debug mode names , and names to skip .
* /
exports . names = [ ] ;
exports . skips = [ ] ;
/ * *
* Map of special "%n" handling functions , for the debug "format" argument .
*
* Valid key names are a single , lowercased letter , i . e . "n" .
* /
exports . formatters = { } ;
/ * *
* Previously assigned color .
* /
var prevColor = 0 ;
/ * *
* Previous log timestamp .
* /
var prevTime ;
/ * *
* Select a color .
*
* @ return { Number }
* @ api private
* /
function selectColor ( ) {
return exports . colors [ prevColor ++ % exports . colors . length ] ;
}
/ * *
* Create a debugger with the given ` namespace ` .
*
* @ param { String } namespace
* @ return { Function }
* @ api public
* /
function debug ( namespace ) {
// define the `disabled` version
function disabled ( ) {
}
disabled . enabled = false ;
// define the `enabled` version
function enabled ( ) {
var self = enabled ;
// set `diff` timestamp
var curr = + new Date ( ) ;
var ms = curr - ( prevTime || curr ) ;
self . diff = ms ;
self . prev = prevTime ;
self . curr = curr ;
prevTime = curr ;
// add the `color` if not set
if ( null == self . useColors ) self . useColors = exports . useColors ( ) ;
if ( null == self . color && self . useColors ) self . color = selectColor ( ) ;
var args = new Array ( arguments . length ) ;
for ( var i = 0 ; i < args . length ; i ++ ) {
args [ i ] = arguments [ i ] ;
}
args [ 0 ] = exports . coerce ( args [ 0 ] ) ;
if ( 'string' !== typeof args [ 0 ] ) {
// anything else let's inspect with %o
args = [ '%o' ] . concat ( args ) ;
}
// apply any `formatters` transformations
var index = 0 ;
args [ 0 ] = args [ 0 ] . replace ( /%([a-z%])/g , function ( match , format ) {
// if we encounter an escaped % then don't increase the array index
if ( match === '%%' ) return match ;
index ++ ;
var formatter = exports . formatters [ format ] ;
if ( 'function' === typeof formatter ) {
var val = args [ index ] ;
match = formatter . call ( self , val ) ;
// now we need to remove `args[index]` since it's inlined in the `format`
args . splice ( index , 1 ) ;
index -- ;
}
return match ;
} ) ;
// apply env-specific formatting
args = exports . formatArgs . apply ( self , args ) ;
var logFn = enabled . log || exports . log || console . log . bind ( console ) ;
logFn . apply ( self , args ) ;
}
enabled . enabled = true ;
var fn = exports . enabled ( namespace ) ? enabled : disabled ;
fn . namespace = namespace ;
return fn ;
}
/ * *
* Enables a debug mode by namespaces . This can include modes
* separated by a colon and wildcards .
*
* @ param { String } namespaces
* @ api public
* /
function enable ( namespaces ) {
exports . save ( namespaces ) ;
var split = ( namespaces || '' ) . split ( /[\s,]+/ ) ;
var len = split . length ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( ! split [ i ] ) continue ; // ignore empty strings
namespaces = split [ i ] . replace ( /[\\^$+?.()|[\]{}]/g , '\\$&' ) . replace ( /\*/g , '.*?' ) ;
if ( namespaces [ 0 ] === '-' ) {
exports . skips . push ( new RegExp ( '^' + namespaces . substr ( 1 ) + '$' ) ) ;
} else {
exports . names . push ( new RegExp ( '^' + namespaces + '$' ) ) ;
}
}
}
/ * *
* Disable debug output .
*
* @ api public
* /
function disable ( ) {
exports . enable ( '' ) ;
}
/ * *
* Returns true if the given mode name is enabled , false otherwise .
*
* @ param { String } name
* @ return { Boolean }
* @ api public
* /
function enabled ( name ) {
var i , len ;
for ( i = 0 , len = exports . skips . length ; i < len ; i ++ ) {
if ( exports . skips [ i ] . test ( name ) ) {
return false ;
}
}
for ( i = 0 , len = exports . names . length ; i < len ; i ++ ) {
if ( exports . names [ i ] . test ( name ) ) {
return true ;
}
}
return false ;
}
/ * *
* Coerce ` val ` .
*
* @ param { Mixed } val
* @ return { Mixed }
* @ api private
* /
function coerce ( val ) {
if ( val instanceof Error ) return val . stack || val . message ;
return val ;
}
2017-02-25 23:25:06 -05:00
} , { "ms" : 38 } ] , 31 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module dependencies .
* /
var keys = require ( './keys' ) ;
var hasBinary = require ( 'has-binary' ) ;
var sliceBuffer = require ( 'arraybuffer.slice' ) ;
var after = require ( 'after' ) ;
var utf8 = require ( 'wtf-8' ) ;
var base64encoder ;
if ( global && global . ArrayBuffer ) {
base64encoder = require ( 'base64-arraybuffer' ) ;
}
/ * *
* Check if we are running an android browser . That requires us to use
* ArrayBuffer with polling transports ...
*
* http : //ghinda.net/jpeg-blob-ajax-android/
* /
var isAndroid = typeof navigator !== 'undefined' && /Android/i . test ( navigator . userAgent ) ;
/ * *
* Check if we are running in PhantomJS .
* Uploading a Blob with PhantomJS does not work correctly , as reported here :
* https : //github.com/ariya/phantomjs/issues/11395
* @ type boolean
* /
var isPhantomJS = typeof navigator !== 'undefined' && /PhantomJS/i . test ( navigator . userAgent ) ;
/ * *
* When true , avoids using Blobs to encode payloads .
* @ type boolean
* /
var dontSendBlobs = isAndroid || isPhantomJS ;
/ * *
* Current protocol version .
* /
exports . protocol = 3 ;
/ * *
* Packet types .
* /
var packets = exports . packets = {
open : 0 // non-ws
, close : 1 // non-ws
, ping : 2
, pong : 3
, message : 4
, upgrade : 5
, noop : 6
} ;
var packetslist = keys ( packets ) ;
/ * *
* Premade error packet .
* /
var err = { type : 'error' , data : 'parser error' } ;
/ * *
* Create a blob api even for blob builder when vendor prefixes exist
* /
var Blob = require ( 'blob' ) ;
/ * *
* Encodes a packet .
*
* < packet type id > [ < data > ]
*
* Example :
*
* 5 hello world
* 3
* 4
*
* Binary is encoded in an identical principle
*
* @ api private
* /
exports . encodePacket = function ( packet , supportsBinary , utf8encode , callback ) {
if ( 'function' == typeof supportsBinary ) {
callback = supportsBinary ;
supportsBinary = false ;
}
if ( 'function' == typeof utf8encode ) {
callback = utf8encode ;
utf8encode = null ;
}
var data = ( packet . data === undefined )
? undefined
: packet . data . buffer || packet . data ;
if ( global . ArrayBuffer && data instanceof ArrayBuffer ) {
return encodeArrayBuffer ( packet , supportsBinary , callback ) ;
} else if ( Blob && data instanceof global . Blob ) {
return encodeBlob ( packet , supportsBinary , callback ) ;
}
// might be an object with { base64: true, data: dataAsBase64String }
if ( data && data . base64 ) {
return encodeBase64Object ( packet , callback ) ;
}
// Sending data as a utf-8 string
var encoded = packets [ packet . type ] ;
// data fragment is optional
if ( undefined !== packet . data ) {
encoded += utf8encode ? utf8 . encode ( String ( packet . data ) ) : String ( packet . data ) ;
}
return callback ( '' + encoded ) ;
} ;
function encodeBase64Object ( packet , callback ) {
// packet data is an object { base64: true, data: dataAsBase64String }
var message = 'b' + exports . packets [ packet . type ] + packet . data . data ;
return callback ( message ) ;
}
/ * *
* Encode packet helpers for binary types
* /
function encodeArrayBuffer ( packet , supportsBinary , callback ) {
if ( ! supportsBinary ) {
return exports . encodeBase64Packet ( packet , callback ) ;
}
var data = packet . data ;
var contentArray = new Uint8Array ( data ) ;
var resultBuffer = new Uint8Array ( 1 + data . byteLength ) ;
resultBuffer [ 0 ] = packets [ packet . type ] ;
for ( var i = 0 ; i < contentArray . length ; i ++ ) {
resultBuffer [ i + 1 ] = contentArray [ i ] ;
}
return callback ( resultBuffer . buffer ) ;
}
function encodeBlobAsArrayBuffer ( packet , supportsBinary , callback ) {
if ( ! supportsBinary ) {
return exports . encodeBase64Packet ( packet , callback ) ;
}
var fr = new FileReader ( ) ;
fr . onload = function ( ) {
packet . data = fr . result ;
exports . encodePacket ( packet , supportsBinary , true , callback ) ;
} ;
return fr . readAsArrayBuffer ( packet . data ) ;
}
function encodeBlob ( packet , supportsBinary , callback ) {
if ( ! supportsBinary ) {
return exports . encodeBase64Packet ( packet , callback ) ;
}
if ( dontSendBlobs ) {
return encodeBlobAsArrayBuffer ( packet , supportsBinary , callback ) ;
}
var length = new Uint8Array ( 1 ) ;
length [ 0 ] = packets [ packet . type ] ;
var blob = new Blob ( [ length . buffer , packet . data ] ) ;
return callback ( blob ) ;
}
/ * *
* Encodes a packet with binary data in a base64 string
*
* @ param { Object } packet , has ` type ` and ` data `
* @ return { String } base64 encoded message
* /
exports . encodeBase64Packet = function ( packet , callback ) {
var message = 'b' + exports . packets [ packet . type ] ;
if ( Blob && packet . data instanceof global . Blob ) {
var fr = new FileReader ( ) ;
fr . onload = function ( ) {
var b64 = fr . result . split ( ',' ) [ 1 ] ;
callback ( message + b64 ) ;
} ;
return fr . readAsDataURL ( packet . data ) ;
}
var b64data ;
try {
b64data = String . fromCharCode . apply ( null , new Uint8Array ( packet . data ) ) ;
} catch ( e ) {
// iPhone Safari doesn't let you apply with typed arrays
var typed = new Uint8Array ( packet . data ) ;
var basic = new Array ( typed . length ) ;
for ( var i = 0 ; i < typed . length ; i ++ ) {
basic [ i ] = typed [ i ] ;
}
b64data = String . fromCharCode . apply ( null , basic ) ;
}
message += global . btoa ( b64data ) ;
return callback ( message ) ;
} ;
/ * *
* Decodes a packet . Changes format to Blob if requested .
*
* @ return { Object } with ` type ` and ` data ` ( if any )
* @ api private
* /
exports . decodePacket = function ( data , binaryType , utf8decode ) {
if ( data === undefined ) {
return err ;
}
// String data
if ( typeof data == 'string' ) {
if ( data . charAt ( 0 ) == 'b' ) {
return exports . decodeBase64Packet ( data . substr ( 1 ) , binaryType ) ;
}
if ( utf8decode ) {
data = tryDecode ( data ) ;
if ( data === false ) {
return err ;
}
}
var type = data . charAt ( 0 ) ;
if ( Number ( type ) != type || ! packetslist [ type ] ) {
return err ;
}
if ( data . length > 1 ) {
return { type : packetslist [ type ] , data : data . substring ( 1 ) } ;
} else {
return { type : packetslist [ type ] } ;
}
}
var asArray = new Uint8Array ( data ) ;
var type = asArray [ 0 ] ;
var rest = sliceBuffer ( data , 1 ) ;
if ( Blob && binaryType === 'blob' ) {
rest = new Blob ( [ rest ] ) ;
}
return { type : packetslist [ type ] , data : rest } ;
} ;
function tryDecode ( data ) {
try {
data = utf8 . decode ( data ) ;
} catch ( e ) {
return false ;
}
return data ;
}
/ * *
* Decodes a packet encoded in a base64 string
*
* @ param { String } base64 encoded message
* @ return { Object } with ` type ` and ` data ` ( if any )
* /
exports . decodeBase64Packet = function ( msg , binaryType ) {
var type = packetslist [ msg . charAt ( 0 ) ] ;
if ( ! base64encoder ) {
return { type : type , data : { base64 : true , data : msg . substr ( 1 ) } } ;
}
var data = base64encoder . decode ( msg . substr ( 1 ) ) ;
if ( binaryType === 'blob' && Blob ) {
data = new Blob ( [ data ] ) ;
}
return { type : type , data : data } ;
} ;
/ * *
* Encodes multiple messages ( payload ) .
*
* < length > : data
*
* Example :
*
* 11 : hello world2 : hi
*
* If any contents are binary , they will be encoded as base64 strings . Base64
* encoded strings are marked with a b before the length specifier
*
* @ param { Array } packets
* @ api private
* /
exports . encodePayload = function ( packets , supportsBinary , callback ) {
if ( typeof supportsBinary == 'function' ) {
callback = supportsBinary ;
supportsBinary = null ;
}
var isBinary = hasBinary ( packets ) ;
if ( supportsBinary && isBinary ) {
if ( Blob && ! dontSendBlobs ) {
return exports . encodePayloadAsBlob ( packets , callback ) ;
}
return exports . encodePayloadAsArrayBuffer ( packets , callback ) ;
}
if ( ! packets . length ) {
return callback ( '0:' ) ;
}
function setLengthHeader ( message ) {
return message . length + ':' + message ;
}
function encodeOne ( packet , doneCallback ) {
exports . encodePacket ( packet , ! isBinary ? false : supportsBinary , true , function ( message ) {
doneCallback ( null , setLengthHeader ( message ) ) ;
} ) ;
}
map ( packets , encodeOne , function ( err , results ) {
return callback ( results . join ( '' ) ) ;
} ) ;
} ;
/ * *
* Async array map using after
* /
function map ( ary , each , done ) {
var result = new Array ( ary . length ) ;
var next = after ( ary . length , done ) ;
var eachWithIndex = function ( i , el , cb ) {
each ( el , function ( error , msg ) {
result [ i ] = msg ;
cb ( error , result ) ;
} ) ;
} ;
for ( var i = 0 ; i < ary . length ; i ++ ) {
eachWithIndex ( i , ary [ i ] , next ) ;
}
}
/ *
* Decodes data when a payload is maybe expected . Possible binary contents are
* decoded from their base64 representation
*
* @ param { String } data , callback method
* @ api public
* /
exports . decodePayload = function ( data , binaryType , callback ) {
if ( typeof data != 'string' ) {
return exports . decodePayloadAsBinary ( data , binaryType , callback ) ;
}
if ( typeof binaryType === 'function' ) {
callback = binaryType ;
binaryType = null ;
}
var packet ;
if ( data == '' ) {
// parser error - ignoring payload
return callback ( err , 0 , 1 ) ;
}
var length = ''
, n , msg ;
for ( var i = 0 , l = data . length ; i < l ; i ++ ) {
var chr = data . charAt ( i ) ;
if ( ':' != chr ) {
length += chr ;
} else {
if ( '' == length || ( length != ( n = Number ( length ) ) ) ) {
// parser error - ignoring payload
return callback ( err , 0 , 1 ) ;
}
msg = data . substr ( i + 1 , n ) ;
if ( length != msg . length ) {
// parser error - ignoring payload
return callback ( err , 0 , 1 ) ;
}
if ( msg . length ) {
packet = exports . decodePacket ( msg , binaryType , true ) ;
if ( err . type == packet . type && err . data == packet . data ) {
// parser error in individual packet - ignoring payload
return callback ( err , 0 , 1 ) ;
}
var ret = callback ( packet , i + n , l ) ;
if ( false === ret ) return ;
}
// advance cursor
i += n ;
length = '' ;
}
}
if ( length != '' ) {
// parser error - ignoring payload
return callback ( err , 0 , 1 ) ;
}
} ;
/ * *
* Encodes multiple messages ( payload ) as binary .
*
* < 1 = binary , 0 = string > < number from 0 - 9 > < number from 0 - 9 > [ ... ] < number
* 255 > < data >
*
* Example :
* 1 3 255 1 2 3 , if the binary contents are interpreted as 8 bit integers
*
* @ param { Array } packets
* @ return { ArrayBuffer } encoded payload
* @ api private
* /
exports . encodePayloadAsArrayBuffer = function ( packets , callback ) {
if ( ! packets . length ) {
return callback ( new ArrayBuffer ( 0 ) ) ;
}
function encodeOne ( packet , doneCallback ) {
exports . encodePacket ( packet , true , true , function ( data ) {
return doneCallback ( null , data ) ;
} ) ;
}
map ( packets , encodeOne , function ( err , encodedPackets ) {
var totalLength = encodedPackets . reduce ( function ( acc , p ) {
var len ;
if ( typeof p === 'string' ) {
len = p . length ;
} else {
len = p . byteLength ;
}
return acc + len . toString ( ) . length + len + 2 ; // string/binary identifier + separator = 2
} , 0 ) ;
var resultArray = new Uint8Array ( totalLength ) ;
var bufferIndex = 0 ;
encodedPackets . forEach ( function ( p ) {
var isString = typeof p === 'string' ;
var ab = p ;
if ( isString ) {
var view = new Uint8Array ( p . length ) ;
for ( var i = 0 ; i < p . length ; i ++ ) {
view [ i ] = p . charCodeAt ( i ) ;
}
ab = view . buffer ;
}
if ( isString ) { // not true binary
resultArray [ bufferIndex ++ ] = 0 ;
} else { // true binary
resultArray [ bufferIndex ++ ] = 1 ;
}
var lenStr = ab . byteLength . toString ( ) ;
for ( var i = 0 ; i < lenStr . length ; i ++ ) {
resultArray [ bufferIndex ++ ] = parseInt ( lenStr [ i ] ) ;
}
resultArray [ bufferIndex ++ ] = 255 ;
var view = new Uint8Array ( ab ) ;
for ( var i = 0 ; i < view . length ; i ++ ) {
resultArray [ bufferIndex ++ ] = view [ i ] ;
}
} ) ;
return callback ( resultArray . buffer ) ;
} ) ;
} ;
/ * *
* Encode as Blob
* /
exports . encodePayloadAsBlob = function ( packets , callback ) {
function encodeOne ( packet , doneCallback ) {
exports . encodePacket ( packet , true , true , function ( encoded ) {
var binaryIdentifier = new Uint8Array ( 1 ) ;
binaryIdentifier [ 0 ] = 1 ;
if ( typeof encoded === 'string' ) {
var view = new Uint8Array ( encoded . length ) ;
for ( var i = 0 ; i < encoded . length ; i ++ ) {
view [ i ] = encoded . charCodeAt ( i ) ;
}
encoded = view . buffer ;
binaryIdentifier [ 0 ] = 0 ;
}
var len = ( encoded instanceof ArrayBuffer )
? encoded . byteLength
: encoded . size ;
var lenStr = len . toString ( ) ;
var lengthAry = new Uint8Array ( lenStr . length + 1 ) ;
for ( var i = 0 ; i < lenStr . length ; i ++ ) {
lengthAry [ i ] = parseInt ( lenStr [ i ] ) ;
}
lengthAry [ lenStr . length ] = 255 ;
if ( Blob ) {
var blob = new Blob ( [ binaryIdentifier . buffer , lengthAry . buffer , encoded ] ) ;
doneCallback ( null , blob ) ;
}
} ) ;
}
map ( packets , encodeOne , function ( err , results ) {
return callback ( new Blob ( results ) ) ;
} ) ;
} ;
/ *
* Decodes data when a payload is maybe expected . Strings are decoded by
* interpreting each byte as a key code for entries marked to start with 0. See
* description of encodePayloadAsBinary
*
* @ param { ArrayBuffer } data , callback method
* @ api public
* /
exports . decodePayloadAsBinary = function ( data , binaryType , callback ) {
if ( typeof binaryType === 'function' ) {
callback = binaryType ;
binaryType = null ;
}
var bufferTail = data ;
var buffers = [ ] ;
var numberTooLong = false ;
while ( bufferTail . byteLength > 0 ) {
var tailArray = new Uint8Array ( bufferTail ) ;
var isString = tailArray [ 0 ] === 0 ;
var msgLength = '' ;
for ( var i = 1 ; ; i ++ ) {
if ( tailArray [ i ] == 255 ) break ;
if ( msgLength . length > 310 ) {
numberTooLong = true ;
break ;
}
msgLength += tailArray [ i ] ;
}
if ( numberTooLong ) return callback ( err , 0 , 1 ) ;
bufferTail = sliceBuffer ( bufferTail , 2 + msgLength . length ) ;
msgLength = parseInt ( msgLength ) ;
var msg = sliceBuffer ( bufferTail , 0 , msgLength ) ;
if ( isString ) {
try {
msg = String . fromCharCode . apply ( null , new Uint8Array ( msg ) ) ;
} catch ( e ) {
// iPhone Safari doesn't let you apply to typed arrays
var typed = new Uint8Array ( msg ) ;
msg = '' ;
for ( var i = 0 ; i < typed . length ; i ++ ) {
msg += String . fromCharCode ( typed [ i ] ) ;
}
}
}
buffers . push ( msg ) ;
bufferTail = sliceBuffer ( bufferTail , msgLength ) ;
}
var total = buffers . length ;
buffers . forEach ( function ( buffer , i ) {
callback ( exports . decodePacket ( buffer , binaryType , true ) , i , total ) ;
} ) ;
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./keys" : 32 , "after" : 7 , "arraybuffer.slice" : 8 , "base64-arraybuffer" : 10 , "blob" : 11 , "has-binary" : 33 , "wtf-8" : 54 } ] , 32 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Gets the keys for an object .
*
* @ return { Array } keys
* @ api private
* /
module . exports = Object . keys || function keys ( obj ) {
var arr = [ ] ;
var has = Object . prototype . hasOwnProperty ;
for ( var i in obj ) {
if ( has . call ( obj , i ) ) {
arr . push ( i ) ;
}
}
return arr ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 33 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ *
* Module requirements .
* /
var isArray = require ( 'isarray' ) ;
/ * *
* Module exports .
* /
module . exports = hasBinary ;
/ * *
* Checks for binary data .
*
* Right now only Buffer and ArrayBuffer are supported . .
*
* @ param { Object } anything
* @ api public
* /
function hasBinary ( data ) {
function _hasBinary ( obj ) {
if ( ! obj ) return false ;
if ( ( global . Buffer && global . Buffer . isBuffer && global . Buffer . isBuffer ( obj ) ) ||
( global . ArrayBuffer && obj instanceof ArrayBuffer ) ||
( global . Blob && obj instanceof Blob ) ||
( global . File && obj instanceof File )
) {
return true ;
}
if ( isArray ( obj ) ) {
for ( var i = 0 ; i < obj . length ; i ++ ) {
if ( _hasBinary ( obj [ i ] ) ) {
return true ;
}
}
} else if ( obj && 'object' == typeof obj ) {
// see: https://github.com/Automattic/has-binary/pull/4
if ( obj . toJSON && 'function' == typeof obj . toJSON ) {
obj = obj . toJSON ( ) ;
}
for ( var key in obj ) {
if ( Object . prototype . hasOwnProperty . call ( obj , key ) && _hasBinary ( obj [ key ] ) ) {
return true ;
}
}
}
return false ;
}
return _hasBinary ( data ) ;
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "isarray" : 36 } ] , 34 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module exports .
*
* Logic borrowed from Modernizr :
*
* - https : //github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
* /
try {
module . exports = typeof XMLHttpRequest !== 'undefined' &&
'withCredentials' in new XMLHttpRequest ( ) ;
} catch ( err ) {
// if XMLHttp support is disabled in IE then it will throw
// when trying to create
module . exports = false ;
}
2017-02-25 23:25:06 -05:00
} , { } ] , 35 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
var indexOf = [ ] . indexOf ;
module . exports = function ( arr , obj ) {
if ( indexOf ) return arr . indexOf ( obj ) ;
for ( var i = 0 ; i < arr . length ; ++ i ) {
if ( arr [ i ] === obj ) return i ;
}
return - 1 ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 36 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = Array . isArray || function ( arr ) {
return Object . prototype . toString . call ( arr ) == '[object Array]' ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 37 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
; ( function ( ) {
// Detect the `define` function exposed by asynchronous module loaders. The
// strict `define` check is necessary for compatibility with `r.js`.
var isLoader = typeof define === "function" && define . amd ;
// A set of types used to distinguish objects from primitives.
var objectTypes = {
"function" : true ,
"object" : true
} ;
// Detect the `exports` object exposed by CommonJS implementations.
var freeExports = objectTypes [ typeof exports ] && exports && ! exports . nodeType && exports ;
// Use the `global` object exposed by Node (including Browserify via
// `insert-module-globals`), Narwhal, and Ringo as the default context,
// and the `window` object in browsers. Rhino exports a `global` function
// instead.
var root = objectTypes [ typeof window ] && window || this ,
freeGlobal = freeExports && objectTypes [ typeof module ] && module && ! module . nodeType && typeof global == "object" && global ;
if ( freeGlobal && ( freeGlobal [ "global" ] === freeGlobal || freeGlobal [ "window" ] === freeGlobal || freeGlobal [ "self" ] === freeGlobal ) ) {
root = freeGlobal ;
}
// Public: Initializes JSON 3 using the given `context` object, attaching the
// `stringify` and `parse` functions to the specified `exports` object.
function runInContext ( context , exports ) {
context || ( context = root [ "Object" ] ( ) ) ;
exports || ( exports = root [ "Object" ] ( ) ) ;
// Native constructor aliases.
var Number = context [ "Number" ] || root [ "Number" ] ,
String = context [ "String" ] || root [ "String" ] ,
Object = context [ "Object" ] || root [ "Object" ] ,
Date = context [ "Date" ] || root [ "Date" ] ,
SyntaxError = context [ "SyntaxError" ] || root [ "SyntaxError" ] ,
TypeError = context [ "TypeError" ] || root [ "TypeError" ] ,
Math = context [ "Math" ] || root [ "Math" ] ,
nativeJSON = context [ "JSON" ] || root [ "JSON" ] ;
// Delegate to the native `stringify` and `parse` implementations.
if ( typeof nativeJSON == "object" && nativeJSON ) {
exports . stringify = nativeJSON . stringify ;
exports . parse = nativeJSON . parse ;
}
// Convenience aliases.
var objectProto = Object . prototype ,
getClass = objectProto . toString ,
isProperty , forEach , undef ;
// Test the `Date#getUTC*` methods. Based on work by @Yaffle.
var isExtended = new Date ( - 3509827334573292 ) ;
try {
// The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
// results for certain dates in Opera >= 10.53.
isExtended = isExtended . getUTCFullYear ( ) == - 109252 && isExtended . getUTCMonth ( ) === 0 && isExtended . getUTCDate ( ) === 1 &&
// Safari < 2.0.2 stores the internal millisecond time value correctly,
// but clips the values returned by the date methods to the range of
// signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
isExtended . getUTCHours ( ) == 10 && isExtended . getUTCMinutes ( ) == 37 && isExtended . getUTCSeconds ( ) == 6 && isExtended . getUTCMilliseconds ( ) == 708 ;
} catch ( exception ) { }
// Internal: Determines whether the native `JSON.stringify` and `parse`
// implementations are spec-compliant. Based on work by Ken Snyder.
function has ( name ) {
if ( has [ name ] !== undef ) {
// Return cached feature test result.
return has [ name ] ;
}
var isSupported ;
if ( name == "bug-string-char-index" ) {
// IE <= 7 doesn't support accessing string characters using square
// bracket notation. IE 8 only supports this for primitives.
isSupported = "a" [ 0 ] != "a" ;
} else if ( name == "json" ) {
// Indicates whether both `JSON.stringify` and `JSON.parse` are
// supported.
isSupported = has ( "json-stringify" ) && has ( "json-parse" ) ;
} else {
var value , serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}' ;
// Test `JSON.stringify`.
if ( name == "json-stringify" ) {
var stringify = exports . stringify , stringifySupported = typeof stringify == "function" && isExtended ;
if ( stringifySupported ) {
// A test function object with a custom `toJSON` method.
( value = function ( ) {
return 1 ;
} ) . toJSON = value ;
try {
stringifySupported =
// Firefox 3.1b1 and b2 serialize string, number, and boolean
// primitives as object literals.
stringify ( 0 ) === "0" &&
// FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
// literals.
stringify ( new Number ( ) ) === "0" &&
stringify ( new String ( ) ) == '""' &&
// FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
// does not define a canonical JSON representation (this applies to
// objects with `toJSON` properties as well, *unless* they are nested
// within an object or array).
stringify ( getClass ) === undef &&
// IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
// FF 3.1b3 pass this test.
stringify ( undef ) === undef &&
// Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
// respectively, if the value is omitted entirely.
stringify ( ) === undef &&
// FF 3.1b1, 2 throw an error if the given value is not a number,
// string, array, object, Boolean, or `null` literal. This applies to
// objects with custom `toJSON` methods as well, unless they are nested
// inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
// methods entirely.
stringify ( value ) === "1" &&
stringify ( [ value ] ) == "[1]" &&
// Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
// `"[null]"`.
stringify ( [ undef ] ) == "[null]" &&
// YUI 3.0.0b1 fails to serialize `null` literals.
stringify ( null ) == "null" &&
// FF 3.1b1, 2 halts serialization if an array contains a function:
// `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
// elides non-JSON values from objects and arrays, unless they
// define custom `toJSON` methods.
stringify ( [ undef , getClass , null ] ) == "[null,null,null]" &&
// Simple serialization test. FF 3.1b1 uses Unicode escape sequences
// where character escape codes are expected (e.g., `\b` => `\u0008`).
stringify ( { "a" : [ value , true , false , null , "\x00\b\n\f\r\t" ] } ) == serialized &&
// FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
stringify ( null , value ) === "1" &&
stringify ( [ 1 , 2 ] , null , 1 ) == "[\n 1,\n 2\n]" &&
// JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
// serialize extended years.
stringify ( new Date ( - 8.64 e15 ) ) == '"-271821-04-20T00:00:00.000Z"' &&
// The milliseconds are optional in ES 5, but required in 5.1.
stringify ( new Date ( 8.64 e15 ) ) == '"+275760-09-13T00:00:00.000Z"' &&
// Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
// four-digit years instead of six-digit years. Credits: @Yaffle.
stringify ( new Date ( - 621987552e5 ) ) == '"-000001-01-01T00:00:00.000Z"' &&
// Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
// values less than 1000. Credits: @Yaffle.
stringify ( new Date ( - 1 ) ) == '"1969-12-31T23:59:59.999Z"' ;
} catch ( exception ) {
stringifySupported = false ;
}
}
isSupported = stringifySupported ;
}
// Test `JSON.parse`.
if ( name == "json-parse" ) {
var parse = exports . parse ;
if ( typeof parse == "function" ) {
try {
// FF 3.1b1, b2 will throw an exception if a bare literal is provided.
// Conforming implementations should also coerce the initial argument to
// a string prior to parsing.
if ( parse ( "0" ) === 0 && ! parse ( false ) ) {
// Simple parsing test.
value = parse ( serialized ) ;
var parseSupported = value [ "a" ] . length == 5 && value [ "a" ] [ 0 ] === 1 ;
if ( parseSupported ) {
try {
// Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
parseSupported = ! parse ( '"\t"' ) ;
} catch ( exception ) { }
if ( parseSupported ) {
try {
// FF 4.0 and 4.0.1 allow leading `+` signs and leading
// decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
// certain octal literals.
parseSupported = parse ( "01" ) !== 1 ;
} catch ( exception ) { }
}
if ( parseSupported ) {
try {
// FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
// points. These environments, along with FF 3.1b1 and 2,
// also allow trailing commas in JSON objects and arrays.
parseSupported = parse ( "1." ) !== 1 ;
} catch ( exception ) { }
}
}
}
} catch ( exception ) {
parseSupported = false ;
}
}
isSupported = parseSupported ;
}
}
return has [ name ] = ! ! isSupported ;
}
if ( ! has ( "json" ) ) {
// Common `[[Class]]` name aliases.
var functionClass = "[object Function]" ,
dateClass = "[object Date]" ,
numberClass = "[object Number]" ,
stringClass = "[object String]" ,
arrayClass = "[object Array]" ,
booleanClass = "[object Boolean]" ;
// Detect incomplete support for accessing string characters by index.
var charIndexBuggy = has ( "bug-string-char-index" ) ;
// Define additional utility methods if the `Date` methods are buggy.
if ( ! isExtended ) {
var floor = Math . floor ;
// A mapping between the months of the year and the number of days between
// January 1st and the first of the respective month.
var Months = [ 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 ] ;
// Internal: Calculates the number of days between the Unix epoch and the
// first day of the given month.
var getDay = function ( year , month ) {
return Months [ month ] + 365 * ( year - 1970 ) + floor ( ( year - 1969 + ( month = + ( month > 1 ) ) ) / 4 ) - floor ( ( year - 1901 + month ) / 100 ) + floor ( ( year - 1601 + month ) / 400 ) ;
} ;
}
// Internal: Determines if a property is a direct property of the given
// object. Delegates to the native `Object#hasOwnProperty` method.
if ( ! ( isProperty = objectProto . hasOwnProperty ) ) {
isProperty = function ( property ) {
var members = { } , constructor ;
if ( ( members . _ _proto _ _ = null , members . _ _proto _ _ = {
// The *proto* property cannot be set multiple times in recent
// versions of Firefox and SeaMonkey.
"toString" : 1
} , members ) . toString != getClass ) {
// Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
// supports the mutable *proto* property.
isProperty = function ( property ) {
// Capture and break the object's prototype chain (see section 8.6.2
// of the ES 5.1 spec). The parenthesized expression prevents an
// unsafe transformation by the Closure Compiler.
var original = this . _ _proto _ _ , result = property in ( this . _ _proto _ _ = null , this ) ;
// Restore the original prototype chain.
this . _ _proto _ _ = original ;
return result ;
} ;
} else {
// Capture a reference to the top-level `Object` constructor.
constructor = members . constructor ;
// Use the `constructor` property to simulate `Object#hasOwnProperty` in
// other environments.
isProperty = function ( property ) {
var parent = ( this . constructor || constructor ) . prototype ;
return property in this && ! ( property in parent && this [ property ] === parent [ property ] ) ;
} ;
}
members = null ;
return isProperty . call ( this , property ) ;
} ;
}
// Internal: Normalizes the `for...in` iteration algorithm across
// environments. Each enumerated key is yielded to a `callback` function.
forEach = function ( object , callback ) {
var size = 0 , Properties , members , property ;
// Tests for bugs in the current environment's `for...in` algorithm. The
// `valueOf` property inherits the non-enumerable flag from
// `Object.prototype` in older versions of IE, Netscape, and Mozilla.
( Properties = function ( ) {
this . valueOf = 0 ;
} ) . prototype . valueOf = 0 ;
// Iterate over a new instance of the `Properties` class.
members = new Properties ( ) ;
for ( property in members ) {
// Ignore all properties inherited from `Object.prototype`.
if ( isProperty . call ( members , property ) ) {
size ++ ;
}
}
Properties = members = null ;
// Normalize the iteration algorithm.
if ( ! size ) {
// A list of non-enumerable properties inherited from `Object.prototype`.
members = [ "valueOf" , "toString" , "toLocaleString" , "propertyIsEnumerable" , "isPrototypeOf" , "hasOwnProperty" , "constructor" ] ;
// IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
// properties.
forEach = function ( object , callback ) {
var isFunction = getClass . call ( object ) == functionClass , property , length ;
var hasProperty = ! isFunction && typeof object . constructor != "function" && objectTypes [ typeof object . hasOwnProperty ] && object . hasOwnProperty || isProperty ;
for ( property in object ) {
// Gecko <= 1.0 enumerates the `prototype` property of functions under
// certain conditions; IE does not.
if ( ! ( isFunction && property == "prototype" ) && hasProperty . call ( object , property ) ) {
callback ( property ) ;
}
}
// Manually invoke the callback for each non-enumerable property.
for ( length = members . length ; property = members [ -- length ] ; hasProperty . call ( object , property ) && callback ( property ) ) ;
} ;
} else if ( size == 2 ) {
// Safari <= 2.0.4 enumerates shadowed properties twice.
forEach = function ( object , callback ) {
// Create a set of iterated properties.
var members = { } , isFunction = getClass . call ( object ) == functionClass , property ;
for ( property in object ) {
// Store each property name to prevent double enumeration. The
// `prototype` property of functions is not enumerated due to cross-
// environment inconsistencies.
if ( ! ( isFunction && property == "prototype" ) && ! isProperty . call ( members , property ) && ( members [ property ] = 1 ) && isProperty . call ( object , property ) ) {
callback ( property ) ;
}
}
} ;
} else {
// No bugs detected; use the standard `for...in` algorithm.
forEach = function ( object , callback ) {
var isFunction = getClass . call ( object ) == functionClass , property , isConstructor ;
for ( property in object ) {
if ( ! ( isFunction && property == "prototype" ) && isProperty . call ( object , property ) && ! ( isConstructor = property === "constructor" ) ) {
callback ( property ) ;
}
}
// Manually invoke the callback for the `constructor` property due to
// cross-environment inconsistencies.
if ( isConstructor || isProperty . call ( object , ( property = "constructor" ) ) ) {
callback ( property ) ;
}
} ;
}
return forEach ( object , callback ) ;
} ;
// Public: Serializes a JavaScript `value` as a JSON string. The optional
// `filter` argument may specify either a function that alters how object and
// array members are serialized, or an array of strings and numbers that
// indicates which properties should be serialized. The optional `width`
// argument may be either a string or number that specifies the indentation
// level of the output.
if ( ! has ( "json-stringify" ) ) {
// Internal: A map of control characters and their escaped equivalents.
var Escapes = {
92 : "\\\\" ,
34 : '\\"' ,
8 : "\\b" ,
12 : "\\f" ,
10 : "\\n" ,
13 : "\\r" ,
9 : "\\t"
} ;
// Internal: Converts `value` into a zero-padded string such that its
// length is at least equal to `width`. The `width` must be <= 6.
var leadingZeroes = "000000" ;
var toPaddedString = function ( width , value ) {
// The `|| 0` expression is necessary to work around a bug in
// Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
return ( leadingZeroes + ( value || 0 ) ) . slice ( - width ) ;
} ;
// Internal: Double-quotes a string `value`, replacing all ASCII control
// characters (characters with code unit values between 0 and 31) with
// their escaped equivalents. This is an implementation of the
// `Quote(value)` operation defined in ES 5.1 section 15.12.3.
var unicodePrefix = "\\u00" ;
var quote = function ( value ) {
var result = '"' , index = 0 , length = value . length , useCharIndex = ! charIndexBuggy || length > 10 ;
var symbols = useCharIndex && ( charIndexBuggy ? value . split ( "" ) : value ) ;
for ( ; index < length ; index ++ ) {
var charCode = value . charCodeAt ( index ) ;
// If the character is a control character, append its Unicode or
// shorthand escape sequence; otherwise, append the character as-is.
switch ( charCode ) {
case 8 : case 9 : case 10 : case 12 : case 13 : case 34 : case 92 :
result += Escapes [ charCode ] ;
break ;
default :
if ( charCode < 32 ) {
result += unicodePrefix + toPaddedString ( 2 , charCode . toString ( 16 ) ) ;
break ;
}
result += useCharIndex ? symbols [ index ] : value . charAt ( index ) ;
}
}
return result + '"' ;
} ;
// Internal: Recursively serializes an object. Implements the
// `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
var serialize = function ( property , object , callback , properties , whitespace , indentation , stack ) {
var value , className , year , month , date , time , hours , minutes , seconds , milliseconds , results , element , index , length , prefix , result ;
try {
// Necessary for host object support.
value = object [ property ] ;
} catch ( exception ) { }
if ( typeof value == "object" && value ) {
className = getClass . call ( value ) ;
if ( className == dateClass && ! isProperty . call ( value , "toJSON" ) ) {
if ( value > - 1 / 0 && value < 1 / 0 ) {
// Dates are serialized according to the `Date#toJSON` method
// specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
// for the ISO 8601 date time string format.
if ( getDay ) {
// Manually compute the year, month, date, hours, minutes,
// seconds, and milliseconds if the `getUTC*` methods are
// buggy. Adapted from @Yaffle's `date-shim` project.
date = floor ( value / 864e5 ) ;
for ( year = floor ( date / 365.2425 ) + 1970 - 1 ; getDay ( year + 1 , 0 ) <= date ; year ++ ) ;
for ( month = floor ( ( date - getDay ( year , 0 ) ) / 30.42 ) ; getDay ( year , month + 1 ) <= date ; month ++ ) ;
date = 1 + date - getDay ( year , month ) ;
// The `time` value specifies the time within the day (see ES
// 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
// to compute `A modulo B`, as the `%` operator does not
// correspond to the `modulo` operation for negative numbers.
time = ( value % 864e5 + 864e5 ) % 864e5 ;
// The hours, minutes, seconds, and milliseconds are obtained by
// decomposing the time within the day. See section 15.9.1.10.
hours = floor ( time / 36e5 ) % 24 ;
minutes = floor ( time / 6e4 ) % 60 ;
seconds = floor ( time / 1e3 ) % 60 ;
milliseconds = time % 1e3 ;
} else {
year = value . getUTCFullYear ( ) ;
month = value . getUTCMonth ( ) ;
date = value . getUTCDate ( ) ;
hours = value . getUTCHours ( ) ;
minutes = value . getUTCMinutes ( ) ;
seconds = value . getUTCSeconds ( ) ;
milliseconds = value . getUTCMilliseconds ( ) ;
}
// Serialize extended years correctly.
value = ( year <= 0 || year >= 1e4 ? ( year < 0 ? "-" : "+" ) + toPaddedString ( 6 , year < 0 ? - year : year ) : toPaddedString ( 4 , year ) ) +
"-" + toPaddedString ( 2 , month + 1 ) + "-" + toPaddedString ( 2 , date ) +
// Months, dates, hours, minutes, and seconds should have two
// digits; milliseconds should have three.
"T" + toPaddedString ( 2 , hours ) + ":" + toPaddedString ( 2 , minutes ) + ":" + toPaddedString ( 2 , seconds ) +
// Milliseconds are optional in ES 5.0, but required in 5.1.
"." + toPaddedString ( 3 , milliseconds ) + "Z" ;
} else {
value = null ;
}
} else if ( typeof value . toJSON == "function" && ( ( className != numberClass && className != stringClass && className != arrayClass ) || isProperty . call ( value , "toJSON" ) ) ) {
// Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
// `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
// ignores all `toJSON` methods on these objects unless they are
// defined directly on an instance.
value = value . toJSON ( property ) ;
}
}
if ( callback ) {
// If a replacement function was provided, call it to obtain the value
// for serialization.
value = callback . call ( object , property , value ) ;
}
if ( value === null ) {
return "null" ;
}
className = getClass . call ( value ) ;
if ( className == booleanClass ) {
// Booleans are represented literally.
return "" + value ;
} else if ( className == numberClass ) {
// JSON numbers must be finite. `Infinity` and `NaN` are serialized as
// `"null"`.
return value > - 1 / 0 && value < 1 / 0 ? "" + value : "null" ;
} else if ( className == stringClass ) {
// Strings are double-quoted and escaped.
return quote ( "" + value ) ;
}
// Recursively serialize objects and arrays.
if ( typeof value == "object" ) {
// Check for cyclic structures. This is a linear search; performance
// is inversely proportional to the number of unique nested objects.
for ( length = stack . length ; length -- ; ) {
if ( stack [ length ] === value ) {
// Cyclic structures cannot be serialized by `JSON.stringify`.
throw TypeError ( ) ;
}
}
// Add the object to the stack of traversed objects.
stack . push ( value ) ;
results = [ ] ;
// Save the current indentation level and indent one additional level.
prefix = indentation ;
indentation += whitespace ;
if ( className == arrayClass ) {
// Recursively serialize array elements.
for ( index = 0 , length = value . length ; index < length ; index ++ ) {
element = serialize ( index , value , callback , properties , whitespace , indentation , stack ) ;
results . push ( element === undef ? "null" : element ) ;
}
result = results . length ? ( whitespace ? "[\n" + indentation + results . join ( ",\n" + indentation ) + "\n" + prefix + "]" : ( "[" + results . join ( "," ) + "]" ) ) : "[]" ;
} else {
// Recursively serialize object members. Members are selected from
// either a user-specified list of property names, or the object
// itself.
forEach ( properties || value , function ( property ) {
var element = serialize ( property , value , callback , properties , whitespace , indentation , stack ) ;
if ( element !== undef ) {
// According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
// is not the empty string, let `member` {quote(property) + ":"}
// be the concatenation of `member` and the `space` character."
// The "`space` character" refers to the literal space
// character, not the `space` {width} argument provided to
// `JSON.stringify`.
results . push ( quote ( property ) + ":" + ( whitespace ? " " : "" ) + element ) ;
}
} ) ;
result = results . length ? ( whitespace ? "{\n" + indentation + results . join ( ",\n" + indentation ) + "\n" + prefix + "}" : ( "{" + results . join ( "," ) + "}" ) ) : "{}" ;
}
// Remove the object from the traversed object stack.
stack . pop ( ) ;
return result ;
}
} ;
// Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
exports . stringify = function ( source , filter , width ) {
var whitespace , callback , properties , className ;
if ( objectTypes [ typeof filter ] && filter ) {
if ( ( className = getClass . call ( filter ) ) == functionClass ) {
callback = filter ;
} else if ( className == arrayClass ) {
// Convert the property names array into a makeshift set.
properties = { } ;
for ( var index = 0 , length = filter . length , value ; index < length ; value = filter [ index ++ ] , ( ( className = getClass . call ( value ) ) , className == stringClass || className == numberClass ) && ( properties [ value ] = 1 ) ) ;
}
}
if ( width ) {
if ( ( className = getClass . call ( width ) ) == numberClass ) {
// Convert the `width` to an integer and create a string containing
// `width` number of space characters.
if ( ( width -= width % 1 ) > 0 ) {
for ( whitespace = "" , width > 10 && ( width = 10 ) ; whitespace . length < width ; whitespace += " " ) ;
}
} else if ( className == stringClass ) {
whitespace = width . length <= 10 ? width : width . slice ( 0 , 10 ) ;
}
}
// Opera <= 7.54u2 discards the values associated with empty string keys
// (`""`) only if they are used directly within an object member list
// (e.g., `!("" in { "": 1})`).
return serialize ( "" , ( value = { } , value [ "" ] = source , value ) , callback , properties , whitespace , "" , [ ] ) ;
} ;
}
// Public: Parses a JSON source string.
if ( ! has ( "json-parse" ) ) {
var fromCharCode = String . fromCharCode ;
// Internal: A map of escaped control characters and their unescaped
// equivalents.
var Unescapes = {
92 : "\\" ,
34 : '"' ,
47 : "/" ,
98 : "\b" ,
116 : "\t" ,
110 : "\n" ,
102 : "\f" ,
114 : "\r"
} ;
// Internal: Stores the parser state.
var Index , Source ;
// Internal: Resets the parser state and throws a `SyntaxError`.
var abort = function ( ) {
Index = Source = null ;
throw SyntaxError ( ) ;
} ;
// Internal: Returns the next token, or `"$"` if the parser has reached
// the end of the source string. A token may be a string, number, `null`
// literal, or Boolean literal.
var lex = function ( ) {
var source = Source , length = source . length , value , begin , position , isSigned , charCode ;
while ( Index < length ) {
charCode = source . charCodeAt ( Index ) ;
switch ( charCode ) {
case 9 : case 10 : case 13 : case 32 :
// Skip whitespace tokens, including tabs, carriage returns, line
// feeds, and space characters.
Index ++ ;
break ;
case 123 : case 125 : case 91 : case 93 : case 58 : case 44 :
// Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
// the current position.
value = charIndexBuggy ? source . charAt ( Index ) : source [ Index ] ;
Index ++ ;
return value ;
case 34 :
// `"` delimits a JSON string; advance to the next character and
// begin parsing the string. String tokens are prefixed with the
// sentinel `@` character to distinguish them from punctuators and
// end-of-string tokens.
for ( value = "@" , Index ++ ; Index < length ; ) {
charCode = source . charCodeAt ( Index ) ;
if ( charCode < 32 ) {
// Unescaped ASCII control characters (those with a code unit
// less than the space character) are not permitted.
abort ( ) ;
} else if ( charCode == 92 ) {
// A reverse solidus (`\`) marks the beginning of an escaped
// control character (including `"`, `\`, and `/`) or Unicode
// escape sequence.
charCode = source . charCodeAt ( ++ Index ) ;
switch ( charCode ) {
case 92 : case 34 : case 47 : case 98 : case 116 : case 110 : case 102 : case 114 :
// Revive escaped control characters.
value += Unescapes [ charCode ] ;
Index ++ ;
break ;
case 117 :
// `\u` marks the beginning of a Unicode escape sequence.
// Advance to the first character and validate the
// four-digit code point.
begin = ++ Index ;
for ( position = Index + 4 ; Index < position ; Index ++ ) {
charCode = source . charCodeAt ( Index ) ;
// A valid sequence comprises four hexdigits (case-
// insensitive) that form a single hexadecimal value.
if ( ! ( charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70 ) ) {
// Invalid Unicode escape sequence.
abort ( ) ;
}
}
// Revive the escaped character.
value += fromCharCode ( "0x" + source . slice ( begin , Index ) ) ;
break ;
default :
// Invalid escape sequence.
abort ( ) ;
}
} else {
if ( charCode == 34 ) {
// An unescaped double-quote character marks the end of the
// string.
break ;
}
charCode = source . charCodeAt ( Index ) ;
begin = Index ;
// Optimize for the common case where a string is valid.
while ( charCode >= 32 && charCode != 92 && charCode != 34 ) {
charCode = source . charCodeAt ( ++ Index ) ;
}
// Append the string as-is.
value += source . slice ( begin , Index ) ;
}
}
if ( source . charCodeAt ( Index ) == 34 ) {
// Advance to the next character and return the revived string.
Index ++ ;
return value ;
}
// Unterminated string.
abort ( ) ;
default :
// Parse numbers and literals.
begin = Index ;
// Advance past the negative sign, if one is specified.
if ( charCode == 45 ) {
isSigned = true ;
charCode = source . charCodeAt ( ++ Index ) ;
}
// Parse an integer or floating-point value.
if ( charCode >= 48 && charCode <= 57 ) {
// Leading zeroes are interpreted as octal literals.
if ( charCode == 48 && ( ( charCode = source . charCodeAt ( Index + 1 ) ) , charCode >= 48 && charCode <= 57 ) ) {
// Illegal octal literal.
abort ( ) ;
}
isSigned = false ;
// Parse the integer component.
for ( ; Index < length && ( ( charCode = source . charCodeAt ( Index ) ) , charCode >= 48 && charCode <= 57 ) ; Index ++ ) ;
// Floats cannot contain a leading decimal point; however, this
// case is already accounted for by the parser.
if ( source . charCodeAt ( Index ) == 46 ) {
position = ++ Index ;
// Parse the decimal component.
for ( ; position < length && ( ( charCode = source . charCodeAt ( position ) ) , charCode >= 48 && charCode <= 57 ) ; position ++ ) ;
if ( position == Index ) {
// Illegal trailing decimal.
abort ( ) ;
}
Index = position ;
}
// Parse exponents. The `e` denoting the exponent is
// case-insensitive.
charCode = source . charCodeAt ( Index ) ;
if ( charCode == 101 || charCode == 69 ) {
charCode = source . charCodeAt ( ++ Index ) ;
// Skip past the sign following the exponent, if one is
// specified.
if ( charCode == 43 || charCode == 45 ) {
Index ++ ;
}
// Parse the exponential component.
for ( position = Index ; position < length && ( ( charCode = source . charCodeAt ( position ) ) , charCode >= 48 && charCode <= 57 ) ; position ++ ) ;
if ( position == Index ) {
// Illegal empty exponent.
abort ( ) ;
}
Index = position ;
}
// Coerce the parsed value to a JavaScript number.
return + source . slice ( begin , Index ) ;
}
// A negative sign may only precede numbers.
if ( isSigned ) {
abort ( ) ;
}
// `true`, `false`, and `null` literals.
if ( source . slice ( Index , Index + 4 ) == "true" ) {
Index += 4 ;
return true ;
} else if ( source . slice ( Index , Index + 5 ) == "false" ) {
Index += 5 ;
return false ;
} else if ( source . slice ( Index , Index + 4 ) == "null" ) {
Index += 4 ;
return null ;
}
// Unrecognized token.
abort ( ) ;
}
}
// Return the sentinel `$` character if the parser has reached the end
// of the source string.
return "$" ;
} ;
// Internal: Parses a JSON `value` token.
var get = function ( value ) {
var results , hasMembers ;
if ( value == "$" ) {
// Unexpected end of input.
abort ( ) ;
}
if ( typeof value == "string" ) {
if ( ( charIndexBuggy ? value . charAt ( 0 ) : value [ 0 ] ) == "@" ) {
// Remove the sentinel `@` character.
return value . slice ( 1 ) ;
}
// Parse object and array literals.
if ( value == "[" ) {
// Parses a JSON array, returning a new JavaScript array.
results = [ ] ;
for ( ; ; hasMembers || ( hasMembers = true ) ) {
value = lex ( ) ;
// A closing square bracket marks the end of the array literal.
if ( value == "]" ) {
break ;
}
// If the array literal contains elements, the current token
// should be a comma separating the previous element from the
// next.
if ( hasMembers ) {
if ( value == "," ) {
value = lex ( ) ;
if ( value == "]" ) {
// Unexpected trailing `,` in array literal.
abort ( ) ;
}
} else {
// A `,` must separate each array element.
abort ( ) ;
}
}
// Elisions and leading commas are not permitted.
if ( value == "," ) {
abort ( ) ;
}
results . push ( get ( value ) ) ;
}
return results ;
} else if ( value == "{" ) {
// Parses a JSON object, returning a new JavaScript object.
results = { } ;
for ( ; ; hasMembers || ( hasMembers = true ) ) {
value = lex ( ) ;
// A closing curly brace marks the end of the object literal.
if ( value == "}" ) {
break ;
}
// If the object literal contains members, the current token
// should be a comma separator.
if ( hasMembers ) {
if ( value == "," ) {
value = lex ( ) ;
if ( value == "}" ) {
// Unexpected trailing `,` in object literal.
abort ( ) ;
}
} else {
// A `,` must separate each object member.
abort ( ) ;
}
}
// Leading commas are not permitted, object property names must be
// double-quoted strings, and a `:` must separate each property
// name and value.
if ( value == "," || typeof value != "string" || ( charIndexBuggy ? value . charAt ( 0 ) : value [ 0 ] ) != "@" || lex ( ) != ":" ) {
abort ( ) ;
}
results [ value . slice ( 1 ) ] = get ( lex ( ) ) ;
}
return results ;
}
// Unexpected token encountered.
abort ( ) ;
}
return value ;
} ;
// Internal: Updates a traversed object member.
var update = function ( source , property , callback ) {
var element = walk ( source , property , callback ) ;
if ( element === undef ) {
delete source [ property ] ;
} else {
source [ property ] = element ;
}
} ;
// Internal: Recursively traverses a parsed JSON object, invoking the
// `callback` function for each value. This is an implementation of the
// `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
var walk = function ( source , property , callback ) {
var value = source [ property ] , length ;
if ( typeof value == "object" && value ) {
// `forEach` can't be used to traverse an array in Opera <= 8.54
// because its `Object#hasOwnProperty` implementation returns `false`
// for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
if ( getClass . call ( value ) == arrayClass ) {
for ( length = value . length ; length -- ; ) {
update ( value , length , callback ) ;
}
} else {
forEach ( value , function ( property ) {
update ( value , property , callback ) ;
} ) ;
}
}
return callback . call ( source , property , value ) ;
} ;
// Public: `JSON.parse`. See ES 5.1 section 15.12.2.
exports . parse = function ( source , callback ) {
var result , value ;
Index = 0 ;
Source = "" + source ;
result = get ( lex ( ) ) ;
// If a JSON string contains multiple tokens, it is invalid.
if ( lex ( ) != "$" ) {
abort ( ) ;
}
// Reset the parser state.
Index = Source = null ;
return callback && getClass . call ( callback ) == functionClass ? walk ( ( value = { } , value [ "" ] = result , value ) , "" , callback ) : result ;
} ;
}
}
exports [ "runInContext" ] = runInContext ;
return exports ;
}
if ( freeExports && ! isLoader ) {
// Export for CommonJS environments.
runInContext ( root , freeExports ) ;
} else {
// Export for web browsers and JavaScript engines.
var nativeJSON = root . JSON ,
previousJSON = root [ "JSON3" ] ,
isRestored = false ;
var JSON3 = runInContext ( root , ( root [ "JSON3" ] = {
// Public: Restores the original value of the global `JSON` object and
// returns a reference to the `JSON3` object.
"noConflict" : function ( ) {
if ( ! isRestored ) {
isRestored = true ;
root . JSON = nativeJSON ;
root [ "JSON3" ] = previousJSON ;
nativeJSON = previousJSON = null ;
}
return JSON3 ;
}
} ) ) ;
root . JSON = {
"parse" : JSON3 . parse ,
"stringify" : JSON3 . stringify
} ;
}
// Export for asynchronous module loaders.
if ( isLoader ) {
define ( function ( ) {
return JSON3 ;
} ) ;
}
} ) . call ( this ) ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { } ] , 38 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Helpers .
* /
var s = 1000
var m = s * 60
var h = m * 60
var d = h * 24
var y = d * 365.25
/ * *
* Parse or format the given ` val ` .
*
* Options :
*
* - ` long ` verbose formatting [ false ]
*
* @ param { String | Number } val
* @ param { Object } options
* @ throws { Error } throw an error if val is not a non - empty string or a number
* @ return { String | Number }
* @ api public
* /
module . exports = function ( val , options ) {
options = options || { }
var type = typeof val
if ( type === 'string' && val . length > 0 ) {
return parse ( val )
} else if ( type === 'number' && isNaN ( val ) === false ) {
return options . long ?
fmtLong ( val ) :
fmtShort ( val )
}
throw new Error ( 'val is not a non-empty string or a valid number. val=' + JSON . stringify ( val ) )
}
/ * *
* Parse the given ` str ` and return milliseconds .
*
* @ param { String } str
* @ return { Number }
* @ api private
* /
function parse ( str ) {
str = String ( str )
if ( str . length > 10000 ) {
return
}
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i . exec ( str )
if ( ! match ) {
return
}
var n = parseFloat ( match [ 1 ] )
var type = ( match [ 2 ] || 'ms' ) . toLowerCase ( )
switch ( type ) {
case 'years' :
case 'year' :
case 'yrs' :
case 'yr' :
case 'y' :
return n * y
case 'days' :
case 'day' :
case 'd' :
return n * d
case 'hours' :
case 'hour' :
case 'hrs' :
case 'hr' :
case 'h' :
return n * h
case 'minutes' :
case 'minute' :
case 'mins' :
case 'min' :
case 'm' :
return n * m
case 'seconds' :
case 'second' :
case 'secs' :
case 'sec' :
case 's' :
return n * s
case 'milliseconds' :
case 'millisecond' :
case 'msecs' :
case 'msec' :
case 'ms' :
return n
default :
return undefined
}
}
/ * *
* Short format for ` ms ` .
*
* @ param { Number } ms
* @ return { String }
* @ api private
* /
function fmtShort ( ms ) {
if ( ms >= d ) {
return Math . round ( ms / d ) + 'd'
}
if ( ms >= h ) {
return Math . round ( ms / h ) + 'h'
}
if ( ms >= m ) {
return Math . round ( ms / m ) + 'm'
}
if ( ms >= s ) {
return Math . round ( ms / s ) + 's'
}
return ms + 'ms'
}
/ * *
* Long format for ` ms ` .
*
* @ param { Number } ms
* @ return { String }
* @ api private
* /
function fmtLong ( ms ) {
return plural ( ms , d , 'day' ) ||
plural ( ms , h , 'hour' ) ||
plural ( ms , m , 'minute' ) ||
plural ( ms , s , 'second' ) ||
ms + ' ms'
}
/ * *
* Pluralization helper .
* /
function plural ( ms , n , name ) {
if ( ms < n ) {
return
}
if ( ms < n * 1.5 ) {
return Math . floor ( ms / n ) + ' ' + name
}
return Math . ceil ( ms / n ) + ' ' + name + 's'
}
2017-02-25 23:25:06 -05:00
} , { } ] , 39 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* JSON parse .
*
* @ see Based on jQuery # parseJSON ( MIT ) and JSON2
* @ api private
* /
var rvalidchars = /^[\],:{}\s]*$/ ;
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g ;
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g ;
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g ;
var rtrimLeft = /^\s+/ ;
var rtrimRight = /\s+$/ ;
module . exports = function parsejson ( data ) {
if ( 'string' != typeof data || ! data ) {
return null ;
}
data = data . replace ( rtrimLeft , '' ) . replace ( rtrimRight , '' ) ;
// Attempt to parse using the native JSON parser first
if ( global . JSON && JSON . parse ) {
return JSON . parse ( data ) ;
}
if ( rvalidchars . test ( data . replace ( rvalidescape , '@' )
. replace ( rvalidtokens , ']' )
. replace ( rvalidbraces , '' ) ) ) {
return ( new Function ( 'return ' + data ) ) ( ) ;
}
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { } ] , 40 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Compiles a querystring
* Returns string representation of the object
*
* @ param { Object }
* @ api private
* /
exports . encode = function ( obj ) {
var str = '' ;
for ( var i in obj ) {
if ( obj . hasOwnProperty ( i ) ) {
if ( str . length ) str += '&' ;
str += encodeURIComponent ( i ) + '=' + encodeURIComponent ( obj [ i ] ) ;
}
}
return str ;
} ;
/ * *
* Parses a simple querystring into an object
*
* @ param { String } qs
* @ api private
* /
exports . decode = function ( qs ) {
var qry = { } ;
var pairs = qs . split ( '&' ) ;
for ( var i = 0 , l = pairs . length ; i < l ; i ++ ) {
var pair = pairs [ i ] . split ( '=' ) ;
qry [ decodeURIComponent ( pair [ 0 ] ) ] = decodeURIComponent ( pair [ 1 ] ) ;
}
return qry ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 41 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Parses an URI
*
* @ author Steven Levithan < stevenlevithan . com > ( MIT license )
* @ api private
* /
var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ ;
var parts = [
'source' , 'protocol' , 'authority' , 'userInfo' , 'user' , 'password' , 'host' , 'port' , 'relative' , 'path' , 'directory' , 'file' , 'query' , 'anchor'
] ;
module . exports = function parseuri ( str ) {
var src = str ,
b = str . indexOf ( '[' ) ,
e = str . indexOf ( ']' ) ;
if ( b != - 1 && e != - 1 ) {
str = str . substring ( 0 , b ) + str . substring ( b , e ) . replace ( /:/g , ';' ) + str . substring ( e , str . length ) ;
}
var m = re . exec ( str || '' ) ,
uri = { } ,
i = 14 ;
while ( i -- ) {
uri [ parts [ i ] ] = m [ i ] || '' ;
}
if ( b != - 1 && e != - 1 ) {
uri . source = src ;
uri . host = uri . host . substring ( 1 , uri . host . length - 1 ) . replace ( /;/g , ':' ) ;
uri . authority = uri . authority . replace ( '[' , '' ) . replace ( ']' , '' ) . replace ( /;/g , ':' ) ;
uri . ipv6uri = true ;
}
return uri ;
} ;
2017-02-25 23:25:06 -05:00
} , { } ] , 42 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var url = require ( './url' ) ;
var parser = require ( 'socket.io-parser' ) ;
var Manager = require ( './manager' ) ;
var debug = require ( 'debug' ) ( 'socket.io-client' ) ;
/ * *
* Module exports .
* /
module . exports = exports = lookup ;
/ * *
* Managers cache .
* /
var cache = exports . managers = { } ;
/ * *
* Looks up an existing ` Manager ` for multiplexing .
* If the user summons :
*
* ` io('http://localhost/a'); `
* ` io('http://localhost/b'); `
*
* We reuse the existing instance based on same scheme / port / host ,
* and we initialize sockets for each namespace .
*
* @ api public
* /
function lookup ( uri , opts ) {
if ( typeof uri === 'object' ) {
opts = uri ;
uri = undefined ;
}
opts = opts || { } ;
var parsed = url ( uri ) ;
var source = parsed . source ;
var id = parsed . id ;
var path = parsed . path ;
var sameNamespace = cache [ id ] && path in cache [ id ] . nsps ;
var newConnection = opts . forceNew || opts [ 'force new connection' ] ||
false === opts . multiplex || sameNamespace ;
var io ;
if ( newConnection ) {
debug ( 'ignoring socket cache for %s' , source ) ;
io = Manager ( source , opts ) ;
} else {
if ( ! cache [ id ] ) {
debug ( 'new io instance for %s' , source ) ;
cache [ id ] = Manager ( source , opts ) ;
}
io = cache [ id ] ;
}
if ( parsed . query && ! opts . query ) {
opts . query = parsed . query ;
} else if ( opts && 'object' === typeof opts . query ) {
opts . query = encodeQueryString ( opts . query ) ;
}
return io . socket ( parsed . path , opts ) ;
}
/ * *
* Helper method to parse query objects to string .
* @ param { object } query
* @ returns { string }
* /
function encodeQueryString ( obj ) {
var str = [ ] ;
for ( var p in obj ) {
if ( obj . hasOwnProperty ( p ) ) {
str . push ( encodeURIComponent ( p ) + '=' + encodeURIComponent ( obj [ p ] ) ) ;
}
}
return str . join ( '&' ) ;
}
/ * *
* Protocol version .
*
* @ api public
* /
exports . protocol = parser . protocol ;
/ * *
* ` connect ` .
*
* @ param { String } uri
* @ api public
* /
exports . connect = lookup ;
/ * *
* Expose constructors for standalone build .
*
* @ api public
* /
exports . Manager = require ( './manager' ) ;
exports . Socket = require ( './socket' ) ;
2017-02-25 23:25:06 -05:00
} , { "./manager" : 43 , "./socket" : 45 , "./url" : 46 , "debug" : 48 , "socket.io-parser" : 51 } ] , 43 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var eio = require ( 'engine.io-client' ) ;
var Socket = require ( './socket' ) ;
var Emitter = require ( 'component-emitter' ) ;
var parser = require ( 'socket.io-parser' ) ;
var on = require ( './on' ) ;
var bind = require ( 'component-bind' ) ;
var debug = require ( 'debug' ) ( 'socket.io-client:manager' ) ;
var indexOf = require ( 'indexof' ) ;
var Backoff = require ( 'backo2' ) ;
/ * *
* IE6 + hasOwnProperty
* /
var has = Object . prototype . hasOwnProperty ;
/ * *
* Module exports
* /
module . exports = Manager ;
/ * *
* ` Manager ` constructor .
*
* @ param { String } engine instance or engine uri / opts
* @ param { Object } options
* @ api public
* /
function Manager ( uri , opts ) {
if ( ! ( this instanceof Manager ) ) return new Manager ( uri , opts ) ;
if ( uri && ( 'object' === typeof uri ) ) {
opts = uri ;
uri = undefined ;
}
opts = opts || { } ;
opts . path = opts . path || '/socket.io' ;
this . nsps = { } ;
this . subs = [ ] ;
this . opts = opts ;
this . reconnection ( opts . reconnection !== false ) ;
this . reconnectionAttempts ( opts . reconnectionAttempts || Infinity ) ;
this . reconnectionDelay ( opts . reconnectionDelay || 1000 ) ;
this . reconnectionDelayMax ( opts . reconnectionDelayMax || 5000 ) ;
this . randomizationFactor ( opts . randomizationFactor || 0.5 ) ;
this . backoff = new Backoff ( {
min : this . reconnectionDelay ( ) ,
max : this . reconnectionDelayMax ( ) ,
jitter : this . randomizationFactor ( )
} ) ;
this . timeout ( null == opts . timeout ? 20000 : opts . timeout ) ;
this . readyState = 'closed' ;
this . uri = uri ;
this . connecting = [ ] ;
this . lastPing = null ;
this . encoding = false ;
this . packetBuffer = [ ] ;
this . encoder = new parser . Encoder ( ) ;
this . decoder = new parser . Decoder ( ) ;
this . autoConnect = opts . autoConnect !== false ;
if ( this . autoConnect ) this . open ( ) ;
}
/ * *
* Propagate given event to sockets and emit on ` this `
*
* @ api private
* /
Manager . prototype . emitAll = function ( ) {
this . emit . apply ( this , arguments ) ;
for ( var nsp in this . nsps ) {
if ( has . call ( this . nsps , nsp ) ) {
this . nsps [ nsp ] . emit . apply ( this . nsps [ nsp ] , arguments ) ;
}
}
} ;
/ * *
* Update ` socket.id ` of all sockets
*
* @ api private
* /
Manager . prototype . updateSocketIds = function ( ) {
for ( var nsp in this . nsps ) {
if ( has . call ( this . nsps , nsp ) ) {
this . nsps [ nsp ] . id = this . engine . id ;
}
}
} ;
/ * *
* Mix in ` Emitter ` .
* /
Emitter ( Manager . prototype ) ;
/ * *
* Sets the ` reconnection ` config .
*
* @ param { Boolean } true / false if it should automatically reconnect
* @ return { Manager } self or value
* @ api public
* /
Manager . prototype . reconnection = function ( v ) {
if ( ! arguments . length ) return this . _reconnection ;
this . _reconnection = ! ! v ;
return this ;
} ;
/ * *
* Sets the reconnection attempts config .
*
* @ param { Number } max reconnection attempts before giving up
* @ return { Manager } self or value
* @ api public
* /
Manager . prototype . reconnectionAttempts = function ( v ) {
if ( ! arguments . length ) return this . _reconnectionAttempts ;
this . _reconnectionAttempts = v ;
return this ;
} ;
/ * *
* Sets the delay between reconnections .
*
* @ param { Number } delay
* @ return { Manager } self or value
* @ api public
* /
Manager . prototype . reconnectionDelay = function ( v ) {
if ( ! arguments . length ) return this . _reconnectionDelay ;
this . _reconnectionDelay = v ;
this . backoff && this . backoff . setMin ( v ) ;
return this ;
} ;
Manager . prototype . randomizationFactor = function ( v ) {
if ( ! arguments . length ) return this . _randomizationFactor ;
this . _randomizationFactor = v ;
this . backoff && this . backoff . setJitter ( v ) ;
return this ;
} ;
/ * *
* Sets the maximum delay between reconnections .
*
* @ param { Number } delay
* @ return { Manager } self or value
* @ api public
* /
Manager . prototype . reconnectionDelayMax = function ( v ) {
if ( ! arguments . length ) return this . _reconnectionDelayMax ;
this . _reconnectionDelayMax = v ;
this . backoff && this . backoff . setMax ( v ) ;
return this ;
} ;
/ * *
* Sets the connection timeout . ` false ` to disable
*
* @ return { Manager } self or value
* @ api public
* /
Manager . prototype . timeout = function ( v ) {
if ( ! arguments . length ) return this . _timeout ;
this . _timeout = v ;
return this ;
} ;
/ * *
* Starts trying to reconnect if reconnection is enabled and we have not
* started reconnecting yet
*
* @ api private
* /
Manager . prototype . maybeReconnectOnOpen = function ( ) {
// Only try to reconnect if it's the first time we're connecting
if ( ! this . reconnecting && this . _reconnection && this . backoff . attempts === 0 ) {
// keeps reconnection from firing twice for the same reconnection loop
this . reconnect ( ) ;
}
} ;
/ * *
* Sets the current transport ` socket ` .
*
* @ param { Function } optional , callback
* @ return { Manager } self
* @ api public
* /
Manager . prototype . open =
Manager . prototype . connect = function ( fn , opts ) {
debug ( 'readyState %s' , this . readyState ) ;
if ( ~ this . readyState . indexOf ( 'open' ) ) return this ;
debug ( 'opening %s' , this . uri ) ;
this . engine = eio ( this . uri , this . opts ) ;
var socket = this . engine ;
var self = this ;
this . readyState = 'opening' ;
this . skipReconnect = false ;
// emit `open`
var openSub = on ( socket , 'open' , function ( ) {
self . onopen ( ) ;
fn && fn ( ) ;
} ) ;
// emit `connect_error`
var errorSub = on ( socket , 'error' , function ( data ) {
debug ( 'connect_error' ) ;
self . cleanup ( ) ;
self . readyState = 'closed' ;
self . emitAll ( 'connect_error' , data ) ;
if ( fn ) {
var err = new Error ( 'Connection error' ) ;
err . data = data ;
fn ( err ) ;
} else {
// Only do this if there is no fn to handle the error
self . maybeReconnectOnOpen ( ) ;
}
} ) ;
// emit `connect_timeout`
if ( false !== this . _timeout ) {
var timeout = this . _timeout ;
debug ( 'connect attempt will timeout after %d' , timeout ) ;
// set timer
var timer = setTimeout ( function ( ) {
debug ( 'connect attempt timed out after %d' , timeout ) ;
openSub . destroy ( ) ;
socket . close ( ) ;
socket . emit ( 'error' , 'timeout' ) ;
self . emitAll ( 'connect_timeout' , timeout ) ;
} , timeout ) ;
this . subs . push ( {
destroy : function ( ) {
clearTimeout ( timer ) ;
}
} ) ;
}
this . subs . push ( openSub ) ;
this . subs . push ( errorSub ) ;
return this ;
} ;
/ * *
* Called upon transport open .
*
* @ api private
* /
Manager . prototype . onopen = function ( ) {
debug ( 'open' ) ;
// clear old subs
this . cleanup ( ) ;
// mark as open
this . readyState = 'open' ;
this . emit ( 'open' ) ;
// add new subs
var socket = this . engine ;
this . subs . push ( on ( socket , 'data' , bind ( this , 'ondata' ) ) ) ;
this . subs . push ( on ( socket , 'ping' , bind ( this , 'onping' ) ) ) ;
this . subs . push ( on ( socket , 'pong' , bind ( this , 'onpong' ) ) ) ;
this . subs . push ( on ( socket , 'error' , bind ( this , 'onerror' ) ) ) ;
this . subs . push ( on ( socket , 'close' , bind ( this , 'onclose' ) ) ) ;
this . subs . push ( on ( this . decoder , 'decoded' , bind ( this , 'ondecoded' ) ) ) ;
} ;
/ * *
* Called upon a ping .
*
* @ api private
* /
Manager . prototype . onping = function ( ) {
this . lastPing = new Date ( ) ;
this . emitAll ( 'ping' ) ;
} ;
/ * *
* Called upon a packet .
*
* @ api private
* /
Manager . prototype . onpong = function ( ) {
this . emitAll ( 'pong' , new Date ( ) - this . lastPing ) ;
} ;
/ * *
* Called with data .
*
* @ api private
* /
Manager . prototype . ondata = function ( data ) {
this . decoder . add ( data ) ;
} ;
/ * *
* Called when parser fully decodes a packet .
*
* @ api private
* /
Manager . prototype . ondecoded = function ( packet ) {
this . emit ( 'packet' , packet ) ;
} ;
/ * *
* Called upon socket error .
*
* @ api private
* /
Manager . prototype . onerror = function ( err ) {
debug ( 'error' , err ) ;
this . emitAll ( 'error' , err ) ;
} ;
/ * *
* Creates a new socket for the given ` nsp ` .
*
* @ return { Socket }
* @ api public
* /
Manager . prototype . socket = function ( nsp , opts ) {
var socket = this . nsps [ nsp ] ;
if ( ! socket ) {
socket = new Socket ( this , nsp , opts ) ;
this . nsps [ nsp ] = socket ;
var self = this ;
socket . on ( 'connecting' , onConnecting ) ;
socket . on ( 'connect' , function ( ) {
socket . id = self . engine . id ;
} ) ;
if ( this . autoConnect ) {
// manually call here since connecting evnet is fired before listening
onConnecting ( ) ;
}
}
function onConnecting ( ) {
if ( ! ~ indexOf ( self . connecting , socket ) ) {
self . connecting . push ( socket ) ;
}
}
return socket ;
} ;
/ * *
* Called upon a socket close .
*
* @ param { Socket } socket
* /
Manager . prototype . destroy = function ( socket ) {
var index = indexOf ( this . connecting , socket ) ;
if ( ~ index ) this . connecting . splice ( index , 1 ) ;
if ( this . connecting . length ) return ;
this . close ( ) ;
} ;
/ * *
* Writes a packet .
*
* @ param { Object } packet
* @ api private
* /
Manager . prototype . packet = function ( packet ) {
debug ( 'writing packet %j' , packet ) ;
var self = this ;
if ( packet . query && packet . type === 0 ) packet . nsp += '?' + packet . query ;
if ( ! self . encoding ) {
// encode, then write to engine with result
self . encoding = true ;
this . encoder . encode ( packet , function ( encodedPackets ) {
for ( var i = 0 ; i < encodedPackets . length ; i ++ ) {
self . engine . write ( encodedPackets [ i ] , packet . options ) ;
}
self . encoding = false ;
self . processPacketQueue ( ) ;
} ) ;
} else { // add packet to the queue
self . packetBuffer . push ( packet ) ;
}
} ;
/ * *
* If packet buffer is non - empty , begins encoding the
* next packet in line .
*
* @ api private
* /
Manager . prototype . processPacketQueue = function ( ) {
if ( this . packetBuffer . length > 0 && ! this . encoding ) {
var pack = this . packetBuffer . shift ( ) ;
this . packet ( pack ) ;
}
} ;
/ * *
* Clean up transport subscriptions and packet buffer .
*
* @ api private
* /
Manager . prototype . cleanup = function ( ) {
debug ( 'cleanup' ) ;
var subsLength = this . subs . length ;
for ( var i = 0 ; i < subsLength ; i ++ ) {
var sub = this . subs . shift ( ) ;
sub . destroy ( ) ;
}
this . packetBuffer = [ ] ;
this . encoding = false ;
this . lastPing = null ;
this . decoder . destroy ( ) ;
} ;
/ * *
* Close the current socket .
*
* @ api private
* /
Manager . prototype . close =
Manager . prototype . disconnect = function ( ) {
debug ( 'disconnect' ) ;
this . skipReconnect = true ;
this . reconnecting = false ;
if ( 'opening' === this . readyState ) {
// `onclose` will not fire because
// an open event never happened
this . cleanup ( ) ;
}
this . backoff . reset ( ) ;
this . readyState = 'closed' ;
if ( this . engine ) this . engine . close ( ) ;
} ;
/ * *
* Called upon engine close .
*
* @ api private
* /
Manager . prototype . onclose = function ( reason ) {
debug ( 'onclose' ) ;
this . cleanup ( ) ;
this . backoff . reset ( ) ;
this . readyState = 'closed' ;
this . emit ( 'close' , reason ) ;
if ( this . _reconnection && ! this . skipReconnect ) {
this . reconnect ( ) ;
}
} ;
/ * *
* Attempt a reconnection .
*
* @ api private
* /
Manager . prototype . reconnect = function ( ) {
if ( this . reconnecting || this . skipReconnect ) return this ;
var self = this ;
if ( this . backoff . attempts >= this . _reconnectionAttempts ) {
debug ( 'reconnect failed' ) ;
this . backoff . reset ( ) ;
this . emitAll ( 'reconnect_failed' ) ;
this . reconnecting = false ;
} else {
var delay = this . backoff . duration ( ) ;
debug ( 'will wait %dms before reconnect attempt' , delay ) ;
this . reconnecting = true ;
var timer = setTimeout ( function ( ) {
if ( self . skipReconnect ) return ;
debug ( 'attempting reconnect' ) ;
self . emitAll ( 'reconnect_attempt' , self . backoff . attempts ) ;
self . emitAll ( 'reconnecting' , self . backoff . attempts ) ;
// check again for the case socket closed in above events
if ( self . skipReconnect ) return ;
self . open ( function ( err ) {
if ( err ) {
debug ( 'reconnect attempt error' ) ;
self . reconnecting = false ;
self . reconnect ( ) ;
self . emitAll ( 'reconnect_error' , err . data ) ;
} else {
debug ( 'reconnect success' ) ;
self . onreconnect ( ) ;
}
} ) ;
} , delay ) ;
this . subs . push ( {
destroy : function ( ) {
clearTimeout ( timer ) ;
}
} ) ;
}
} ;
/ * *
* Called upon successful reconnect .
*
* @ api private
* /
Manager . prototype . onreconnect = function ( ) {
var attempt = this . backoff . attempts ;
this . reconnecting = false ;
this . backoff . reset ( ) ;
this . updateSocketIds ( ) ;
this . emitAll ( 'reconnect' , attempt ) ;
} ;
2017-02-25 23:25:06 -05:00
} , { "./on" : 44 , "./socket" : 45 , "backo2" : 9 , "component-bind" : 12 , "component-emitter" : 47 , "debug" : 48 , "engine.io-client" : 18 , "indexof" : 35 , "socket.io-parser" : 51 } ] , 44 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module exports .
* /
module . exports = on ;
/ * *
* Helper for subscriptions .
*
* @ param { Object | EventEmitter } obj with ` Emitter ` mixin or ` EventEmitter `
* @ param { String } event name
* @ param { Function } callback
* @ api public
* /
function on ( obj , ev , fn ) {
obj . on ( ev , fn ) ;
return {
destroy : function ( ) {
obj . removeListener ( ev , fn ) ;
}
} ;
}
2017-02-25 23:25:06 -05:00
} , { } ] , 45 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var parser = require ( 'socket.io-parser' ) ;
var Emitter = require ( 'component-emitter' ) ;
var toArray = require ( 'to-array' ) ;
var on = require ( './on' ) ;
var bind = require ( 'component-bind' ) ;
var debug = require ( 'debug' ) ( 'socket.io-client:socket' ) ;
var hasBin = require ( 'has-binary' ) ;
/ * *
* Module exports .
* /
module . exports = exports = Socket ;
/ * *
* Internal events ( blacklisted ) .
* These events can ' t be emitted by the user .
*
* @ api private
* /
var events = {
connect : 1 ,
connect _error : 1 ,
connect _timeout : 1 ,
connecting : 1 ,
disconnect : 1 ,
error : 1 ,
reconnect : 1 ,
reconnect _attempt : 1 ,
reconnect _failed : 1 ,
reconnect _error : 1 ,
reconnecting : 1 ,
ping : 1 ,
pong : 1
} ;
/ * *
* Shortcut to ` Emitter#emit ` .
* /
var emit = Emitter . prototype . emit ;
/ * *
* ` Socket ` constructor .
*
* @ api public
* /
function Socket ( io , nsp , opts ) {
this . io = io ;
this . nsp = nsp ;
this . json = this ; // compat
this . ids = 0 ;
this . acks = { } ;
this . receiveBuffer = [ ] ;
this . sendBuffer = [ ] ;
this . connected = false ;
this . disconnected = true ;
if ( opts && opts . query ) {
this . query = opts . query ;
}
if ( this . io . autoConnect ) this . open ( ) ;
}
/ * *
* Mix in ` Emitter ` .
* /
Emitter ( Socket . prototype ) ;
/ * *
* Subscribe to open , close and packet events
*
* @ api private
* /
Socket . prototype . subEvents = function ( ) {
if ( this . subs ) return ;
var io = this . io ;
this . subs = [
on ( io , 'open' , bind ( this , 'onopen' ) ) ,
on ( io , 'packet' , bind ( this , 'onpacket' ) ) ,
on ( io , 'close' , bind ( this , 'onclose' ) )
] ;
} ;
/ * *
* "Opens" the socket .
*
* @ api public
* /
Socket . prototype . open =
Socket . prototype . connect = function ( ) {
if ( this . connected ) return this ;
this . subEvents ( ) ;
this . io . open ( ) ; // ensure open
if ( 'open' === this . io . readyState ) this . onopen ( ) ;
this . emit ( 'connecting' ) ;
return this ;
} ;
/ * *
* Sends a ` message ` event .
*
* @ return { Socket } self
* @ api public
* /
Socket . prototype . send = function ( ) {
var args = toArray ( arguments ) ;
args . unshift ( 'message' ) ;
this . emit . apply ( this , args ) ;
return this ;
} ;
/ * *
* Override ` emit ` .
* If the event is in ` events ` , it ' s emitted normally .
*
* @ param { String } event name
* @ return { Socket } self
* @ api public
* /
Socket . prototype . emit = function ( ev ) {
if ( events . hasOwnProperty ( ev ) ) {
emit . apply ( this , arguments ) ;
return this ;
}
var args = toArray ( arguments ) ;
var parserType = parser . EVENT ; // default
if ( hasBin ( args ) ) { parserType = parser . BINARY _EVENT ; } // binary
var packet = { type : parserType , data : args } ;
packet . options = { } ;
packet . options . compress = ! this . flags || false !== this . flags . compress ;
// event ack callback
if ( 'function' === typeof args [ args . length - 1 ] ) {
debug ( 'emitting packet with ack id %d' , this . ids ) ;
this . acks [ this . ids ] = args . pop ( ) ;
packet . id = this . ids ++ ;
}
if ( this . connected ) {
this . packet ( packet ) ;
} else {
this . sendBuffer . push ( packet ) ;
}
delete this . flags ;
return this ;
} ;
/ * *
* Sends a packet .
*
* @ param { Object } packet
* @ api private
* /
Socket . prototype . packet = function ( packet ) {
packet . nsp = this . nsp ;
this . io . packet ( packet ) ;
} ;
/ * *
* Called upon engine ` open ` .
*
* @ api private
* /
Socket . prototype . onopen = function ( ) {
debug ( 'transport is open - connecting' ) ;
// write connect packet if necessary
if ( '/' !== this . nsp ) {
if ( this . query ) {
this . packet ( { type : parser . CONNECT , query : this . query } ) ;
} else {
this . packet ( { type : parser . CONNECT } ) ;
}
}
} ;
/ * *
* Called upon engine ` close ` .
*
* @ param { String } reason
* @ api private
* /
Socket . prototype . onclose = function ( reason ) {
debug ( 'close (%s)' , reason ) ;
this . connected = false ;
this . disconnected = true ;
delete this . id ;
this . emit ( 'disconnect' , reason ) ;
} ;
/ * *
* Called with socket packet .
*
* @ param { Object } packet
* @ api private
* /
Socket . prototype . onpacket = function ( packet ) {
if ( packet . nsp !== this . nsp ) return ;
switch ( packet . type ) {
case parser . CONNECT :
this . onconnect ( ) ;
break ;
case parser . EVENT :
this . onevent ( packet ) ;
break ;
case parser . BINARY _EVENT :
this . onevent ( packet ) ;
break ;
case parser . ACK :
this . onack ( packet ) ;
break ;
case parser . BINARY _ACK :
this . onack ( packet ) ;
break ;
case parser . DISCONNECT :
this . ondisconnect ( ) ;
break ;
case parser . ERROR :
this . emit ( 'error' , packet . data ) ;
break ;
}
} ;
/ * *
* Called upon a server event .
*
* @ param { Object } packet
* @ api private
* /
Socket . prototype . onevent = function ( packet ) {
var args = packet . data || [ ] ;
debug ( 'emitting event %j' , args ) ;
if ( null != packet . id ) {
debug ( 'attaching ack callback to event' ) ;
args . push ( this . ack ( packet . id ) ) ;
}
if ( this . connected ) {
emit . apply ( this , args ) ;
} else {
this . receiveBuffer . push ( args ) ;
}
} ;
/ * *
* Produces an ack callback to emit with an event .
*
* @ api private
* /
Socket . prototype . ack = function ( id ) {
var self = this ;
var sent = false ;
return function ( ) {
// prevent double callbacks
if ( sent ) return ;
sent = true ;
var args = toArray ( arguments ) ;
debug ( 'sending ack %j' , args ) ;
var type = hasBin ( args ) ? parser . BINARY _ACK : parser . ACK ;
self . packet ( {
type : type ,
id : id ,
data : args
} ) ;
} ;
} ;
/ * *
* Called upon a server acknowlegement .
*
* @ param { Object } packet
* @ api private
* /
Socket . prototype . onack = function ( packet ) {
var ack = this . acks [ packet . id ] ;
if ( 'function' === typeof ack ) {
debug ( 'calling ack %s with %j' , packet . id , packet . data ) ;
ack . apply ( this , packet . data ) ;
delete this . acks [ packet . id ] ;
} else {
debug ( 'bad ack %s' , packet . id ) ;
}
} ;
/ * *
* Called upon server connect .
*
* @ api private
* /
Socket . prototype . onconnect = function ( ) {
this . connected = true ;
this . disconnected = false ;
this . emit ( 'connect' ) ;
this . emitBuffered ( ) ;
} ;
/ * *
* Emit buffered events ( received and emitted ) .
*
* @ api private
* /
Socket . prototype . emitBuffered = function ( ) {
var i ;
for ( i = 0 ; i < this . receiveBuffer . length ; i ++ ) {
emit . apply ( this , this . receiveBuffer [ i ] ) ;
}
this . receiveBuffer = [ ] ;
for ( i = 0 ; i < this . sendBuffer . length ; i ++ ) {
this . packet ( this . sendBuffer [ i ] ) ;
}
this . sendBuffer = [ ] ;
} ;
/ * *
* Called upon server disconnect .
*
* @ api private
* /
Socket . prototype . ondisconnect = function ( ) {
debug ( 'server disconnect (%s)' , this . nsp ) ;
this . destroy ( ) ;
this . onclose ( 'io server disconnect' ) ;
} ;
/ * *
* Called upon forced client / server side disconnections ,
* this method ensures the manager stops tracking us and
* that reconnections don ' t get triggered for this .
*
* @ api private .
* /
Socket . prototype . destroy = function ( ) {
if ( this . subs ) {
// clean subscriptions to avoid reconnections
for ( var i = 0 ; i < this . subs . length ; i ++ ) {
this . subs [ i ] . destroy ( ) ;
}
this . subs = null ;
}
this . io . destroy ( this ) ;
} ;
/ * *
* Disconnects the socket manually .
*
* @ return { Socket } self
* @ api public
* /
Socket . prototype . close =
Socket . prototype . disconnect = function ( ) {
if ( this . connected ) {
debug ( 'performing disconnect (%s)' , this . nsp ) ;
this . packet ( { type : parser . DISCONNECT } ) ;
}
// remove socket from pool
this . destroy ( ) ;
if ( this . connected ) {
// fire events
this . onclose ( 'io client disconnect' ) ;
}
return this ;
} ;
/ * *
* Sets the compress flag .
*
* @ param { Boolean } if ` true ` , compresses the sending data
* @ return { Socket } self
* @ api public
* /
Socket . prototype . compress = function ( compress ) {
this . flags = this . flags || { } ;
this . flags . compress = compress ;
return this ;
} ;
2017-02-25 23:25:06 -05:00
} , { "./on" : 44 , "component-bind" : 12 , "component-emitter" : 47 , "debug" : 48 , "has-binary" : 33 , "socket.io-parser" : 51 , "to-array" : 53 } ] , 46 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/ * *
* Module dependencies .
* /
var parseuri = require ( 'parseuri' ) ;
var debug = require ( 'debug' ) ( 'socket.io-client:url' ) ;
/ * *
* Module exports .
* /
module . exports = url ;
/ * *
* URL parser .
*
* @ param { String } url
* @ param { Object } An object meant to mimic window . location .
* Defaults to window . location .
* @ api public
* /
function url ( uri , loc ) {
var obj = uri ;
// default to window.location
loc = loc || global . location ;
if ( null == uri ) uri = loc . protocol + '//' + loc . host ;
// relative path support
if ( 'string' === typeof uri ) {
if ( '/' === uri . charAt ( 0 ) ) {
if ( '/' === uri . charAt ( 1 ) ) {
uri = loc . protocol + uri ;
} else {
uri = loc . host + uri ;
}
}
if ( ! /^(https?|wss?):\/\// . test ( uri ) ) {
debug ( 'protocol-less url %s' , uri ) ;
if ( 'undefined' !== typeof loc ) {
uri = loc . protocol + '//' + uri ;
} else {
uri = 'https://' + uri ;
}
}
// parse
debug ( 'parse %s' , uri ) ;
obj = parseuri ( uri ) ;
}
// make sure we treat `localhost:80` and `localhost` equally
if ( ! obj . port ) {
if ( /^(http|ws)$/ . test ( obj . protocol ) ) {
obj . port = '80' ;
} else if ( /^(http|ws)s$/ . test ( obj . protocol ) ) {
obj . port = '443' ;
}
}
obj . path = obj . path || '/' ;
var ipv6 = obj . host . indexOf ( ':' ) !== - 1 ;
var host = ipv6 ? '[' + obj . host + ']' : obj . host ;
// define unique id
obj . id = obj . protocol + '://' + host + ':' + obj . port ;
// define href
obj . href = obj . protocol + '://' + host + ( loc && loc . port === obj . port ? '' : ( ':' + obj . port ) ) ;
return obj ;
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "debug" : 48 , "parseuri" : 41 } ] , 47 : [ function ( require , module , exports ) {
arguments [ 4 ] [ 28 ] [ 0 ] . apply ( exports , arguments )
} , { "dup" : 28 } ] , 48 : [ function ( require , module , exports ) {
arguments [ 4 ] [ 29 ] [ 0 ] . apply ( exports , arguments )
} , { "./debug" : 49 , "_process" : 59 , "dup" : 29 } ] , 49 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
arguments [ 4 ] [ 30 ] [ 0 ] . apply ( exports , arguments )
2017-02-25 23:25:06 -05:00
} , { "dup" : 30 , "ms" : 38 } ] , 50 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/*global Blob,File*/
/ * *
* Module requirements
* /
var isArray = require ( 'isarray' ) ;
var isBuf = require ( './is-buffer' ) ;
/ * *
* Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder .
* Anything with blobs or files should be fed through removeBlobs before coming
* here .
*
* @ param { Object } packet - socket . io event packet
* @ return { Object } with deconstructed packet and list of buffers
* @ api public
* /
exports . deconstructPacket = function ( packet ) {
var buffers = [ ] ;
var packetData = packet . data ;
function _deconstructPacket ( data ) {
if ( ! data ) return data ;
if ( isBuf ( data ) ) {
var placeholder = { _placeholder : true , num : buffers . length } ;
buffers . push ( data ) ;
return placeholder ;
} else if ( isArray ( data ) ) {
var newData = new Array ( data . length ) ;
for ( var i = 0 ; i < data . length ; i ++ ) {
newData [ i ] = _deconstructPacket ( data [ i ] ) ;
}
return newData ;
} else if ( 'object' == typeof data && ! ( data instanceof Date ) ) {
var newData = { } ;
for ( var key in data ) {
newData [ key ] = _deconstructPacket ( data [ key ] ) ;
}
return newData ;
}
return data ;
}
var pack = packet ;
pack . data = _deconstructPacket ( packetData ) ;
pack . attachments = buffers . length ; // number of binary 'attachments'
return { packet : pack , buffers : buffers } ;
} ;
/ * *
* Reconstructs a binary packet from its placeholder packet and buffers
*
* @ param { Object } packet - event packet with placeholders
* @ param { Array } buffers - binary buffers to put in placeholder positions
* @ return { Object } reconstructed packet
* @ api public
* /
exports . reconstructPacket = function ( packet , buffers ) {
var curPlaceHolder = 0 ;
function _reconstructPacket ( data ) {
if ( data && data . _placeholder ) {
var buf = buffers [ data . num ] ; // appropriate buffer (should be natural order anyway)
return buf ;
} else if ( isArray ( data ) ) {
for ( var i = 0 ; i < data . length ; i ++ ) {
data [ i ] = _reconstructPacket ( data [ i ] ) ;
}
return data ;
} else if ( data && 'object' == typeof data ) {
for ( var key in data ) {
data [ key ] = _reconstructPacket ( data [ key ] ) ;
}
return data ;
}
return data ;
}
packet . data = _reconstructPacket ( packet . data ) ;
packet . attachments = undefined ; // no longer useful
return packet ;
} ;
/ * *
* Asynchronously removes Blobs or Files from data via
* FileReader ' s readAsArrayBuffer method . Used before encoding
* data as msgpack . Calls callback with the blobless data .
*
* @ param { Object } data
* @ param { Function } callback
* @ api private
* /
exports . removeBlobs = function ( data , callback ) {
function _removeBlobs ( obj , curKey , containingObject ) {
if ( ! obj ) return obj ;
// convert any blob
if ( ( global . Blob && obj instanceof Blob ) ||
( global . File && obj instanceof File ) ) {
pendingBlobs ++ ;
// async filereader
var fileReader = new FileReader ( ) ;
fileReader . onload = function ( ) { // this.result == arraybuffer
if ( containingObject ) {
containingObject [ curKey ] = this . result ;
}
else {
bloblessData = this . result ;
}
// if nothing pending its callback time
if ( ! -- pendingBlobs ) {
callback ( bloblessData ) ;
}
} ;
fileReader . readAsArrayBuffer ( obj ) ; // blob -> arraybuffer
} else if ( isArray ( obj ) ) { // handle array
for ( var i = 0 ; i < obj . length ; i ++ ) {
_removeBlobs ( obj [ i ] , i , obj ) ;
}
} else if ( obj && 'object' == typeof obj && ! isBuf ( obj ) ) { // and object
for ( var key in obj ) {
_removeBlobs ( obj [ key ] , key , obj ) ;
}
}
}
var pendingBlobs = 0 ;
var bloblessData = data ;
_removeBlobs ( bloblessData ) ;
if ( ! pendingBlobs ) {
callback ( bloblessData ) ;
}
} ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { "./is-buffer" : 52 , "isarray" : 36 } ] , 51 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
/ * *
* Module dependencies .
* /
var debug = require ( 'debug' ) ( 'socket.io-parser' ) ;
var json = require ( 'json3' ) ;
var Emitter = require ( 'component-emitter' ) ;
var binary = require ( './binary' ) ;
var isBuf = require ( './is-buffer' ) ;
/ * *
* Protocol version .
*
* @ api public
* /
exports . protocol = 4 ;
/ * *
* Packet types .
*
* @ api public
* /
exports . types = [
'CONNECT' ,
'DISCONNECT' ,
'EVENT' ,
'ACK' ,
'ERROR' ,
'BINARY_EVENT' ,
'BINARY_ACK'
] ;
/ * *
* Packet type ` connect ` .
*
* @ api public
* /
exports . CONNECT = 0 ;
/ * *
* Packet type ` disconnect ` .
*
* @ api public
* /
exports . DISCONNECT = 1 ;
/ * *
* Packet type ` event ` .
*
* @ api public
* /
exports . EVENT = 2 ;
/ * *
* Packet type ` ack ` .
*
* @ api public
* /
exports . ACK = 3 ;
/ * *
* Packet type ` error ` .
*
* @ api public
* /
exports . ERROR = 4 ;
/ * *
* Packet type 'binary event'
*
* @ api public
* /
exports . BINARY _EVENT = 5 ;
/ * *
* Packet type ` binary ack ` . For acks with binary arguments .
*
* @ api public
* /
exports . BINARY _ACK = 6 ;
/ * *
* Encoder constructor .
*
* @ api public
* /
exports . Encoder = Encoder ;
/ * *
* Decoder constructor .
*
* @ api public
* /
exports . Decoder = Decoder ;
/ * *
* A socket . io Encoder instance
*
* @ api public
* /
function Encoder ( ) { }
/ * *
* Encode a packet as a single string if non - binary , or as a
* buffer sequence , depending on packet type .
*
* @ param { Object } obj - packet object
* @ param { Function } callback - function to handle encodings ( likely engine . write )
* @ return Calls callback with Array of encodings
* @ api public
* /
Encoder . prototype . encode = function ( obj , callback ) {
debug ( 'encoding packet %j' , obj ) ;
if ( exports . BINARY _EVENT == obj . type || exports . BINARY _ACK == obj . type ) {
encodeAsBinary ( obj , callback ) ;
}
else {
var encoding = encodeAsString ( obj ) ;
callback ( [ encoding ] ) ;
}
} ;
/ * *
* Encode packet as string .
*
* @ param { Object } packet
* @ return { String } encoded
* @ api private
* /
function encodeAsString ( obj ) {
var str = '' ;
var nsp = false ;
// first is type
str += obj . type ;
// attachments if we have them
if ( exports . BINARY _EVENT == obj . type || exports . BINARY _ACK == obj . type ) {
str += obj . attachments ;
str += '-' ;
}
// if we have a namespace other than `/`
// we append it followed by a comma `,`
if ( obj . nsp && '/' != obj . nsp ) {
nsp = true ;
str += obj . nsp ;
}
// immediately followed by the id
if ( null != obj . id ) {
if ( nsp ) {
str += ',' ;
nsp = false ;
}
str += obj . id ;
}
// json data
if ( null != obj . data ) {
if ( nsp ) str += ',' ;
str += json . stringify ( obj . data ) ;
}
debug ( 'encoded %j as %s' , obj , str ) ;
return str ;
}
/ * *
* Encode packet as 'buffer sequence' by removing blobs , and
* deconstructing packet into object with placeholders and
* a list of buffers .
*
* @ param { Object } packet
* @ return { Buffer } encoded
* @ api private
* /
function encodeAsBinary ( obj , callback ) {
function writeEncoding ( bloblessData ) {
var deconstruction = binary . deconstructPacket ( bloblessData ) ;
var pack = encodeAsString ( deconstruction . packet ) ;
var buffers = deconstruction . buffers ;
buffers . unshift ( pack ) ; // add packet info to beginning of data list
callback ( buffers ) ; // write all the buffers
}
binary . removeBlobs ( obj , writeEncoding ) ;
}
/ * *
* A socket . io Decoder instance
*
* @ return { Object } decoder
* @ api public
* /
function Decoder ( ) {
this . reconstructor = null ;
}
/ * *
* Mix in ` Emitter ` with Decoder .
* /
Emitter ( Decoder . prototype ) ;
/ * *
* Decodes an ecoded packet string into packet JSON .
*
* @ param { String } obj - encoded packet
* @ return { Object } packet
* @ api public
* /
Decoder . prototype . add = function ( obj ) {
var packet ;
if ( 'string' == typeof obj ) {
packet = decodeString ( obj ) ;
if ( exports . BINARY _EVENT == packet . type || exports . BINARY _ACK == packet . type ) { // binary packet's json
this . reconstructor = new BinaryReconstructor ( packet ) ;
// no attachments, labeled binary but no binary data to follow
if ( this . reconstructor . reconPack . attachments === 0 ) {
this . emit ( 'decoded' , packet ) ;
}
} else { // non-binary full packet
this . emit ( 'decoded' , packet ) ;
}
}
else if ( isBuf ( obj ) || obj . base64 ) { // raw binary data
if ( ! this . reconstructor ) {
throw new Error ( 'got binary data when not reconstructing a packet' ) ;
} else {
packet = this . reconstructor . takeBinaryData ( obj ) ;
if ( packet ) { // received final buffer
this . reconstructor = null ;
this . emit ( 'decoded' , packet ) ;
}
}
}
else {
throw new Error ( 'Unknown type: ' + obj ) ;
}
} ;
/ * *
* Decode a packet String ( JSON data )
*
* @ param { String } str
* @ return { Object } packet
* @ api private
* /
function decodeString ( str ) {
var p = { } ;
var i = 0 ;
// look up type
p . type = Number ( str . charAt ( 0 ) ) ;
if ( null == exports . types [ p . type ] ) return error ( ) ;
// look up attachments if type binary
if ( exports . BINARY _EVENT == p . type || exports . BINARY _ACK == p . type ) {
var buf = '' ;
while ( str . charAt ( ++ i ) != '-' ) {
buf += str . charAt ( i ) ;
if ( i == str . length ) break ;
}
if ( buf != Number ( buf ) || str . charAt ( i ) != '-' ) {
throw new Error ( 'Illegal attachments' ) ;
}
p . attachments = Number ( buf ) ;
}
// look up namespace (if any)
if ( '/' == str . charAt ( i + 1 ) ) {
p . nsp = '' ;
while ( ++ i ) {
var c = str . charAt ( i ) ;
if ( ',' == c ) break ;
p . nsp += c ;
if ( i == str . length ) break ;
}
} else {
p . nsp = '/' ;
}
// look up id
var next = str . charAt ( i + 1 ) ;
if ( '' !== next && Number ( next ) == next ) {
p . id = '' ;
while ( ++ i ) {
var c = str . charAt ( i ) ;
if ( null == c || Number ( c ) != c ) {
-- i ;
break ;
}
p . id += str . charAt ( i ) ;
if ( i == str . length ) break ;
}
p . id = Number ( p . id ) ;
}
// look up json data
if ( str . charAt ( ++ i ) ) {
p = tryParse ( p , str . substr ( i ) ) ;
}
debug ( 'decoded %s as %j' , str , p ) ;
return p ;
}
function tryParse ( p , str ) {
try {
p . data = json . parse ( str ) ;
} catch ( e ) {
return error ( ) ;
}
return p ;
} ;
/ * *
* Deallocates a parser ' s resources
*
* @ api public
* /
Decoder . prototype . destroy = function ( ) {
if ( this . reconstructor ) {
this . reconstructor . finishedReconstruction ( ) ;
}
} ;
/ * *
* A manager of a binary event 's ' buffer sequence ' . Should
* be constructed whenever a packet of type BINARY _EVENT is
* decoded .
*
* @ param { Object } packet
* @ return { BinaryReconstructor } initialized reconstructor
* @ api private
* /
function BinaryReconstructor ( packet ) {
this . reconPack = packet ;
this . buffers = [ ] ;
}
/ * *
* Method to be called when binary data received from connection
* after a BINARY _EVENT packet .
*
* @ param { Buffer | ArrayBuffer } binData - the raw binary data received
* @ return { null | Object } returns null if more binary data is expected or
* a reconstructed packet object if all buffers have been received .
* @ api private
* /
BinaryReconstructor . prototype . takeBinaryData = function ( binData ) {
this . buffers . push ( binData ) ;
if ( this . buffers . length == this . reconPack . attachments ) { // done with buffer list
var packet = binary . reconstructPacket ( this . reconPack , this . buffers ) ;
this . finishedReconstruction ( ) ;
return packet ;
}
return null ;
} ;
/ * *
* Cleans up binary packet reconstruction variables .
*
* @ api private
* /
BinaryReconstructor . prototype . finishedReconstruction = function ( ) {
this . reconPack = null ;
this . buffers = [ ] ;
} ;
function error ( data ) {
return {
type : exports . ERROR ,
data : 'parser error'
} ;
}
2017-02-25 23:25:06 -05:00
} , { "./binary" : 50 , "./is-buffer" : 52 , "component-emitter" : 13 , "debug" : 15 , "json3" : 37 } ] , 52 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
module . exports = isBuf ;
/ * *
* Returns true if obj is a buffer or an arraybuffer .
*
* @ api private
* /
function isBuf ( obj ) {
return ( global . Buffer && global . Buffer . isBuffer ( obj ) ) ||
( global . ArrayBuffer && obj instanceof ArrayBuffer ) ;
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { } ] , 53 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
module . exports = toArray
function toArray ( list , index ) {
var array = [ ]
index = index || 0
for ( var i = index || 0 ; i < list . length ; i ++ ) {
array [ i - index ] = list [ i ]
}
return array
}
2017-02-25 23:25:06 -05:00
} , { } ] , 54 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
( function ( global ) {
/*! https://mths.be/wtf8 v1.0.0 by @mathias */
; ( function ( root ) {
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports ;
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module . exports == freeExports && module ;
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global ;
if ( freeGlobal . global === freeGlobal || freeGlobal . window === freeGlobal ) {
root = freeGlobal ;
}
/*--------------------------------------------------------------------------*/
var stringFromCharCode = String . fromCharCode ;
// Taken from https://mths.be/punycode
function ucs2decode ( string ) {
var output = [ ] ;
var counter = 0 ;
var length = string . length ;
var value ;
var extra ;
while ( counter < length ) {
value = string . charCodeAt ( counter ++ ) ;
if ( value >= 0xD800 && value <= 0xDBFF && counter < length ) {
// high surrogate, and there is a next character
extra = string . charCodeAt ( counter ++ ) ;
if ( ( extra & 0xFC00 ) == 0xDC00 ) { // low surrogate
output . push ( ( ( value & 0x3FF ) << 10 ) + ( extra & 0x3FF ) + 0x10000 ) ;
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output . push ( value ) ;
counter -- ;
}
} else {
output . push ( value ) ;
}
}
return output ;
}
// Taken from https://mths.be/punycode
function ucs2encode ( array ) {
var length = array . length ;
var index = - 1 ;
var value ;
var output = '' ;
while ( ++ index < length ) {
value = array [ index ] ;
if ( value > 0xFFFF ) {
value -= 0x10000 ;
output += stringFromCharCode ( value >>> 10 & 0x3FF | 0xD800 ) ;
value = 0xDC00 | value & 0x3FF ;
}
output += stringFromCharCode ( value ) ;
}
return output ;
}
/*--------------------------------------------------------------------------*/
function createByte ( codePoint , shift ) {
return stringFromCharCode ( ( ( codePoint >> shift ) & 0x3F ) | 0x80 ) ;
}
function encodeCodePoint ( codePoint ) {
if ( ( codePoint & 0xFFFFFF80 ) == 0 ) { // 1-byte sequence
return stringFromCharCode ( codePoint ) ;
}
var symbol = '' ;
if ( ( codePoint & 0xFFFFF800 ) == 0 ) { // 2-byte sequence
symbol = stringFromCharCode ( ( ( codePoint >> 6 ) & 0x1F ) | 0xC0 ) ;
}
else if ( ( codePoint & 0xFFFF0000 ) == 0 ) { // 3-byte sequence
symbol = stringFromCharCode ( ( ( codePoint >> 12 ) & 0x0F ) | 0xE0 ) ;
symbol += createByte ( codePoint , 6 ) ;
}
else if ( ( codePoint & 0xFFE00000 ) == 0 ) { // 4-byte sequence
symbol = stringFromCharCode ( ( ( codePoint >> 18 ) & 0x07 ) | 0xF0 ) ;
symbol += createByte ( codePoint , 12 ) ;
symbol += createByte ( codePoint , 6 ) ;
}
symbol += stringFromCharCode ( ( codePoint & 0x3F ) | 0x80 ) ;
return symbol ;
}
function wtf8encode ( string ) {
var codePoints = ucs2decode ( string ) ;
var length = codePoints . length ;
var index = - 1 ;
var codePoint ;
var byteString = '' ;
while ( ++ index < length ) {
codePoint = codePoints [ index ] ;
byteString += encodeCodePoint ( codePoint ) ;
}
return byteString ;
}
/*--------------------------------------------------------------------------*/
function readContinuationByte ( ) {
if ( byteIndex >= byteCount ) {
throw Error ( 'Invalid byte index' ) ;
}
var continuationByte = byteArray [ byteIndex ] & 0xFF ;
byteIndex ++ ;
if ( ( continuationByte & 0xC0 ) == 0x80 ) {
return continuationByte & 0x3F ;
}
// If we end up here, it’ s not a continuation byte.
throw Error ( 'Invalid continuation byte' ) ;
}
function decodeSymbol ( ) {
var byte1 ;
var byte2 ;
var byte3 ;
var byte4 ;
var codePoint ;
if ( byteIndex > byteCount ) {
throw Error ( 'Invalid byte index' ) ;
}
if ( byteIndex == byteCount ) {
return false ;
}
// Read the first byte.
byte1 = byteArray [ byteIndex ] & 0xFF ;
byteIndex ++ ;
// 1-byte sequence (no continuation bytes)
if ( ( byte1 & 0x80 ) == 0 ) {
return byte1 ;
}
// 2-byte sequence
if ( ( byte1 & 0xE0 ) == 0xC0 ) {
var byte2 = readContinuationByte ( ) ;
codePoint = ( ( byte1 & 0x1F ) << 6 ) | byte2 ;
if ( codePoint >= 0x80 ) {
return codePoint ;
} else {
throw Error ( 'Invalid continuation byte' ) ;
}
}
// 3-byte sequence (may include unpaired surrogates)
if ( ( byte1 & 0xF0 ) == 0xE0 ) {
byte2 = readContinuationByte ( ) ;
byte3 = readContinuationByte ( ) ;
codePoint = ( ( byte1 & 0x0F ) << 12 ) | ( byte2 << 6 ) | byte3 ;
if ( codePoint >= 0x0800 ) {
return codePoint ;
} else {
throw Error ( 'Invalid continuation byte' ) ;
}
}
// 4-byte sequence
if ( ( byte1 & 0xF8 ) == 0xF0 ) {
byte2 = readContinuationByte ( ) ;
byte3 = readContinuationByte ( ) ;
byte4 = readContinuationByte ( ) ;
codePoint = ( ( byte1 & 0x0F ) << 0x12 ) | ( byte2 << 0x0C ) |
( byte3 << 0x06 ) | byte4 ;
if ( codePoint >= 0x010000 && codePoint <= 0x10FFFF ) {
return codePoint ;
}
}
throw Error ( 'Invalid WTF-8 detected' ) ;
}
var byteArray ;
var byteCount ;
var byteIndex ;
function wtf8decode ( byteString ) {
byteArray = ucs2decode ( byteString ) ;
byteCount = byteArray . length ;
byteIndex = 0 ;
var codePoints = [ ] ;
var tmp ;
while ( ( tmp = decodeSymbol ( ) ) !== false ) {
codePoints . push ( tmp ) ;
}
return ucs2encode ( codePoints ) ;
}
/*--------------------------------------------------------------------------*/
var wtf8 = {
'version' : '1.0.0' ,
'encode' : wtf8encode ,
'decode' : wtf8decode
} ;
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define . amd == 'object' &&
define . amd
) {
define ( function ( ) {
return wtf8 ;
} ) ;
} else if ( freeExports && ! freeExports . nodeType ) {
if ( freeModule ) { // in Node.js or RingoJS v0.8.0+
freeModule . exports = wtf8 ;
} else { // in Narwhal or RingoJS v0.7.0-
var object = { } ;
var hasOwnProperty = object . hasOwnProperty ;
for ( var key in wtf8 ) {
hasOwnProperty . call ( wtf8 , key ) && ( freeExports [ key ] = wtf8 [ key ] ) ;
}
}
} else { // in Rhino or a web browser
root . wtf8 = wtf8 ;
}
} ( this ) ) ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-25 23:25:06 -05:00
} , { } ] , 55 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
'use strict' ;
var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_' . split ( '' )
, length = 64
, map = { }
, seed = 0
, i = 0
, prev ;
/ * *
* Return a string representing the specified number .
*
* @ param { Number } num The number to convert .
* @ returns { String } The string representation of the number .
* @ api public
* /
function encode ( num ) {
var encoded = '' ;
do {
encoded = alphabet [ num % length ] + encoded ;
num = Math . floor ( num / length ) ;
} while ( num > 0 ) ;
return encoded ;
}
/ * *
* Return the integer value specified by the given string .
*
* @ param { String } str The string to convert .
* @ returns { Number } The integer value represented by the string .
* @ api public
* /
function decode ( str ) {
var decoded = 0 ;
for ( i = 0 ; i < str . length ; i ++ ) {
decoded = decoded * length + map [ str . charAt ( i ) ] ;
}
return decoded ;
}
/ * *
* Yeast : A tiny growing id generator .
*
* @ returns { String } A unique id .
* @ api public
* /
function yeast ( ) {
var now = encode ( + new Date ( ) ) ;
if ( now !== prev ) return seed = 0 , prev = now ;
return now + '.' + encode ( seed ++ ) ;
}
//
// Map each character to its index.
//
for ( ; i < length ; i ++ ) map [ alphabet [ i ] ] = i ;
//
// Expose the `yeast`, `encode` and `decode` functions.
//
yeast . encode = encode ;
yeast . decode = decode ;
module . exports = yeast ;
2017-02-25 23:25:06 -05:00
} , { } ] , 56 : [ function ( require , module , exports ) {
2017-02-25 21:36:44 -05:00
var Stack = require ( "./stack.js" ) ;
var Color = require ( "./color.js" ) ;
var Grid = require ( "./grid.js" ) ;
var consts = require ( "./game-consts.js" ) ;
var GRID _SIZE = consts . GRID _SIZE ;
var CELL _WIDTH = consts . CELL _WIDTH ;
function defineGetter ( getter ) {
return {
get : getter ,
enumerable : true
} ;
}
function defineInstanceMethods ( thisobj , data /*, methods...*/ )
{
for ( var i = 2 ; i < arguments . length ; i ++ )
thisobj [ arguments [ i ] . name ] = arguments [ i ] . bind ( this , data ) ;
}
function defineAccessorProperties ( thisobj , data /*, names...*/ )
{
var descript = { } ;
function getAt ( name ) { return function ( ) { return data [ name ] } }
for ( var i = 2 ; i < arguments . length ; i ++ )
descript [ arguments [ i ] ] = defineGetter ( getAt ( arguments [ i ] ) ) ;
Object . defineProperties ( thisobj , descript ) ;
}
function TailMove ( orientation )
{
this . move = 1 ;
Object . defineProperty ( this , "orientation" , {
value : orientation ,
enumerable : true
} ) ;
}
function Tail ( player , sdata )
{
var data = {
tail : [ ] ,
tailGrid : [ ] ,
prev : null ,
startRow : 0 ,
startCol : 0 ,
prevRow : 0 ,
prevCol : 0 ,
player : player
} ;
if ( sdata )
{
data . startRow = data . prevRow = sdata . startRow || 0 ;
data . startCol = data . prevCol = sdata . startCol || 0 ;
sdata . tail . forEach ( function ( val ) {
addTail ( data , val . orientation , val . move ) ;
} ) ;
}
data . grid = player . grid ;
defineInstanceMethods ( this , data , addTail , hitsTail , fillTail , renderTail , reposition , serialData ) ;
Object . defineProperty ( this , "moves" , {
get : function ( ) { return data . tail . slice ( 0 ) ; } ,
enumerable : true
} ) ;
}
//Instance methods.
2017-02-23 23:10:36 -05:00
function serialData ( data ) {
2017-02-25 21:36:44 -05:00
return {
2017-02-23 23:10:36 -05:00
tail : data . tail ,
startRow : data . startRow ,
startCol : data . startCol
2017-02-25 21:36:44 -05:00
} ;
2017-02-23 23:10:36 -05:00
}
function setTailGrid ( data , tailGrid , r , c )
{
if ( ! tailGrid [ r ] )
tailGrid [ r ] = [ ] ;
tailGrid [ r ] [ c ] = true ;
}
function addTail ( data , orientation , count )
{
if ( count === undefined )
count = 1 ;
if ( ! count || count < 0 )
return ;
var prev = data . prev ;
var r = data . prevRow , c = data . prevCol ;
if ( data . tail . length === 0 )
setTailGrid ( data , data . tailGrid , r , c ) ;
if ( ! prev || prev . orientation !== orientation )
{
prev = data . prev = new TailMove ( orientation ) ;
data . tail . push ( prev ) ;
2017-02-26 02:31:30 -05:00
prev . move += count - 1 ;
2017-02-23 23:10:36 -05:00
}
else
prev . move += count ;
for ( var i = 0 ; i < count ; i ++ )
{
var pos = walk ( [ data . prevRow , data . prevCol ] , null , orientation , 1 ) ;
data . prevRow = pos [ 0 ] ;
data . prevCol = pos [ 1 ] ;
setTailGrid ( data , data . tailGrid , pos [ 0 ] , pos [ 1 ] ) ;
}
}
function reposition ( data , row , col )
{
data . prevRow = data . startRow = row ;
data . prevCol = data . startCol = col ;
data . prev = null ;
if ( data . tail . length === 0 )
return ;
else
{
var ret = data . tail ;
data . tail = [ ] ;
data . tailGrid = [ ] ;
return ret ;
}
}
/ *
function render2 ( data , ctx )
{
ctx . fillStyle = data . player . tailColor . rgbString ( ) ;
for ( var r = 0 ; r < data . tailGrid . length ; r ++ )
{
if ( ! data . tailGrid [ r ] )
continue ;
for ( var c = 0 ; c < data . tailGrid [ r ] . length ; c ++ )
if ( data . tailGrid [ r ] [ c ] )
ctx . fillRect ( c * CELL _WIDTH , r * CELL _WIDTH , CELL _WIDTH , CELL _WIDTH ) ;
}
}
* /
//Helper methods.
function renderTail ( data , ctx )
{
if ( data . tail . length === 0 )
return ;
ctx . fillStyle = data . player . tailColor . rgbString ( ) ;
var prevOrient = - 1 ;
var start = [ data . startRow , data . startCol ] ;
//fillTailRect(ctx, start, start);
data . tail . forEach ( function ( tail ) {
var negDir = tail . orientation === 0 || tail . orientation === 3 ;
var back = start ;
if ( ! negDir )
start = walk ( start , null , tail . orientation , 1 ) ;
var finish = walk ( start , null , tail . orientation , tail . move - 1 ) ;
if ( tail . move > 1 )
fillTailRect ( ctx , start , finish ) ;
if ( prevOrient !== - 1 )
//Draw folding triangle.
renderCorner ( ctx , back , prevOrient , tail . orientation ) ;
start = finish ;
if ( negDir )
walk ( start , start , tail . orientation , 1 ) ;
prevOrient = tail . orientation ;
} ) ;
var curOrient = data . player . currentHeading ;
if ( prevOrient === curOrient )
{
fillTailRect ( ctx , start , start ) ;
}
else
renderCorner ( ctx , start , prevOrient , curOrient ) ;
}
function renderCorner ( ctx , cornerStart , dir1 , dir2 )
{
if ( dir1 === 0 || dir2 === 0 )
walk ( cornerStart , cornerStart , 2 , 1 ) ;
if ( dir1 === 3 || dir2 === 3 )
walk ( cornerStart , cornerStart , 1 , 1 ) ;
var a = walk ( cornerStart , null , dir2 , 1 ) ;
var b = walk ( a , null , dir1 , 1 ) ;
var triangle = new Path2D ( ) ;
triangle . moveTo ( cornerStart [ 1 ] * CELL _WIDTH , cornerStart [ 0 ] * CELL _WIDTH ) ;
triangle . lineTo ( a [ 1 ] * CELL _WIDTH , a [ 0 ] * CELL _WIDTH ) ;
triangle . lineTo ( b [ 1 ] * CELL _WIDTH , b [ 0 ] * CELL _WIDTH ) ;
triangle . closePath ( ) ;
for ( var i = 0 ; i < 2 ; i ++ )
ctx . fill ( triangle ) ;
}
function walk ( from , ret , orient , dist )
{
ret = ret || [ ] ;
ret [ 0 ] = from [ 0 ] ;
ret [ 1 ] = from [ 1 ] ;
switch ( orient )
{
case 0 : ret [ 0 ] -= dist ; break ; //UP
case 1 : ret [ 1 ] += dist ; break ; //RIGHT
case 2 : ret [ 0 ] += dist ; break ; //DOWN
case 3 : ret [ 1 ] -= dist ; break ; //LEFT
}
return ret ;
}
function fillTailRect ( ctx , start , end )
{
var x = start [ 1 ] * CELL _WIDTH ;
var y = start [ 0 ] * CELL _WIDTH ;
var width = ( end [ 1 ] - start [ 1 ] ) * CELL _WIDTH ;
var height = ( end [ 0 ] - start [ 0 ] ) * CELL _WIDTH ;
if ( width === 0 )
width += CELL _WIDTH ;
if ( height === 0 )
height += CELL _WIDTH ;
if ( width < 0 )
{
x += width ;
width = - width ;
}
if ( height < 0 )
{
y += height ;
height = - height ;
}
ctx . fillRect ( x , y , width , height ) ;
}
//TODO: fade in colors using grid property-getters/setters
2017-02-25 00:33:34 -05:00
function fillTail ( data )
2017-02-23 23:10:36 -05:00
{
if ( data . tail . length === 0 )
return ;
function onTail ( c ) { return data . tailGrid [ c [ 0 ] ] && data . tailGrid [ c [ 0 ] ] [ c [ 1 ] ] ; }
2017-02-25 00:33:34 -05:00
var grid = data . grid ;
2017-02-23 23:10:36 -05:00
var start = [ data . startRow , data . startCol ] ;
var been = new Grid ( grid . size ) ;
var coords = [ ] ;
coords . push ( start ) ;
while ( coords . length > 0 ) //BFS for all tail spaces.
{
var coord = coords . shift ( ) ;
var r = coord [ 0 ] ;
var c = coord [ 1 ] ;
if ( grid . isOutOfBounds ( r , c ) )
continue ;
if ( been . get ( r , c ) )
continue ;
if ( onTail ( coord ) ) //on the tail.
{
been . set ( r , c , true ) ;
grid . set ( r , c , data . player ) ;
//Find all spots that this tail encloses.
floodFill ( data , grid , r + 1 , c , been ) ;
floodFill ( data , grid , r - 1 , c , been ) ;
floodFill ( data , grid , r , c + 1 , been ) ;
floodFill ( data , grid , r , c - 1 , been ) ;
coords . push ( [ r + 1 , c ] ) ;
coords . push ( [ r - 1 , c ] ) ;
coords . push ( [ r , c + 1 ] ) ;
coords . push ( [ r , c - 1 ] ) ;
}
}
}
function floodFill ( data , grid , row , col , been )
{
var coords = [ ] ;
var filled = new Stack ( 40000 ) ;
var surrounded = true ;
function onTail ( c ) { return data . tailGrid [ c [ 0 ] ] && data . tailGrid [ c [ 0 ] ] [ c [ 1 ] ] ; }
coords . push ( [ row , col ] ) ;
while ( coords . length > 0 )
{
var coord = coords . shift ( ) ;
var r = coord [ 0 ] ;
var c = coord [ 1 ] ;
if ( grid . isOutOfBounds ( r , c ) )
{
surrounded = false ;
continue ;
}
//End this traverse on boundaries (where we been, on the tail, and when we enter our territory)
if ( been . get ( r , c ) || onTail ( coord ) || grid . get ( r , c ) === data . player )
continue ;
been . set ( r , c , true ) ;
if ( surrounded )
filled . push ( coord ) ;
coords . push ( [ r + 1 , c ] ) ;
coords . push ( [ r - 1 , c ] ) ;
coords . push ( [ r , c + 1 ] ) ;
coords . push ( [ r , c - 1 ] ) ;
}
if ( surrounded )
{
while ( ! filled . isEmpty ( ) )
{
coord = filled . pop ( ) ;
grid . set ( coord [ 0 ] , coord [ 1 ] , data . player ) ;
}
}
return surrounded ;
}
function hitsTail ( data , other )
{
return ( data . prevRow !== other . row || data . prevCol !== other . col ) &&
( data . startRow !== other . row || data . startCol !== other . col ) &&
! ! ( data . tailGrid [ other . row ] && data . tailGrid [ other . row ] [ other . col ] ) ;
}
var SPEED = 5 ;
var SHADOW _OFFSET = 10 ;
function Player ( isClient , grid , sdata ) {
var data = { } ;
//Parameters
data . num = sdata . num ;
data . name = sdata . name || "Player " + ( data . num + 1 ) ;
data . isCient = isClient ;
data . grid = grid ;
data . posX = sdata . posX ;
data . posY = sdata . posY ;
this . heading = data . currentHeading = sdata . currentHeading ; //0 is up, 1 is right, 2 is down, 3 is left.
data . dead = false ;
//Only need colors for client side.
if ( isClient )
{
var hue = Math . random ( ) ;
var base = new Color ( hue , . 8 , . 5 ) ;
this . baseColor = base ;
this . shadowColor = base . deriveLumination ( - . 3 ) ;
this . tailColor = base . deriveLumination ( . 2 ) . deriveAlpha ( . 5 ) ;
}
//Tail requires special handling.
2017-02-25 00:33:34 -05:00
this . grid = grid ; //Temporary
2017-02-23 23:10:36 -05:00
if ( sdata . tail )
data . tail = new Tail ( this , sdata . tail ) ;
else
{
data . tail = new Tail ( this ) ;
2017-02-25 00:33:34 -05:00
data . tail . reposition ( calcRow ( data ) , calcCol ( data ) ) ;
2017-02-23 23:10:36 -05:00
}
//Instance methods.
this . move = move . bind ( this , data ) ;
this . die = function ( ) { data . dead = true ; } ;
2017-02-24 19:57:13 -05:00
this . serialData = function ( ) {
return {
num : data . num ,
name : data . name ,
posX : data . posX ,
posY : data . posY ,
currentHeading : data . currentHeading ,
tail : data . tail . serialData ( )
} ;
2017-02-25 18:52:52 -05:00
} ;
2017-02-25 00:33:34 -05:00
2017-02-23 23:10:36 -05:00
//Read-only Properties.
2017-02-25 00:33:34 -05:00
defineAccessorProperties ( this , data , "currentHeading" , "dead" , "name" , "num" , "posX" , "posY" , "grid" , "tail" ) ;
2017-02-23 23:10:36 -05:00
Object . defineProperties ( this , {
2017-02-25 00:33:34 -05:00
row : defineGetter ( function ( ) { return calcRow ( data ) ; } ) ,
col : defineGetter ( function ( ) { return calcCol ( data ) ; } )
2017-02-23 23:10:36 -05:00
} ) ;
}
2017-02-25 00:33:34 -05:00
//Gets the next integer in positive or negative direction.
function nearestInteger ( positive , val )
{
return positive ? Math . ceil ( val ) : Math . floor ( val ) ;
}
function calcRow ( data )
{
return nearestInteger ( data . currentHeading === 2 /*DOWN*/ , data . posY / CELL _WIDTH ) ;
}
function calcCol ( data )
{
return nearestInteger ( data . currentHeading === 1 /*RIGHT*/ , data . posX / CELL _WIDTH ) ;
}
2017-02-23 23:10:36 -05:00
//Instance methods
Player . prototype . render = function ( ctx , fade )
{
//Render tail.
this . tail . renderTail ( ctx ) ;
//Render player.
fade = fade || 1 ;
ctx . fillStyle = this . shadowColor . deriveAlpha ( fade ) . rgbString ( ) ;
ctx . fillRect ( this . posX , this . posY , CELL _WIDTH , CELL _WIDTH ) ;
var mid = CELL _WIDTH / 2 ;
var grd = ctx . createRadialGradient ( this . posX + mid , this . posY + mid - SHADOW _OFFSET , 1 ,
this . posX + mid , this . posY + mid - SHADOW _OFFSET , CELL _WIDTH ) ;
2017-02-25 21:36:44 -05:00
grd . addColorStop ( 0 , this . baseColor . deriveAlpha ( fade ) . rgbString ( ) ) ;
2017-02-25 18:52:52 -05:00
grd . addColorStop ( 1 , new Color ( 0 , 0 , 1 , fade ) . rgbString ( ) ) ;
2017-02-23 23:10:36 -05:00
ctx . fillStyle = grd ;
2017-02-25 18:52:52 -05:00
ctx . fillRect ( this . posX - 1 , this . posY - SHADOW _OFFSET , CELL _WIDTH + 2 , CELL _WIDTH ) ;
2017-02-23 23:10:36 -05:00
//Render name
ctx . fillStyle = this . shadowColor . deriveAlpha ( fade ) . rgbString ( ) ;
ctx . textAlign = "center" ;
2017-02-24 02:17:49 -05:00
2017-02-25 18:52:52 -05:00
var yoff = - SHADOW _OFFSET * 2 ;
2017-02-24 02:17:49 -05:00
if ( this . row === 0 )
yoff = SHADOW _OFFSET * 2 + CELL _WIDTH ;
ctx . font = "18px Changa" ;
ctx . fillText ( this . name , this . posX + CELL _WIDTH / 2 , this . posY + yoff ) ;
2017-02-23 23:10:36 -05:00
} ;
function move ( data )
{
//Move to new position.
var heading = this . heading ;
if ( this . posX % CELL _WIDTH !== 0 || this . posY % CELL _WIDTH !== 0 )
heading = data . currentHeading ;
else
data . currentHeading = heading ;
switch ( heading )
{
case 0 : data . posY -= SPEED ; break ; //UP
case 1 : data . posX += SPEED ; break ; //RIGHT
case 2 : data . posY += SPEED ; break ; //DOWN
case 3 : data . posX -= SPEED ; break ; //LEFT
}
//Check for out of bounds.
var row = this . row , col = this . col ;
if ( data . grid . isOutOfBounds ( row , col ) )
{
data . dead = true ;
return ;
}
//Update tail position.
if ( data . grid . get ( row , col ) === this )
{
//Safe zone!
2017-02-25 00:33:34 -05:00
this . tail . fillTail ( ) ;
2017-02-23 23:10:36 -05:00
this . tail . reposition ( row , col ) ;
}
//If we are completely in a new cell (not in our safe zone), we add to the tail.
else if ( this . posX % CELL _WIDTH === 0 && this . posY % CELL _WIDTH === 0 )
this . tail . addTail ( heading ) ;
}
module . exports = Player ;
2017-02-25 23:25:06 -05:00
} , { "./color.js" : 1 , "./game-consts.js" : 3 , "./grid.js" : 6 , "./stack.js" : 57 } ] , 57 : [ function ( require , module , exports ) {
2017-02-23 23:10:36 -05:00
function Stack ( initSize )
{
var len = 0 ;
var arr = [ ] ;
this . ensureCapacity = function ( size )
{
arr . length = Math . max ( arr . length , size || 0 ) ;
} ;
this . push = function ( ele )
{
this [ len ] = ele ;
len ++ ;
} ;
this . pop = function ( )
{
if ( len === 0 )
return ;
len -- ;
var tmp = this [ len ] ;
this [ len ] = undefined ;
return tmp ;
} ;
this . isEmpty = function ( ) {
return len === 0 ;
}
this . ensureCapacity ( initSize ) ;
Object . defineProperty ( this , "length" , {
get : function ( ) { return len ; }
} ) ;
}
module . exports = Stack ;
2017-02-25 23:25:06 -05:00
} , { } ] , 58 : [ function ( require , module , exports ) {
} , { } ] , 59 : [ function ( require , module , exports ) {
// shim for using process in browser
var process = module . exports = { } ;
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout ;
var cachedClearTimeout ;
function defaultSetTimout ( ) {
throw new Error ( 'setTimeout has not been defined' ) ;
}
function defaultClearTimeout ( ) {
throw new Error ( 'clearTimeout has not been defined' ) ;
}
( function ( ) {
try {
if ( typeof setTimeout === 'function' ) {
cachedSetTimeout = setTimeout ;
} else {
cachedSetTimeout = defaultSetTimout ;
}
} catch ( e ) {
cachedSetTimeout = defaultSetTimout ;
}
try {
if ( typeof clearTimeout === 'function' ) {
cachedClearTimeout = clearTimeout ;
} else {
cachedClearTimeout = defaultClearTimeout ;
}
} catch ( e ) {
cachedClearTimeout = defaultClearTimeout ;
}
} ( ) )
function runTimeout ( fun ) {
if ( cachedSetTimeout === setTimeout ) {
//normal enviroments in sane situations
return setTimeout ( fun , 0 ) ;
}
// if setTimeout wasn't available but was latter defined
if ( ( cachedSetTimeout === defaultSetTimout || ! cachedSetTimeout ) && setTimeout ) {
cachedSetTimeout = setTimeout ;
return setTimeout ( fun , 0 ) ;
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout ( fun , 0 ) ;
} catch ( e ) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout . call ( null , fun , 0 ) ;
} catch ( e ) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout . call ( this , fun , 0 ) ;
}
}
}
function runClearTimeout ( marker ) {
if ( cachedClearTimeout === clearTimeout ) {
//normal enviroments in sane situations
return clearTimeout ( marker ) ;
}
// if clearTimeout wasn't available but was latter defined
if ( ( cachedClearTimeout === defaultClearTimeout || ! cachedClearTimeout ) && clearTimeout ) {
cachedClearTimeout = clearTimeout ;
return clearTimeout ( marker ) ;
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout ( marker ) ;
} catch ( e ) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout . call ( null , marker ) ;
} catch ( e ) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout . call ( this , marker ) ;
}
}
}
var queue = [ ] ;
var draining = false ;
var currentQueue ;
var queueIndex = - 1 ;
function cleanUpNextTick ( ) {
if ( ! draining || ! currentQueue ) {
return ;
}
draining = false ;
if ( currentQueue . length ) {
queue = currentQueue . concat ( queue ) ;
} else {
queueIndex = - 1 ;
}
if ( queue . length ) {
drainQueue ( ) ;
}
}
function drainQueue ( ) {
if ( draining ) {
return ;
}
var timeout = runTimeout ( cleanUpNextTick ) ;
draining = true ;
var len = queue . length ;
while ( len ) {
currentQueue = queue ;
queue = [ ] ;
while ( ++ queueIndex < len ) {
if ( currentQueue ) {
currentQueue [ queueIndex ] . run ( ) ;
}
}
queueIndex = - 1 ;
len = queue . length ;
}
currentQueue = null ;
draining = false ;
runClearTimeout ( timeout ) ;
}
process . nextTick = function ( fun ) {
var args = new Array ( arguments . length - 1 ) ;
if ( arguments . length > 1 ) {
for ( var i = 1 ; i < arguments . length ; i ++ ) {
args [ i - 1 ] = arguments [ i ] ;
}
}
queue . push ( new Item ( fun , args ) ) ;
if ( queue . length === 1 && ! draining ) {
runTimeout ( drainQueue ) ;
}
} ;
// v8 likes predictible objects
function Item ( fun , array ) {
this . fun = fun ;
this . array = array ;
}
Item . prototype . run = function ( ) {
this . fun . apply ( null , this . array ) ;
} ;
process . title = 'browser' ;
process . browser = true ;
process . env = { } ;
process . argv = [ ] ;
process . version = '' ; // empty string to avoid regexp issues
process . versions = { } ;
function noop ( ) { }
process . on = noop ;
process . addListener = noop ;
process . once = noop ;
process . off = noop ;
process . removeListener = noop ;
process . removeAllListeners = noop ;
process . emit = noop ;
process . binding = function ( name ) {
throw new Error ( 'process.binding is not supported' ) ;
} ;
process . cwd = function ( ) { return '/' } ;
process . chdir = function ( dir ) {
throw new Error ( 'process.chdir is not supported' ) ;
} ;
process . umask = function ( ) { return 0 ; } ;
} , { } ] } , { } , [ 2 ] ) ;