<commit_before>var SoapClient = require('./soapclient');
var util = require('util');
var http = require('http');
var xml2js = require('xml2js');

var express = require('express');
var bodyparser = require('body-parser');
var os = require('os');

function getLocalInterfaceAddress() {
  var interfaces = os.networkInterfaces();
  var addresses = [];
  for (var k in interfaces) {
    for (var k2 in interfaces[k]) {
      var address = interfaces[k][k2];
      if (address.family === 'IPv4' && !address.internal) {
        addresses.push(address.address);
      }
    }
  }
  return addresses.shift();
}

var BridgeClient = module.exports = function(config) {
  SoapClient.call(this, config);
  this.path = '/upnp/control/bridge1';
  this.serviceType = 'urn:Belkin:service:bridge:1';
  this.sid = null;
  console.log(this.ip, this.port);
  this.listener();
};
util.inherits(BridgeClient, SoapClient);

BridgeClient.prototype.listener = function() {
  var self = this;
  var app = express();
  app.use(bodyparser.raw({type: 'text/xml'}));
  app.all('/', function(req, res) {
    console.log("HEADERS: %j", req.headers);
    xml2js.parseString(req.body, function(err, json){
      if (err) {
        console.log(err);
      }
      console.log("EVENT: %j" , json);
      // TODO: Check / validate req.headers.sid
      if (json['e:propertyset']['e:property'][0]['StatusChange']) {
        xml2js.parseString(json['e:propertyset']['e:property'][0]['StatusChange'][0], function (err, xml) {
          if (!err && xml) {
            self.emit('StatusChange', {
              DeviceId: xml.StateEvent.DeviceID[0]._,
              CapabilityId: xml.StateEvent.CapabilityId[0],
              Value: xml.StateEvent.Value[0]
            });
          }
        });
      }
    });
    res.sendStatus(200);
  });

  var server = app.listen(8080);
  var port = server.address().port;
  this.subscribe('http://' + getLocalInterfaceAddress() + ':' + port);
  console.info('Started Bridge callback server on port ' + port);
};

BridgeClient.prototype.getEndDevices = function(cb) {
  var self = this;

  var parseResponse = function(err, data) {
    if (err) cb(err);
    xml2js.parseString(data, function(err, result) {
      if (!err) {
        var list = result['s:Envelope']['s:Body'][0]['u:GetEndDevicesResponse'][0].DeviceLists[0];
        xml2js.parseString(list, function(err, result2) {
          if (!err) {
            var devinfo = result2.DeviceLists.DeviceList[0].DeviceInfos[0].DeviceInfo;
            if (devinfo) {
              for (var i = 0; i < devinfo.length; i++) {
                var device = {
                  bridge: {
                    ip: self.ip,
                    port: self.port,
                    UDN: self.UDN
                  },
                  friendlyName: devinfo[i].FriendlyName[0],
                  deviceId: devinfo[i].DeviceID[0],
                  currentState: devinfo[i].CurrentState[0].split(','),
                  capabilities: devinfo[i].CapabilityIDs[0].split(',')
                };
                device.internalState = {};
                for (var i = 0; i < device.capabilities.length; i++) {
                  device.internalState[device.capabilities[i]] = device.currentState[i];
                }
                cb(null, device);
              }
            }
            var groupinfos = result2.DeviceLists.DeviceList[0].GroupInfos;
            if (groupinfos) {
              for (var i = 0; i < groupinfos.length; i++) {
                var device = {
                  bridge: {
                    ip: self.ip,
                    port: self.port,
                    UDN: self.UDN
                  },
                  friendlyName: groupinfos[i].GroupInfo[0].GroupName[0],
                  deviceId: groupinfos[i].GroupInfo[0].GroupID[0],
                  currentState: groupinfos[i].GroupInfo[0].GroupCapabilityValues[0].split(','),
                  capabilities: groupinfos[i].GroupInfo[0].GroupCapabilityIDs[0].split(',')
                };
                device.internalState = {};
                for (var i = 0; i < device.capabilities.length; i++) {
                  device.internalState[device.capabilities[i]] = device.currentState[i];
                }
                cb(null, device);
              }
            }
          } else {
            console.log(err, data);
          }
        });
      }
    });
  };

  var body = '<u:GetEndDevices xmlns:u="urn:Belkin:service:bridge:1"><DevUDN>%s</DevUDN><ReqListType>PAIRED_LIST</ReqListType></u:GetEndDevices>';
  this.post('GetEndDevices', util.format(body, this.UDN), parseResponse);
}

BridgeClient.prototype.setDeviceStatus = function(deviceId, capability, value) {
  var isGroupAction = (deviceId.length === 10) ? 'YES' : 'NO';
  var body = [
    '<u:SetDeviceStatus xmlns:u="urn:Belkin:service:bridge:1">',
    '<DeviceStatusList>',
    '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>%s</IsGroupAction><DeviceID available="YES">%s</DeviceID><CapabilityID>%s</CapabilityID><CapabilityValue>%s</CapabilityValue></DeviceStatus>',
    '</DeviceStatusList>',
    '</u:SetDeviceStatus>'
  ].join('\n');
  this.post('SetDeviceStatus', util.format(body, isGroupAction, deviceId, capability, value));
};

BridgeClient.prototype.subscribe = function(callbackUri, cb) {
  var options = {
    host: this.ip,
    port: this.port,
    path: '/upnp/event/bridge1',
    method: 'SUBSCRIBE',
    headers: {
      TIMEOUT: 'Second-120'
    }
  };

  // Initial subscription, not a renewal
  if (!this.sid) {
    options.headers.CALLBACK = '<' + callbackUri + '>';
    options.headers.NT = 'upnp:event';
    console.log('initial event subscription', options);
  } else {
    options.headers.SID = this.sid;
    console.log('event subscription renewal', options);
  }

  var req = http.request(options, function(res) {
    if (res.headers.sid) this.sid = res.headers.sid;
    setTimeout(this.subscribe.bind(this), 100 * 1000, callbackUri);
  }.bind(this));
  req.end();
};
<commit_msg>Remove debug output<commit_after>var SoapClient = require('./soapclient');
var util = require('util');
var http = require('http');
var xml2js = require('xml2js');

var express = require('express');
var bodyparser = require('body-parser');
var os = require('os');

function getLocalInterfaceAddress() {
  var interfaces = os.networkInterfaces();
  var addresses = [];
  for (var k in interfaces) {
    for (var k2 in interfaces[k]) {
      var address = interfaces[k][k2];
      if (address.family === 'IPv4' && !address.internal) {
        addresses.push(address.address);
      }
    }
  }
  return addresses.shift();
}

var BridgeClient = module.exports = function(config) {
  SoapClient.call(this, config);
  this.path = '/upnp/control/bridge1';
  this.serviceType = 'urn:Belkin:service:bridge:1';
  this.sid = null;
  this.listener();
};
util.inherits(BridgeClient, SoapClient);

BridgeClient.prototype.listener = function() {
  var self = this;
  var app = express();
  app.use(bodyparser.raw({type: 'text/xml'}));
  app.all('/', function(req, res) {
    xml2js.parseString(req.body, function(err, json){
      if (err) {
        console.log(err);
      }
      // TODO: Check / validate req.headers.sid
      if (json['e:propertyset']['e:property'][0]['StatusChange']) {
        xml2js.parseString(json['e:propertyset']['e:property'][0]['StatusChange'][0], function (err, xml) {
          if (!err && xml) {
            self.emit('StatusChange', {
              DeviceId: xml.StateEvent.DeviceID[0]._,
              CapabilityId: xml.StateEvent.CapabilityId[0],
              Value: xml.StateEvent.Value[0]
            });
          }
        });
      } else {
        console.log('Unhandled Event: %j', json);
      }
    });
    res.sendStatus(200);
  });

  var server = app.listen(0);
  var port = server.address().port;
  this.subscribe('http://' + getLocalInterfaceAddress() + ':' + port);
  console.info('Started Bridge callback server on port ' + port);
};

BridgeClient.prototype.getEndDevices = function(cb) {
  var self = this;

  var parseResponse = function(err, data) {
    if (err) cb(err);
    xml2js.parseString(data, function(err, result) {
      if (!err) {
        var list = result['s:Envelope']['s:Body'][0]['u:GetEndDevicesResponse'][0].DeviceLists[0];
        xml2js.parseString(list, function(err, result2) {
          if (!err) {
            var devinfo = result2.DeviceLists.DeviceList[0].DeviceInfos[0].DeviceInfo;
            if (devinfo) {
              for (var i = 0; i < devinfo.length; i++) {
                var device = {
                  bridge: {
                    ip: self.ip,
                    port: self.port,
                    UDN: self.UDN
                  },
                  friendlyName: devinfo[i].FriendlyName[0],
                  deviceId: devinfo[i].DeviceID[0],
                  currentState: devinfo[i].CurrentState[0].split(','),
                  capabilities: devinfo[i].CapabilityIDs[0].split(',')
                };
                device.internalState = {};
                for (var i = 0; i < device.capabilities.length; i++) {
                  device.internalState[device.capabilities[i]] = device.currentState[i];
                }
                cb(null, device);
              }
            }
            var groupinfos = result2.DeviceLists.DeviceList[0].GroupInfos;
            if (groupinfos) {
              for (var i = 0; i < groupinfos.length; i++) {
                var device = {
                  bridge: {
                    ip: self.ip,
                    port: self.port,
                    UDN: self.UDN
                  },
                  friendlyName: groupinfos[i].GroupInfo[0].GroupName[0],
                  deviceId: groupinfos[i].GroupInfo[0].GroupID[0],
                  currentState: groupinfos[i].GroupInfo[0].GroupCapabilityValues[0].split(','),
                  capabilities: groupinfos[i].GroupInfo[0].GroupCapabilityIDs[0].split(',')
                };
                device.internalState = {};
                for (var i = 0; i < device.capabilities.length; i++) {
                  device.internalState[device.capabilities[i]] = device.currentState[i];
                }
                cb(null, device);
              }
            }
          } else {
            console.log(err, data);
          }
        });
      }
    });
  };

  var body = '<u:GetEndDevices xmlns:u="urn:Belkin:service:bridge:1"><DevUDN>%s</DevUDN><ReqListType>PAIRED_LIST</ReqListType></u:GetEndDevices>';
  this.post('GetEndDevices', util.format(body, this.UDN), parseResponse);
}

BridgeClient.prototype.setDeviceStatus = function(deviceId, capability, value) {
  var isGroupAction = (deviceId.length === 10) ? 'YES' : 'NO';
  var body = [
    '<u:SetDeviceStatus xmlns:u="urn:Belkin:service:bridge:1">',
    '<DeviceStatusList>',
    '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>%s</IsGroupAction><DeviceID available="YES">%s</DeviceID><CapabilityID>%s</CapabilityID><CapabilityValue>%s</CapabilityValue></DeviceStatus>',
    '</DeviceStatusList>',
    '</u:SetDeviceStatus>'
  ].join('\n');
  this.post('SetDeviceStatus', util.format(body, isGroupAction, deviceId, capability, value));
};

BridgeClient.prototype.subscribe = function(callbackUri, cb) {
  var options = {
    host: this.ip,
    port: this.port,
    path: '/upnp/event/bridge1',
    method: 'SUBSCRIBE',
    headers: {
      TIMEOUT: 'Second-120'
    }
  };

  if (!this.sid) {
    // Initial subscription
    options.headers.CALLBACK = '<' + callbackUri + '>';
    options.headers.NT = 'upnp:event';
  } else {
    // Subscription renewal
    options.headers.SID = this.sid;
  }

  var req = http.request(options, function(res) {
    if (res.headers.sid) this.sid = res.headers.sid;
    setTimeout(this.subscribe.bind(this), 100 * 1000, callbackUri);
  }.bind(this));
  req.end();
};
<|endoftext|>


<commit_before>'use strict';

var url = require('url');

function copy(o, to) {
  to = to || {};
  for (var key in o) to[key] = o[key];
  return to;
}

module.exports = function (ajv, keyword, jsonPatch, patchSchema) {
  if (!ajv._opts.v5)
    throw new Error('keyword ' + keyword + ' requires v5 option');
  ajv.addKeyword(keyword, {
    macro: function (schema, parentSchema, it) {
      var source = schema.source;
      var patch = schema.with;
      if (source.$ref) source = copy(getSchema(source.$ref));
      if (patch.$ref) patch = getSchema(patch.$ref);
      jsonPatch.apply(source, patch, true);
      return source;

      function getSchema($ref) {
        var id = it.baseId && it.baseId != '#'
                  ? url.resolve(it.baseId, $ref)
                  : $ref;
        var validate = ajv.getSchema(id);
        if (validate) return validate.schema;
        throw new Error('can\'t resolve reference ' + $ref + ' from id ' + it.baseId);
      }
    },
    metaSchema: {
      "type": "object",
      "required": [ "source", "with" ],
      "additionalProperties": false,
      "properties": {
        "source": {
          "anyOf": [
            {
              "type": "object",
              "required": [ "$ref" ],
              "additionalProperties": false,
              "properties": {
                "$ref": {
                  "type": "string",
                  "format": "uri"
                }
              }
            },
            { "$ref": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json#" }
          ]
        },
        "with": patchSchema
      }
    }
  });
};
<commit_msg>feat: deep-clone source schema defined with $ref, closes #4<commit_after>'use strict';

var url = require('url');

module.exports = function (ajv, keyword, jsonPatch, patchSchema) {
  if (!ajv._opts.v5)
    throw new Error('keyword ' + keyword + ' requires v5 option');
  ajv.addKeyword(keyword, {
    macro: function (schema, parentSchema, it) {
      var source = schema.source;
      var patch = schema.with;
      if (source.$ref) source = JSON.parse(JSON.stringify(getSchema(source.$ref)));
      if (patch.$ref) patch = getSchema(patch.$ref);
      jsonPatch.apply(source, patch, true);
      return source;

      function getSchema($ref) {
        var id = it.baseId && it.baseId != '#'
                  ? url.resolve(it.baseId, $ref)
                  : $ref;
        var validate = ajv.getSchema(id);
        if (validate) return validate.schema;
        throw new Error('can\'t resolve reference ' + $ref + ' from id ' + it.baseId);
      }
    },
    metaSchema: {
      "type": "object",
      "required": [ "source", "with" ],
      "additionalProperties": false,
      "properties": {
        "source": {
          "anyOf": [
            {
              "type": "object",
              "required": [ "$ref" ],
              "additionalProperties": false,
              "properties": {
                "$ref": {
                  "type": "string",
                  "format": "uri"
                }
              }
            },
            { "$ref": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json#" }
          ]
        },
        "with": patchSchema
      }
    }
  });
};
<|endoftext|>


<commit_before>// TALK / public / js / chat.js
// By Daniel R. (sadasant.com)
// License: http://opensource.org/licenses/mit-license.php

window.onload = function() {

  var last = 0
    , URL = window.location.href
    , I = false
    , busy = false
    , sent = 0 // Number of posts sent before loading
    , USER = window.USER
    , CHAT = window.CHAT
    , $content = $('#content')
    , $textarea = $('textarea')
    , $error = $('#error')
    , $auto = $('#auto')
    , $loadPost

  bindControls()

  // Binding all the buttons and inputs
  function bindControls() {
    $('#send').click(sendPost)
    $('#load').click(loadPosts)
    $('#auto').click(toggleInterval)
    $('#remo').click(removeChat)
    // Resetting the title
    $('#new_post').focus(function() {
      document.title = "TALK: " + CHAT.name
    })
    // Binding CTRL + ENTER
    .on('keypress', function(e) {
      e = window.event || e
      var key = e.keyCode
        , ctrl = e.ctrlKey
      if (key == 10 || (ctrl && key == 13)) {
        sendPost()
      }
    })
    loadPosts()
  }

  // Send post
  function sendPost() {
    var data = {
      post : $textarea.val()
    , date : new Date().toString()
    }
    $error.html('loading...')
    $.post(URL+"/post", data, function(data) {
      if (data === 'ok') {
        sent++
        $textarea.val('')
        if (!I) loadPosts()
      } else {
        if (data.error) {
          $error.html(data.error)
        }
      }
    })
  }

  // Load posts
  function loadPosts() {
    if (busy) return
    busy = true
    var data = {
        last : last
      , I    : I
      }
    if (!I) $error.html('loading...')
    $loadPost = $.post(URL+"/load", data, function(data) {
      if (!data) return
      // Good response
      if (Array.isArray(data)) {
        // Cleaning the content
        if (data.length && !last) $content.html('')
        // Rendering the posts
        var i = 0
          , new_posts = 0 - sent
          , post
        sent = 0
        for (; i < data.length; i++) {
          if (post = data[i]) {
            new_posts++
            $content.append('

'+post.user.name+' '+post.date.split(' ')[4]+'

'+post.post+'

')
          }
        }
        // Updating the Title
        document.title = (new_posts ? "("+new_posts+") " : "") + "TALK: " + CHAT.name
        // We're on the last post
        if (post) last = post.pos+1
        // No errors
        $error.html('')
      } else
      // Bad response
      if (data.error) {
        window.location = "/"
      }
      busy = false
      // Resend
      if (I) setTimeout(loadPosts, 1000)
    }).error(function() {
      busy = false
      // Resend on timeout
      if (I) loadPosts()
    })
  }

  // Toggles long-polling's interval
  function toggleInterval() {
    if (I) {
      I = false
      $loadPost.abort()
      $auto.val('Auto Load')
    } else {
      I = true
      $auto.val('Stop Auto Load')
      loadPosts()
    }
  }

  // Removes the chat
  function removeChat() {
    $.get(URL+"/rm", function(data) {
      if (data == "ok") window.location = "/"
    })
  }
}
<commit_msg>opera mobile fix?<commit_after>// TALK / public / js / chat.js
// By Daniel R. (sadasant.com)
// License: http://opensource.org/licenses/mit-license.php

window.onload = function() {

  var last = 0
    , URL = window.location.href
    , I = false
    , busy = false
    , sent = 0 // Number of posts sent before loading
    , USER = window.USER
    , CHAT = window.CHAT
    , $content = $('#content')
    , $textarea = $('textarea')
    , $error = $('#error')
    , $auto = $('#auto')
    , $loadPost

  bindControls()

  // Binding all the buttons and inputs
  function bindControls() {
    $('#send').click(sendPost)
    $('#load').click(loadPosts)
    $('#auto').click(toggleInterval)
    $('#remo').click(removeChat)
    // Resetting the title
    $('#new_post').focus(function() {
      document.title = "TALK: " + CHAT.name
    })
    // Binding CTRL + ENTER
    .on('keypress', function(e) {
      e = window.event || e
      var key = e.keyCode
        , ctrl = e.ctrlKey
      if (key == 10 || (ctrl && key == 13)) {
        sendPost()
      }
    })
    loadPosts()
  }

  // Send post
  function sendPost() {
    var data = {
      post : $textarea.val()
    , date : new Date().toString()
    }
    $error.html('loading...')
    $.post(URL+"/post", data, function(data) {
      if (data === 'ok') {
        sent++
        $textarea.val('')
        if (!I) loadPosts()
      } else {
        if (data.error) {
          $error.html(data.error)
        }
      }
    })
  }

  // Load posts
  function loadPosts() {
    if (busy) return
    busy = true
    var data = {
        last : last
      , I    : I
      }
    if (!I) $error.html('loading...')
    $loadPost = $.post(URL+"/load", data, function(data) {
      if (!data) return
      // Good response
      if (data.length >= 0) {
        // Cleaning the content
        if (data.length && !last) $content.html('')
        // Rendering the posts
        var i = 0
          , new_posts = 0 - sent
          , post
        sent = 0
        for (; i < data.length; i++) {
          if (post = data[i]) {
            new_posts++
            $content.append('

'+post.user.name+' '+post.date.split(' ')[4]+'

'+post.post+'

')
          }
        }
        // Updating the Title
        document.title = (new_posts ? "("+new_posts+") " : "") + "TALK: " + CHAT.name
        // We're on the last post
        if (post) last = post.pos+1
        // No errors
        $error.html('')
      } else
      // Bad response
      if (data.error) {
        window.location = "/"
      }
      busy = false
      // Resend
      if (I) setTimeout(loadPosts, 1000)
    }).error(function() {
      busy = false
      // Resend on timeout
      if (I) loadPosts()
    })
  }

  // Toggles long-polling's interval
  function toggleInterval() {
    if (I) {
      I = false
      $loadPost.abort()
      $auto.val('Auto Load')
    } else {
      I = true
      $auto.val('Stop Auto Load')
      loadPosts()
    }
  }

  // Removes the chat
  function removeChat() {
    $.get(URL+"/rm", function(data) {
      if (data == "ok") window.location = "/"
    })
  }
}
<|endoftext|>


<commit_before>$(function() {
  var meta = {
    currentSong: 0
  };

  $('.footer').on('click', function() {
    var $opts = $('.options').toggleClass('visible');

    $opts.animate({
      'max-height': $opts.hasClass('visible')? '1000px': 0
    });
  });

  $('.forward').on('click', function() {
    nextSong(meta);
  });

  $('.backward').on('click', function() {
    previousSong(meta);
  });

  $('.play, .pause').on('click', function() {
    $('.play').toggle();
    $('.pause').toggle();

    if($('.play:visible').length) komponist.stop();
    else komponist.play(meta.currentSong);
  });

  var $channelTpl = getChannelTemplate();
  $(document).on('click', '.channel', function() {
    var $e = $(this);

    selectChannel($e);
  }).on('keyup', function() {
    var $e = $(this);

    checkInputs($channelTpl, $e);
    selectChannel($e);
  });

  komponist.on('changed', function(system) {
    if(system !== 'player') return;

    updateSong(meta);
  });
  komponist.once('ready', function() {
    updateSong(meta);
    updatePlayPause();
    createPlaylist($channelTpl, function() {
      updatePlaylist(meta);
      checkInputs($channelTpl);
    });
  });
});

function getChannelTemplate() {
  return $('.channel:first').parent().clone();
}

function checkInputs($tpl, $e) {
  var empties = $('.channel').filter(function(i, e) {
    return $(e).val().trim().length === 0;
  });

  if(!empties.length) {
    $('.channels').append($tpl.clone());
  }
  if(empties.length > 1) {
    empties.not($e).remove();
  }
}

function selectChannel($e) {
  $('.channel').removeClass('selected');
  if($e) $e.addClass('selected');
}

function updateSong(meta) {
  komponist.currentsong(function(err, data) {
    meta.currentSong = parseInt(data.Pos, 10);

    updateInfo(meta);
  });
}

function updateInfo(meta) {
  komponist.playlistid(function(err, data) {
    var d = data[meta.currentSong];
    var info = [d.Name, d.Title].filter(id).join(' - ');

    $('.info').text(info);
  });
}

function updatePlayPause() {
  playerState(function(err, state) {
    $('.play, .pause').show();
    $('.' + state).hide();
  });
}

function createPlaylist($tpl, done) {
  komponist.playlistinfo(function(err, data) {
    var $c = $('.channels');

    $c.empty();

    $.each(data, function(i, v) {
        var $e = $tpl.clone();

        $('.channel', $e).val(v.file);

        $c.append($e);
    });

    done();
  });
}

function updatePlaylist(meta) {
  $('.channel').removeClass('selected');
  $('.channel[value!=""]').eq(meta.currentSong).addClass('selected');
}

function nextSong(meta) {
  komponist.playlistid(function(err, data) {
    meta.currentSong++;

    if(meta.currentSong == data.length) meta.currentSong = 0;

    resume(meta);
    updateInfo(meta);
    updatePlaylist(meta);
  });
}

function previousSong(meta) {
  komponist.playlistid(function(err, data) {
    meta.currentSong--;

    if(meta.currentSong < 0) meta.currentSong = data.length - 1;

    resume(meta);
    updateInfo(meta);
    updatePlaylist(meta);
  });
}

function resume(meta) {
  playerState(function(err, state) {
    if(state == 'play') komponist.play(meta.currentSong);
  });
}

function playerState(cb) {
  komponist.status(function(err, data) {
    cb(err, data.state == 'play'? 'play': 'pause');
  });
}

function id(a) {return a;}
<commit_msg>In case a channel is selected, play it<commit_after>$(function() {
  var meta = {
    currentSong: 0
  };

  $('.footer').on('click', function() {
    var $opts = $('.options').toggleClass('visible');

    $opts.animate({
      'max-height': $opts.hasClass('visible')? '1000px': 0
    });
  });

  $('.forward').on('click', function() {
    nextSong(meta);
  });

  $('.backward').on('click', function() {
    previousSong(meta);
  });

  $('.play, .pause').on('click', function() {
    $('.play').toggle();
    $('.pause').toggle();

    if($('.play:visible').length) komponist.stop();
    else komponist.play(meta.currentSong);
  });

  var $channelTpl = getChannelTemplate();
  $(document).on('click', '.channel', function() {
    var $e = $(this);

    selectChannel($e, meta);
    resume(meta.currentSong);
  }).on('keyup', function() {
    var $e = $(this);

    checkInputs($channelTpl, $e);
    selectChannel($e, meta);
  });

  komponist.on('changed', function(system) {
    if(system !== 'player') return;

    updateSong(meta);
  });
  komponist.once('ready', function() {
    updateSong(meta);
    updatePlayPause();
    createPlaylist($channelTpl, function() {
      updatePlaylist(meta);
      checkInputs($channelTpl);
    });
  });
});

function getChannelTemplate() {
  return $('.channel:first').parent().clone();
}

function checkInputs($tpl, $e) {
  var empties = $('.channel').filter(function(i, e) {
    return $(e).val().trim().length === 0;
  });

  if(!empties.length) {
    $('.channels').append($tpl.clone());
  }
  if(empties.length > 1) {
    empties.not($e).remove();
  }
}

function selectChannel($e, meta) {
  $('.channel').removeClass('selected');
  if($e) $e.addClass('selected');

  var id = $e.parent().index();
  var emptyId = $('channel[value=""]:first').parent().index();
  if(-1 < emptyId && emptyId < id) id--;

  meta.currentSong = id;
}

function updateSong(meta) {
  komponist.currentsong(function(err, data) {
    meta.currentSong = parseInt(data.Pos, 10);

    updateInfo(meta);
  });
}

function updateInfo(meta) {
  komponist.playlistid(function(err, data) {
    var d = data[meta.currentSong];
    var info = [d.Name, d.Title].filter(id).join(' - ');

    $('.info').text(info);
  });
}

function updatePlayPause() {
  playerState(function(err, state) {
    $('.play, .pause').show();
    $('.' + state).hide();
  });
}

function createPlaylist($tpl, done) {
  komponist.playlistinfo(function(err, data) {
    var $c = $('.channels');

    $c.empty();

    $.each(data, function(i, v) {
        var $e = $tpl.clone();

        $('.channel', $e).val(v.file);

        $c.append($e);
    });

    done();
  });
}

function updatePlaylist(meta) {
  $('.channel').removeClass('selected');
  $('.channel[value!=""]').eq(meta.currentSong).addClass('selected');
}

function nextSong(meta) {
  komponist.playlistid(function(err, data) {
    meta.currentSong++;

    if(meta.currentSong == data.length) meta.currentSong = 0;

    resume(meta.currentSong);
    updateInfo(meta);
    updatePlaylist(meta);
  });
}

function previousSong(meta) {
  komponist.playlistid(function(err, data) {
    meta.currentSong--;

    if(meta.currentSong < 0) meta.currentSong = data.length - 1;

    resume(meta.currentSong);
    updateInfo(meta);
    updatePlaylist(meta);
  });
}

function resume(song) {
  playerState(function(err, state) {
    if(state == 'play') komponist.play(song);
  });
}

function playerState(cb) {
  komponist.status(function(err, data) {
    cb(err, data.state == 'play'? 'play': 'pause');
  });
}

function id(a) {return a;}
<|endoftext|>


<commit_before>/*jshint boss:true, expr:true, onevar:false */

/**
Provides a context menu plugin with custom event binding.

@module renodse-contextmenu
**/
var ContextMenu,

    CSS_CONTEXT_MENU = 'rednose-context-menu',
    CSS_CONTEXT_OPEN = 'rednose-context-open';

    CSS_BOOTSTRAP_ICON_WHITE    = 'icon-white',
    CSS_BOOTSTRAP_DROPDOWN      = 'dropdown',
    CSS_BOOTSTRAP_DROPDOWN_MENU = 'dropdown-menu',
    CSS_BOOTSTRAP_OPEN          = 'open';

/**
Provides a context menu plugin with custom event binding.

@class ContextMenu
@namespace Rednose
@param {Object} [config] Config properties.
    @param {Object} [config.content] Contextmenu configuration object.
    @param {Oject} [config.data] Optional object to pass with fired events.
    @param {Object} [config.bubbleTarget] Optional bubble target.
@constructor
@extends Plugin.Base
**/
ContextMenu = Y.Base.create('contextMenu', Y.Plugin.Base, [], {
    // -- Public Properties ----------------------------------------------------

    /**
     * Optional data object, to pass with the event
     */
     data: null,

    // -- Protected Properties -------------------------------------------------

    /**
     * State variable, holds a possible active instance.
     */
    _contextMenu: null,

    // -- Lifecycle Methods ----------------------------------------------------

    /**
     * Initializer, gets called upon instance initiation.
     */
    initializer: function (config) {
        var node         = config.host,
            content      = config.content ? config.content : '',
            bubbleTarget = config.bubbleTarget;

        this._node = node;
        this._content = this._buildHTML(content);

        if (bubbleTarget) {
            this.addTarget(bubbleTarget);
        }

        if (typeof config.data !== 'undefined') {
            this.data = config.data;
        }

        node.on('contextmenu', this._handleContextMenu, this);
    },

    destructor: function () {
        if (this._contextMenu) {
            this._contextMenu.destroy();
        }

        this.data         = null;
        this._contextMenu = null;
    },

    // -- Public Methods -------------------------------------------------------
    open: function (x, y) {
        var node        = this._node,
            contextMenu = this._contextMenu,
            content     = this._content;

        // Remove a previous context menu if it exists, ideally we prolly wanna toggle it.
        Y.all('.' + CSS_CONTEXT_OPEN).each(function (node) {
            node.contextMenu._contextMenu.destroy();
        });

        contextMenu = new Y.Overlay({
            bodyContent: content,
            visible: false,
            constrain: true,
            zIndex: this._getHighzIndex(),
            render: true
        });

        node.addClass(CSS_CONTEXT_OPEN);

        contextMenu.get('boundingBox').addClass(CSS_CONTEXT_MENU);
        contextMenu.get('boundingBox').setStyle('left', x);
        contextMenu.get('boundingBox').setStyle('top', y);
        contextMenu.show();

        this._contextMenu = contextMenu;
        this._bindContextMenu();
    },

    // -- Protected Methods ----------------------------------------------------

    _buildHTML: function (content) {
        var template =
            '
' +
                '

' +
            '
';

        var node = Y.Node.create(template);
        var ul = node.one('ul');

        if (content === '') {
            return content;
        }

        Y.Array.each(content, function (item) {
            var elLi = Y.Node.create('
');
            var elA = Y.Node.create('');
            var html = item.title;

            if (item.className) {
                elLi.addClass(item.className);
            }

            if (item.title !== '-') {
                if (item.icon) {
                    html = ' ' + html;
                }

                elA.set('innerHTML', html);
                elA.setAttribute('data-id', item.id);

                elLi.append(elA);

                if (item.disabled === true) {
                    elLi.addClass('disabled');
                    elA.addClass('disabled');
                }
             } else {
                elLi.addClass('divider');
            }

            ul.append(elLi);
        });

        return node.get('outerHTML');
    },

    _bindContextMenu: function () {
        var self         = this,
            node         = this._node,
            contextMenu  = this._contextMenu;

        // Bind the menu events
        contextMenu.get('boundingBox').all('a').each(function() {
            this.on(['click', 'contextmenu'], function (e) {
                var target = e.currentTarget,
                    args = { node: node };

                e.preventDefault();

                if (target.hasClass('disabled') !== true) {
                    if (self.data !== null) {
                        args.data = self.data;
                    }

                    self.fire(target.getAttribute('data-id'), args);

                    contextMenu.destroy();
                } else {
                    target.blur();
                }
            });
        });

        contextMenu.get('boundingBox').all('li').on('mouseenter', function (e) {
            var node = e.currentTarget;

            if (node.one('i')) {
                node.one('i').addClass(CSS_BOOTSTRAP_ICON_WHITE);
            }
        });

        contextMenu.get('boundingBox').all('li').on('mouseleave', function (e) {
            var node = e.currentTarget;

            if (node.one('i') && node.one('i').hasClass(CSS_BOOTSTRAP_ICON_WHITE)) {
                node.one('i').removeClass(CSS_BOOTSTRAP_ICON_WHITE);
            }
        });

        contextMenu.get('boundingBox').on('clickoutside', function (e) {
            // Dont allow the rightclick mousebutton to hide the contextMenu
            // In some cases a browser (tested on FF17) will fire false positives and
            // immediately hide the contextmenu again.
            if (e.button !== 3) {
                contextMenu.destroy();
            }
        });
    },

    // -- Protected Event Handlers ---------------------------------------------

    _handleContextMenu: function (e) {
        var x = e.pageX,
            y = e.pageY;

        e.preventDefault();

        this.open(x, y);
    },

    _getHighzIndex: function() {
        var elements = document.getElementsByTagName('*');
        var highIndex = 0;

        for (var i = 0; i < elements.length - 1; i++) {
            if (parseInt(elements[i].style.zIndex) > highIndex) {
                highIndex = parseInt(elements[i].style.zIndex)
            }
        }

        return (highIndex + 1);
    }
}, {
    NS : 'contextMenu',
});

// -- Namespace ----------------------------------------------------------------
Y.namespace('Rednose').ContextMenu = ContextMenu;
<commit_msg>Detach contextmenu on destruct.<commit_after>/*jshint boss:true, expr:true, onevar:false */

/**
Provides a context menu plugin with custom event binding.

@module renodse-contextmenu
**/
var ContextMenu,

    CSS_CONTEXT_MENU = 'rednose-context-menu',
    CSS_CONTEXT_OPEN = 'rednose-context-open';

    CSS_BOOTSTRAP_ICON_WHITE    = 'icon-white',
    CSS_BOOTSTRAP_DROPDOWN      = 'dropdown',
    CSS_BOOTSTRAP_DROPDOWN_MENU = 'dropdown-menu',
    CSS_BOOTSTRAP_OPEN          = 'open';

/**
Provides a context menu plugin with custom event binding.

@class ContextMenu
@namespace Rednose
@param {Object} [config] Config properties.
    @param {Object} [config.content] Contextmenu configuration object.
    @param {Oject} [config.data] Optional object to pass with fired events.
    @param {Object} [config.bubbleTarget] Optional bubble target.
@constructor
@extends Plugin.Base
**/
ContextMenu = Y.Base.create('contextMenu', Y.Plugin.Base, [], {
    // -- Public Properties ----------------------------------------------------

    /**
     * Optional data object, to pass with the event
     */
     data: null,

    // -- Protected Properties -------------------------------------------------

    /**
     * State variable, holds a possible active instance.
     */
    _contextMenu: null,

    // -- Lifecycle Methods ----------------------------------------------------

    /**
     * Initializer, gets called upon instance initiation.
     */
    initializer: function (config) {
        var node         = config.host,
            content      = config.content ? config.content : '',
            bubbleTarget = config.bubbleTarget;

        this._node = node;
        this._content = this._buildHTML(content);

        if (bubbleTarget) {
            this.addTarget(bubbleTarget);
        }

        if (typeof config.data !== 'undefined') {
            this.data = config.data;
        }

        node.on('contextmenu', this._handleContextMenu, this);
    },

    destructor: function () {
        if (this._contextMenu) {
            this._contextMenu.destroy();
        }

        this.data         = null;
        this._contextMenu = null;
        this.get('host').detach('contextmenu');
    },

    // -- Public Methods -------------------------------------------------------
    open: function (x, y) {
        var node        = this._node,
            contextMenu = this._contextMenu,
            content     = this._content;

        // Remove a previous context menu if it exists, ideally we prolly wanna toggle it.
        Y.all('.' + CSS_CONTEXT_OPEN).each(function (node) {
            node.contextMenu._contextMenu.destroy();
        });

        contextMenu = new Y.Overlay({
            bodyContent: content,
            visible: false,
            constrain: true,
            zIndex: this._getHighzIndex(),
            render: true
        });

        node.addClass(CSS_CONTEXT_OPEN);

        contextMenu.get('boundingBox').addClass(CSS_CONTEXT_MENU);
        contextMenu.get('boundingBox').setStyle('left', x);
        contextMenu.get('boundingBox').setStyle('top', y);
        contextMenu.show();

        this._contextMenu = contextMenu;
        this._bindContextMenu();
    },

    // -- Protected Methods ----------------------------------------------------

    _buildHTML: function (content) {
        var template =
            '
' +
                '

' +
            '
';

        var node = Y.Node.create(template);
        var ul = node.one('ul');

        if (content === '') {
            return content;
        }

        Y.Array.each(content, function (item) {
            var elLi = Y.Node.create('
');
            var elA = Y.Node.create('');
            var html = item.title;

            if (item.className) {
                elLi.addClass(item.className);
            }

            if (item.title !== '-') {
                if (item.icon) {
                    html = ' ' + html;
                }

                elA.set('innerHTML', html);
                elA.setAttribute('data-id', item.id);

                elLi.append(elA);

                if (item.disabled === true) {
                    elLi.addClass('disabled');
                    elA.addClass('disabled');
                }
             } else {
                elLi.addClass('divider');
            }

            ul.append(elLi);
        });

        return node.get('outerHTML');
    },

    _bindContextMenu: function () {
        var self         = this,
            node         = this._node,
            contextMenu  = this._contextMenu;

        // Bind the menu events
        contextMenu.get('boundingBox').all('a').each(function() {
            this.on(['click', 'contextmenu'], function (e) {
                var target = e.currentTarget,
                    args = { node: node };

                e.preventDefault();

                if (target.hasClass('disabled') !== true) {
                    if (self.data !== null) {
                        args.data = self.data;
                    }

                    self.fire(target.getAttribute('data-id'), args);

                    contextMenu.destroy();
                } else {
                    target.blur();
                }
            });
        });

        contextMenu.get('boundingBox').all('li').on('mouseenter', function (e) {
            var node = e.currentTarget;

            if (node.one('i')) {
                node.one('i').addClass(CSS_BOOTSTRAP_ICON_WHITE);
            }
        });

        contextMenu.get('boundingBox').all('li').on('mouseleave', function (e) {
            var node = e.currentTarget;

            if (node.one('i') && node.one('i').hasClass(CSS_BOOTSTRAP_ICON_WHITE)) {
                node.one('i').removeClass(CSS_BOOTSTRAP_ICON_WHITE);
            }
        });

        contextMenu.get('boundingBox').on('clickoutside', function (e) {
            // Dont allow the rightclick mousebutton to hide the contextMenu
            // In some cases a browser (tested on FF17) will fire false positives and
            // immediately hide the contextmenu again.
            if (e.button !== 3) {
                contextMenu.destroy();
            }
        });
    },

    // -- Protected Event Handlers ---------------------------------------------

    _handleContextMenu: function (e) {
        var x = e.pageX,
            y = e.pageY;

        e.preventDefault();

        this.open(x, y);
    },

    _getHighzIndex: function() {
        var elements = document.getElementsByTagName('*');
        var highIndex = 0;

        for (var i = 0; i < elements.length - 1; i++) {
            if (parseInt(elements[i].style.zIndex) > highIndex) {
                highIndex = parseInt(elements[i].style.zIndex)
            }
        }

        return (highIndex + 1);
    }
}, {
    NS : 'contextMenu',
});

// -- Namespace ----------------------------------------------------------------
Y.namespace('Rednose').ContextMenu = ContextMenu;
<|endoftext|>


<commit_before>var			g_nickname;
var			g_connected = 0;

function	register_player()
{
	g_nickname = $("#nick_zone").val();
	if (!g_connected)
		socket.emit("is valid nickname", g_nickname, seat_nb);

	socket.on("is valid nickname info", function(res, nick)
	{
		if (res == "invalid" && !g_connected)
			$("#msg").text("Size must be between 2 and 8 characters without blanks!");
		else if (res == "valid" && !g_connected)
		{
			socket.emit("socket nickname on table", g_nickname);
			$("#msg").text("");
			$("#play").remove();
			$("#nick_zone").remove();
			$('#container').css("background-image", "url(img/please_wait.png)");
			$("#player_name").css("visibility", "hidden");
			$("#player_name").text(nick);
			g_connected = 1;
		}
		else if (res == "seat busy" && !g_connected)
			$("#msg").text("Seat busy. Please wait or choose another one.");
		else if (res == "already taken" && !g_connected)
			$("#msg").text("This nickname is already taken!");
	});
	socket.on("player name info")
		socket.emit("socket nickname on table", g_nickname);
	socket.on("first deal", function(card1, card2)
	{
		if (g_connected)
		{
			if ($("#container").css("background-image") != "url(img/player_decision.png)");
				$('#container').css("background-image", "url(img/player_decision.png)");
			$("#card1, #card2, #aim, #player_name, #slider, #hide_cards").css("visibility", "visible");
			$("#card1").attr("src", "img/cards/" + card1 + ".png");
			$("#card2").attr("src", "img/cards/" + card2 + ".png");
			$("#ui-state-default").focus();
			$("#curtain").css("visibility", "hidden");
		}
	});
	socket.on("first suit", function(suit)
	{
		$("#hand_value").text(suit);
	});
	socket.on("raise limits", function(r1, r2)
	{
		if (r1 >= 0) {
			$("#min_bet").text((Math.floor(+r1 * 100)) / 100 + "$");
			$("#c2_amount").text((Math.floor(+r1 * 100)) / 100 + "$");
		}
		if (r2 > 0)
			$("#max_bet").text((Math.floor(+r2 * 100)) / 100 + "$");
	});
	socket.on("first choice", function(choice, amount)
	{
		$('#bet_pot').css("visibility", "visible");
		$("#choice1").css("visibility", "visible");
		$("#choice2").css("visibility", "visible");
		$("#choice3").css("visibility", "visible");
		$("#hide_cards").css("visibility", "visible");
		if (choice == "call" && amount > 0)
		{
			$("#c1").text("CALL ");
			$("#c1_amount").text((Math.floor(+amount * 100)) / 100 + "$");
		}
		else if (choice == "check")
		{
			$("#c1").text("CHECK");
			$("#c1_amount").text('');
		}
	});
	socket.on("second choice", function(choice, amount)
	{
		if (choice == "null" && amount < 0)
		{
			$('#choice2').hide();
		}
		else if ((choice == "raise" || choice == "bet") && amount >= 0)
		{

			$('#choice2').show();
			$("#c2").text(choice.toUpperCase() + " +");
			$("#c2_amount").text((Math.floor(amount * 100)) / 100 + "$");
			$("#raise_amount").text((Math.floor(amount * 100)) / 100 + "$");
		}
	});
	socket.on("cancel buttons", function(hidden){
		$("#choice1").css("visibility", hidden);
		$("#choice2").css("visibility", hidden);
		$("#choice3").css("visibility", hidden);
	});
	socket.on("show buttons", function(visible){
		$("#choice1").css("visibility", visible);
		$("#choice2").css("visibility", visible);
		$("#choice3").css("visibility", visible);
	});
	socket.on("third choice", function(choice)
	{
		$("#c3").text("FOLD");
	});
	socket.on("turn wait", function()
	{
		$("#curtain").css("visibility", "visible");
	});
	socket.on("your turn", function()
	{
		$("#curtain").css("visibility", "hidden");
		$("#raise_amount").text($("#min_bet").text());
		$('.ui-slider-horizontal .ui-slider-handle').css('left', '0%');
	});
	socket.on("init cards", function()
	{
		$("#card1, #card2").attr("src", "img/cards/card_back.png");
	});
}

function	choice1_chose()
{
	if ($("#c1").text() == "CHECK")
		socket.emit("player decision", "CHECK", channel + seat_nb.toString(), 0);
	else
		socket.emit("player decision", "CALL", channel + seat_nb.toString(), $("#c1_amount").text());
}

function	choice2_chose()
{
	socket.emit("player decision", "RAISE", channel + seat_nb.toString(), $("#c2_amount").text());
}

function	choice3_chose()
{
	socket.emit("player decision", "FOLD", channel + seat_nb.toString(), 0);
}

function	hide_cards()
{
	var		visibility = $("#card1, #card2").css("visibility");

	if (!g_connected)
		return ;
	if (visibility != "hidden")
		$("#card1, #card2, #hand_value").css("visibility", "hidden");
	else
		$("#card1, #card2, #hand_value").css("visibility", "visible");
}

function pot1_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var UnTier = pot/3;
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((UnTier/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (UnTier <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(UnTier.toFixed(2) + "$");
			$("#raise_amount").text(UnTier.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function pot2_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var UnTier = pot = pot / 3;
		var DeuxTier = UnTier + UnTier;
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((DeuxTier/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (DeuxTier <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(DeuxTier.toFixed(2) + "$");
			$("#raise_amount").text(DeuxTier.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function pot3_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((pot/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (pot <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(pot.toFixed(2) + "$");
			$("#raise_amount").text(pot.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function allin_chosen() {
	var allin = parseFloat($('#max_bet').text().substring(-1));
	$("#c2_amount").text(allin.toFixed(2) + "$");
	$("#raise_amount").text(allin.toFixed(2) + "$");
	$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
}

function	mouse_handler_device()
{
	$("#play").click(register_player);
	$("#choice1").click(choice1_chose);
	$("#choice2").click(choice2_chose);
	$("#choice3").click(choice3_chose);
	$("#hide_cards").click(hide_cards);
	$('#pot1').click(pot1_chosen);
	$('#pot2').click(pot2_chosen);
	$('#pot3').click(pot3_chosen);
	$('#allin').click(allin_chosen);
	$('#disconnect').click(function() {
		socket.disconnect();
		window.location = "http://poker.smartgames.tv/seat-disconnected.html";
	});
}

var	mouseEventReady = true;
<commit_msg>raise amount<commit_after>var			g_nickname;
var			g_connected = 0;

function	register_player()
{
	g_nickname = $("#nick_zone").val();
	if (!g_connected)
		socket.emit("is valid nickname", g_nickname, seat_nb);

	socket.on("is valid nickname info", function(res, nick)
	{
		if (res == "invalid" && !g_connected)
			$("#msg").text("Size must be between 2 and 8 characters without blanks!");
		else if (res == "valid" && !g_connected)
		{
			socket.emit("socket nickname on table", g_nickname);
			$("#msg").text("");
			$("#play").remove();
			$("#nick_zone").remove();
			$('#container').css("background-image", "url(img/please_wait.png)");
			$("#player_name").css("visibility", "hidden");
			$("#player_name").text(nick);
			g_connected = 1;
		}
		else if (res == "seat busy" && !g_connected)
			$("#msg").text("Seat busy. Please wait or choose another one.");
		else if (res == "already taken" && !g_connected)
			$("#msg").text("This nickname is already taken!");
	});
	socket.on("player name info")
		socket.emit("socket nickname on table", g_nickname);
	socket.on("first deal", function(card1, card2)
	{
		if (g_connected)
		{
			if ($("#container").css("background-image") != "url(img/player_decision.png)");
				$('#container').css("background-image", "url(img/player_decision.png)");
			$("#card1, #card2, #aim, #player_name, #slider, #hide_cards").css("visibility", "visible");
			$("#card1").attr("src", "img/cards/" + card1 + ".png");
			$("#card2").attr("src", "img/cards/" + card2 + ".png");
			$("#ui-state-default").focus();
			$("#curtain").css("visibility", "hidden");
		}
	});
	socket.on("first suit", function(suit)
	{
		$("#hand_value").text(suit);
	});
	socket.on("raise limits", function(r1, r2)
	{
		if (r1 >= 0) {
			$("#min_bet").text((Math.floor(+r1 * 100)) / 100 + "$");
			$("#c2_amount").text((Math.floor(+r1 * 100)) / 100 + "$");
		}
		if (r2 > 0)
			$("#max_bet").text((Math.floor(+r2 * 100)) / 100 + "$");
	});
	socket.on("first choice", function(choice, amount)
	{
		$('#bet_pot').css("visibility", "visible");
		$("#choice1").css("visibility", "visible");
		$("#choice2").css("visibility", "visible");
		$("#choice3").css("visibility", "visible");
		$("#hide_cards").css("visibility", "visible");
		if (choice == "call" && amount > 0)
		{
			$("#c1").text("CALL ");
			$("#c1_amount").text((Math.floor(+amount * 100)) / 100 + "$");
		}
		else if (choice == "check")
		{
			$("#c1").text("CHECK");
			$("#c1_amount").text('');
		}
	});
	socket.on("second choice", function(choice, amount)
	{
		if (choice == "null" && amount < 0)
		{
			$('#choice2').hide();
		}
		else if ((choice == "raise" || choice == "bet") && amount >= 0)
		{
			if (!amount)
				console.log('amount : ' + amount);
			$('#choice2').show();
			$("#c2").text(choice.toUpperCase() + " +");
			$("#c2_amount").text((Math.floor(amount * 100)) / 100 + "$");
			$("#raise_amount").text((Math.floor(amount * 100)) / 100 + "$");
		}
	});
	socket.on("cancel buttons", function(hidden){
		$("#choice1").css("visibility", hidden);
		$("#choice2").css("visibility", hidden);
		$("#choice3").css("visibility", hidden);
	});
	socket.on("show buttons", function(visible){
		$("#choice1").css("visibility", visible);
		$("#choice2").css("visibility", visible);
		$("#choice3").css("visibility", visible);
	});
	socket.on("third choice", function(choice)
	{
		$("#c3").text("FOLD");
	});
	socket.on("turn wait", function()
	{
		$("#curtain").css("visibility", "visible");
	});
	socket.on("your turn", function()
	{
		$("#curtain").css("visibility", "hidden");
		$("#raise_amount").text($("#min_bet").text());
		$('.ui-slider-horizontal .ui-slider-handle').css('left', '0%');
	});
	socket.on("init cards", function()
	{
		$("#card1, #card2").attr("src", "img/cards/card_back.png");
	});
}

function	choice1_chose()
{
	if ($("#c1").text() == "CHECK")
		socket.emit("player decision", "CHECK", channel + seat_nb.toString(), 0);
	else
		socket.emit("player decision", "CALL", channel + seat_nb.toString(), $("#c1_amount").text());
}

function	choice2_chose()
{
	socket.emit("player decision", "RAISE", channel + seat_nb.toString(), $("#c2_amount").text());
}

function	choice3_chose()
{
	socket.emit("player decision", "FOLD", channel + seat_nb.toString(), 0);
}

function	hide_cards()
{
	var		visibility = $("#card1, #card2").css("visibility");

	if (!g_connected)
		return ;
	if (visibility != "hidden")
		$("#card1, #card2, #hand_value").css("visibility", "hidden");
	else
		$("#card1, #card2, #hand_value").css("visibility", "visible");
}

function pot1_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var UnTier = pot/3;
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((UnTier/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (UnTier <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(UnTier.toFixed(2) + "$");
			$("#raise_amount").text(UnTier.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function pot2_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var UnTier = pot = pot / 3;
		var DeuxTier = UnTier + UnTier;
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((DeuxTier/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (DeuxTier <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(DeuxTier.toFixed(2) + "$");
			$("#raise_amount").text(DeuxTier.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function pot3_chosen() {
	socket.emit('get pot amount');
	socket.on('pot amount', function(pot) {
		var max_bet = parseFloat($('#max_bet').text().substring(-1));
		var min_bet = parseFloat($('#min_bet').text().substring(-1));
		var toSlide = ((pot/max_bet).toFixed(2))*100;

		if (toSlide >= 100) {
			$("#c2_amount").text(max_bet.toFixed(2) + "$");
			$("#raise_amount").text(max_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
		}
		else if (pot <= min_bet){
			$("#c2_amount").text(min_bet.toFixed(2) + "$");
			$("#raise_amount").text(min_bet.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', '-3%');
		}
		else {
			$("#c2_amount").text(pot.toFixed(2) + "$");
			$("#raise_amount").text(pot.toFixed(2) + "$");
			$('.ui-slider-horizontal .ui-slider-handle').css('left', toSlide+'%');
		}
	});
}

function allin_chosen() {
	var allin = parseFloat($('#max_bet').text().substring(-1));
	$("#c2_amount").text(allin.toFixed(2) + "$");
	$("#raise_amount").text(allin.toFixed(2) + "$");
	$('.ui-slider-horizontal .ui-slider-handle').css('left', '97%');
}

function	mouse_handler_device()
{
	$("#play").click(register_player);
	$("#choice1").click(choice1_chose);
	$("#choice2").click(choice2_chose);
	$("#choice3").click(choice3_chose);
	$("#hide_cards").click(hide_cards);
	$('#pot1').click(pot1_chosen);
	$('#pot2').click(pot2_chosen);
	$('#pot3').click(pot3_chosen);
	$('#allin').click(allin_chosen);
	$('#disconnect').click(function() {
		socket.disconnect();
		window.location = "http://poker.smartgames.tv/seat-disconnected.html";
	});
}

var	mouseEventReady = true;
<|endoftext|>


<commit_before>;(function () {

  var game = new Phaser.Game(GAME_WIDTH, GAME_HEIGHT, Phaser.AUTO, 'breakout', { preload: preload, create: create, update: update });
  var GAME_WIDTH = 800;
  var GAME_HEIGHT = 600;

  var background;

  var bricks;
  var BRICK_ROWS = 4;
  var BRICK_COLS = 15;
  var BRICK_START_X = 120;
  var BRICK_START_Y = 100;
  var BRICK_SPACING_X = 36;
  var BRICK_SPACING_Y = 52;

  var paddle;
  var PADDLE_Y = 500;
  var PADDLE_WIDTH = 48;

  var ball;
  var ballOnPaddle = true;
  var BALL_WIDTH = 16;
  var BALL_HEIGHT = 16;
  var BALL_RELEASE_VELOCITY_X = -75;
  var BALL_RELEASE_VELOCITY_Y = -300;
  var BALL_VELOCITY_MULTIPLIER_X = 10;

  var score = 0;
  var lives = 3;
  var scoreText;
  var livesText;
  var infoText;
  var TEXT_Y = 550;

  var socket;
  var remotePlayers = {};

  function preload() {
    console.log('preload invoked');
    game.load.atlas('breakout', '/assets/breakout.png', '/assets/breakout.json');
    game.load.image('starfield', '/assets/starfield.jpg');
  }

  function create() {
    console.log('create invoked');

    // Prevent game from pausing when browser tab loses focus
    game.stage.disableVisibilityChange = true;

    game.physics.startSystem(Phaser.Physics.ARCADE);

    background = game.add.tileSprite(0, 0, GAME_WIDTH, GAME_HEIGHT, 'starfield');

    // Check bounds collisions on all walls except bottom
    // game.physics.arcade.checkCollision.down = false;

    createBricks();
    createLocalPaddle();
    createLocalBall();
    createText();

    game.input.onDown.add(releaseBall, this);

    socket = io.connect(window.location.hostname);
    attachSocketHandlers();
  }

  function createBricks() {
    console.log('createBricks invoked');
    bricks = game.add.group();
    bricks.enableBody = true;
    bricks.physicsBodyType = Phaser.Physics.ARCADE;

    var brick;
    var brickCount = 0;

    for (var row = 0; row < BRICK_ROWS; row++) {
      for (var col = 0; col < BRICK_COLS; col++) {
        brick = bricks.create(
          BRICK_START_X + (col * BRICK_SPACING_X),
          BRICK_START_Y + (row * BRICK_SPACING_Y),
          'breakout',
          'brick_' + (row + 1) + '_1.png'
        );
        brick.body.bounce.set(1);
        brick.body.immovable = true;
        brick.brickIndex = brickCount++;
      }
    }
  }

  function createLocalPaddle() {
    console.log('createLocalPaddle invoked');
    paddle = game.add.sprite(game.world.centerX, PADDLE_Y, 'breakout', 'paddle_big.png');
    paddle.anchor.setTo(0.5, 0.5);

    game.physics.enable(paddle, Phaser.Physics.ARCADE);

    paddle.body.collideWorldBounds = true;
    paddle.body.bounce.set(1);
    paddle.body.immovable = true;
  }

  function createLocalBall() {
    console.log('createLocalBall invoked');
    ball = game.add.sprite(game.world.centerX, PADDLE_Y - BALL_HEIGHT, 'breakout', 'ball_1.png');
    ball.anchor.set(0.5);
    ball.checkWorldBounds = true;

    game.physics.enable(ball, Phaser.Physics.ARCADE);

    ball.body.collideWorldBounds = true;
    ball.body.bounce.set(1);

    ball.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);

    ball.events.onOutOfBounds.add(ballLost, this);
  }

  function releaseRemoteBall(data) {
    console.log('releaseRemoteBall invoked');

    //Creating a remoteball
    var remoteBall = game.add.sprite(data.posX, PADDLE_Y - BALL_HEIGHT, 'breakout', 'ball_1.png');
    remoteBall.anchor.set(0.5);
    remoteBall.checkWorldBounds = true;
    game.physics.enable(remoteBall, Phaser.Physics.ARCADE);
    remoteBall.body.collideWorldBounds = true;
    remoteBall.body.bounce.set(1);
    remoteBall.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);
    remoteBall.animations.play('spin');

    remoteBall.body.x = data.posX;
    remoteBall.body.velocity.x = data.exitVelocityX;
    remoteBall.body.velocity.y = data.exitVelocityY;

    remotePlayers[data.remotePlayerID]["remotePlayerBall"] = remoteBall;
    // ball.events.onOutOfBounds.add(ballLost, this);
  }

  function createText() {
    console.log('createText invoked');
    scoreText = game.add.text(32, TEXT_Y, 'score: 0',
      { font: '20px Arial', fill: '#ffffff', align: 'left' });
    livesText = game.add.text(GAME_WIDTH - 120, TEXT_Y, 'lives: 3',
      { font: '20px Arial', fill: '#ffffff', align: 'left' });
    infoText = game.add.text(game.world.centerX, GAME_HEIGHT * (2 / 3), 'Click to start',
      { font: '40px Arial', fill: '#ffffff', align: 'center' });
    infoText.anchor.setTo(0.5, 0.5);
  }

  function attachSocketHandlers() {
    console.log('attachSocketHandlers invoked');
    socket.on('connect', onSocketConnect);
    socket.on('disconnect', onSocketDisconnect);
    socket.on('new player', onNewPlayer);
    socket.on('remove player', onRemovePlayer);
    socket.on('initial bricks', onInitialBricks);
    socket.on('brick kill to other clients', onBrickKillToOtherClients);
    socket.on('paddle release ball', onPaddleReleaseBall);
    socket.on('ball hit paddle', onBallHitPaddle);
    socket.on('existing ball', onExistingBall);
    socket.on('kill remote ball', onKillRemoteBall);
  }

  function onKillRemoteBall(data) {
    console.log('onKillRemoteBall invoked');

    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.kill();
  }

  function onExistingBall(data) {
    console.log('onExistingBall invoked');
    //Creating a remoteball

    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];

    if (typeof b === "undefined") {
      var remoteBall = game.add.sprite(data.posX, data.posY, 'breakout', 'ball_1.png');
      remoteBall.anchor.set(0.5);
      remoteBall.checkWorldBounds = true;
      game.physics.enable(remoteBall, Phaser.Physics.ARCADE);
      remoteBall.body.collideWorldBounds = true;
      remoteBall.body.bounce.set(1);
      remoteBall.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);
      remoteBall.animations.play('spin');

      remoteBall.body.velocity.x = data.velocityX;
      remoteBall.body.velocity.y = data.velocityY;

      remotePlayers[data.remotePlayerID]["remotePlayerBall"] = remoteBall;
    }
  }

  function onBallHitPaddle(data) {
    console.log(data.exitVelocityX);
    console.log(data.exitVelocityY);

    // Identify remote player's ball and change its velocity accordingly
    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.body.velocity.x = data.exitVelocityX;
    b.body.velocity.y = data.exitVelocityY;
  }

  function onPaddleReleaseBall(data) {
    console.log("received message that other client has released ball");
    console.log("exit x vel = " + data.exitVelocityX);
    console.log("exit y vel = " + data.exitVelocityY);
    console.log("pos x = " + data.posX);

    releaseRemoteBall(data);
  }

  function onSocketConnect() {
    console.log('onSocketConnect invoked');
    console.log('emitting "new player" message with existingBricks = ' + bricksString(bricks));
    socket.emit('new player', { existingBricks: bricksString(bricks) });
  }

  function onSocketDisconnect() {
    console.log('onSocketDisconnect invoked');
  }

  function onNewPlayer(data) {

    // Notify new player of client's ball position and velocity, but only do so if player hasn't released ball

    if (!ballOnPaddle) {
      socket.emit('existing ball', {
        velocityX: ball.body.velocity.x,
        velocityY: ball.body.velocity.y,
        posX: ball.body.position.x,
        posY: ball.body.position.y
      });
    }

    // Commented out due to errors with Converting circular structure to JSON
    // console.log('onNewPlayer invoked. data = ' + JSON.stringify(data));
    remotePlayers[data.id] = { score: data.score };
    // console.log(data.id + ' added to remotePlayers: ' + JSON.stringify(remotePlayers));
  }

  function onRemovePlayer(data) {
    if (delete remotePlayers[data.id]) {
      console.log(data.id + ' removed from remotePlayers: ' + JSON.stringify(remotePlayers));
    } else {
      console.log(data.id + ' not found in remotePlayers');
    }
  }

  function onInitialBricks(data) {
    console.log('onInitialBricks invoked. data = ' + JSON.stringify(data));
    var i;
    for (var row = 0; row < BRICK_ROWS; row++) {
      for (var col = 0; col < BRICK_COLS; col++) {
        i = row * BRICK_COLS + col;
        if (data.initialBricks.charAt(i) === "0") {
          bricks.children[i].kill();
        }
      }
    }
  }

  function onBrickKillToOtherClients(data) {
    console.log('onBrickKillToOtherClients invoked');
    console.log(data.exitVelocityX);
    console.log(data.exitVelocityY);

    // Change the velocity of the remote ball
    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.body.velocity.x = data.exitVelocityX;
    b.body.velocity.y = data.exitVelocityY;

    bricks.children[data.brickIndex].kill();
  }

  function update() {
    paddle.body.x = game.input.x - 0.5 * PADDLE_WIDTH;

    if (paddle.body.x < 0) {
      paddle.body.x = 0;
    } else if (paddle.body.x > game.width - PADDLE_WIDTH) {
      paddle.body.x = game.width - PADDLE_WIDTH;
    }

    if (ballOnPaddle) {
      ball.body.x = paddle.body.x + 0.5 * PADDLE_WIDTH - 0.5 * BALL_WIDTH;
    } else {
      game.physics.arcade.collide(ball, paddle, ballHitPaddle, null, this);
      game.physics.arcade.collide(ball, bricks, ballHitBrick, null, this);
    }

    if (bricks.countLiving() === 0) {
      startNewRound();
    }
  }

  function releaseBall() {
    if (ballOnPaddle) {
      ballOnPaddle = false;
      ball.body.velocity.x = BALL_RELEASE_VELOCITY_X * ( Math.random() * 4 - 1 );
      ball.body.velocity.y = BALL_RELEASE_VELOCITY_Y;
      ball.animations.play('spin');
      infoText.visible = false;

      // Tell other clients of the release of ball
      socket.emit('paddle release ball', {
        exitVelocityX: ball.body.velocity.x,
        exitVelocityY: ball.body.velocity.y,
        posX: ball.body.x,
      });
    }
  }

  function ballLost() {
    socket.emit('kill remote ball');

    lives--;
    livesText.text = 'lives: ' + lives;
    if (lives === 0) {
      gameOver();
    } else {
      putBallOnPaddle();
    }
  }

  function putBallOnPaddle() {
    ballOnPaddle = true;
    ball.reset(paddle.body.x + 0.5 * PADDLE_WIDTH - 0.5 * BALL_WIDTH, PADDLE_Y - BALL_HEIGHT);
    ball.animations.stop();
  }

  function startNewRound() {
    socket.emit('kill remote ball');

    console.log('startNewRound invoked');
    bricks.callAll('revive');
    if (lives !==0 ) {
      putBallOnPaddle();
      score += 1000;
      scoreText.text = 'score: ' + score;
      infoText.text = 'Next Round';
    }
  }

  function gameOver() {
    ball.body.velocity.setTo(0, 0);

    infoText.text = 'Game Over!';
    infoText.visible = true;
  }

  function ballHitBrick(_ball, _brick) {
    socket.emit('brick kill from client', {
      brickIndex: _brick.brickIndex,
      exitVelocityX: ball.body.velocity.x,
      exitVelocityY: ball.body.velocity.y
    });

    _brick.kill();

    score += 10;
    scoreText.text = 'score: ' + score;
  }

  function ballHitPaddle(_ball, _paddle) {
    var diff = 0;

    if (_ball.body.x < _paddle.body.x) {
      //  Ball is on the left-hand side of the paddle
      diff = _paddle.body.x - _ball.body.x;
      _ball.body.velocity.x = (BALL_VELOCITY_MULTIPLIER_X * diff * -1);
    } else if (_ball.body.x > _paddle.body.x) {
      //  Ball is on the right-hand side of the paddle
      diff = _ball.body.x -_paddle.body.x;
      _ball.body.velocity.x = (BALL_VELOCITY_MULTIPLIER_X * diff);
    } else {
      //  Ball is perfectly in the middle
      //  Add a little random X to stop it bouncing straight up!
      _ball.body.velocity.x = BALL_VELOCITY_MULTIPLIER_X * 0.2 + Math.random() * BALL_VELOCITY_MULTIPLIER_X * 0.8;
    }

    console.log(_ball.body.velocity.x);
    console.log(_ball.body.velocity.y);

    socket.emit('ball hit paddle', {
      exitVelocityX: _ball.body.velocity.x,
      exitVelocityY: _ball.body.velocity.y
    });
  }

  function bricksString(bricksGroup) {
    var i;
    var length = bricksGroup.children.length;
    var result = "";
    for (i = 0; i < length; i++) {
      if (bricksGroup.children[i].alive) {
        result += "1";
      } else {
        result += "0";
      }
    }
    return result;
  }

}());
<commit_msg>client's remote ball is killed when disconnected, only works for 2 players<commit_after>;(function () {

  var game = new Phaser.Game(GAME_WIDTH, GAME_HEIGHT, Phaser.AUTO, 'breakout', { preload: preload, create: create, update: update });
  var GAME_WIDTH = 800;
  var GAME_HEIGHT = 600;

  var background;

  var bricks;
  var BRICK_ROWS = 4;
  var BRICK_COLS = 15;
  var BRICK_START_X = 120;
  var BRICK_START_Y = 100;
  var BRICK_SPACING_X = 36;
  var BRICK_SPACING_Y = 52;

  var paddle;
  var PADDLE_Y = 500;
  var PADDLE_WIDTH = 48;

  var ball;
  var ballOnPaddle = true;
  var BALL_WIDTH = 16;
  var BALL_HEIGHT = 16;
  var BALL_RELEASE_VELOCITY_X = -75;
  var BALL_RELEASE_VELOCITY_Y = -300;
  var BALL_VELOCITY_MULTIPLIER_X = 10;

  var score = 0;
  var lives = 3;
  var scoreText;
  var livesText;
  var infoText;
  var TEXT_Y = 550;

  var socket;
  var remotePlayers = {};

  function preload() {
    console.log('preload invoked');
    game.load.atlas('breakout', '/assets/breakout.png', '/assets/breakout.json');
    game.load.image('starfield', '/assets/starfield.jpg');
  }

  function create() {
    console.log('create invoked');

    // Prevent game from pausing when browser tab loses focus
    game.stage.disableVisibilityChange = true;

    game.physics.startSystem(Phaser.Physics.ARCADE);

    background = game.add.tileSprite(0, 0, GAME_WIDTH, GAME_HEIGHT, 'starfield');

    // Check bounds collisions on all walls except bottom
    // game.physics.arcade.checkCollision.down = false;

    createBricks();
    createLocalPaddle();
    createLocalBall();
    createText();

    game.input.onDown.add(releaseBall, this);

    socket = io.connect(window.location.hostname);
    attachSocketHandlers();
  }

  function createBricks() {
    console.log('createBricks invoked');
    bricks = game.add.group();
    bricks.enableBody = true;
    bricks.physicsBodyType = Phaser.Physics.ARCADE;

    var brick;
    var brickCount = 0;

    for (var row = 0; row < BRICK_ROWS; row++) {
      for (var col = 0; col < BRICK_COLS; col++) {
        brick = bricks.create(
          BRICK_START_X + (col * BRICK_SPACING_X),
          BRICK_START_Y + (row * BRICK_SPACING_Y),
          'breakout',
          'brick_' + (row + 1) + '_1.png'
        );
        brick.body.bounce.set(1);
        brick.body.immovable = true;
        brick.brickIndex = brickCount++;
      }
    }
  }

  function createLocalPaddle() {
    console.log('createLocalPaddle invoked');
    paddle = game.add.sprite(game.world.centerX, PADDLE_Y, 'breakout', 'paddle_big.png');
    paddle.anchor.setTo(0.5, 0.5);

    game.physics.enable(paddle, Phaser.Physics.ARCADE);

    paddle.body.collideWorldBounds = true;
    paddle.body.bounce.set(1);
    paddle.body.immovable = true;
  }

  function createLocalBall() {
    console.log('createLocalBall invoked');
    ball = game.add.sprite(game.world.centerX, PADDLE_Y - BALL_HEIGHT, 'breakout', 'ball_1.png');
    ball.anchor.set(0.5);
    ball.checkWorldBounds = true;

    game.physics.enable(ball, Phaser.Physics.ARCADE);

    ball.body.collideWorldBounds = true;
    ball.body.bounce.set(1);

    ball.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);

    ball.events.onOutOfBounds.add(ballLost, this);
  }

  function releaseRemoteBall(data) {
    console.log('releaseRemoteBall invoked');

    //Creating a remoteball
    var remoteBall = game.add.sprite(data.posX, PADDLE_Y - BALL_HEIGHT, 'breakout', 'ball_1.png');
    remoteBall.anchor.set(0.5);
    remoteBall.checkWorldBounds = true;
    game.physics.enable(remoteBall, Phaser.Physics.ARCADE);
    remoteBall.body.collideWorldBounds = true;
    remoteBall.body.bounce.set(1);
    remoteBall.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);
    remoteBall.animations.play('spin');

    remoteBall.body.x = data.posX;
    remoteBall.body.velocity.x = data.exitVelocityX;
    remoteBall.body.velocity.y = data.exitVelocityY;

    remotePlayers[data.remotePlayerID]["remotePlayerBall"] = remoteBall;
    // ball.events.onOutOfBounds.add(ballLost, this);
  }

  function createText() {
    console.log('createText invoked');
    scoreText = game.add.text(32, TEXT_Y, 'score: 0',
      { font: '20px Arial', fill: '#ffffff', align: 'left' });
    livesText = game.add.text(GAME_WIDTH - 120, TEXT_Y, 'lives: 3',
      { font: '20px Arial', fill: '#ffffff', align: 'left' });
    infoText = game.add.text(game.world.centerX, GAME_HEIGHT * (2 / 3), 'Click to start',
      { font: '40px Arial', fill: '#ffffff', align: 'center' });
    infoText.anchor.setTo(0.5, 0.5);
  }

  function attachSocketHandlers() {
    console.log('attachSocketHandlers invoked');
    socket.on('connect', onSocketConnect);
    socket.on('disconnect', onSocketDisconnect);
    socket.on('new player', onNewPlayer);
    socket.on('remove player', onRemovePlayer);
    socket.on('initial bricks', onInitialBricks);
    socket.on('brick kill to other clients', onBrickKillToOtherClients);
    socket.on('paddle release ball', onPaddleReleaseBall);
    socket.on('ball hit paddle', onBallHitPaddle);
    socket.on('existing ball', onExistingBall);
    socket.on('kill remote ball', onKillRemoteBall);
  }

  function onKillRemoteBall(data) {
    console.log('onKillRemoteBall invoked');

    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.kill();
  }

  function onExistingBall(data) {
    console.log('onExistingBall invoked');
    //Creating a remoteball

    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];

    if (typeof b === "undefined") {
      var remoteBall = game.add.sprite(data.posX, data.posY, 'breakout', 'ball_1.png');
      remoteBall.anchor.set(0.5);
      remoteBall.checkWorldBounds = true;
      game.physics.enable(remoteBall, Phaser.Physics.ARCADE);
      remoteBall.body.collideWorldBounds = true;
      remoteBall.body.bounce.set(1);
      remoteBall.animations.add('spin', [ 'ball_1.png', 'ball_2.png', 'ball_3.png', 'ball_4.png', 'ball_5.png' ], 50, true, false);
      remoteBall.animations.play('spin');

      remoteBall.body.velocity.x = data.velocityX;
      remoteBall.body.velocity.y = data.velocityY;

      remotePlayers[data.remotePlayerID]["remotePlayerBall"] = remoteBall;
    }
  }

  function onBallHitPaddle(data) {
    console.log(data.exitVelocityX);
    console.log(data.exitVelocityY);

    // Identify remote player's ball and change its velocity accordingly
    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.body.velocity.x = data.exitVelocityX;
    b.body.velocity.y = data.exitVelocityY;
  }

  function onPaddleReleaseBall(data) {
    console.log("received message that other client has released ball");
    console.log("exit x vel = " + data.exitVelocityX);
    console.log("exit y vel = " + data.exitVelocityY);
    console.log("pos x = " + data.posX);

    releaseRemoteBall(data);
  }

  function onSocketConnect() {
    console.log('onSocketConnect invoked');
    console.log('emitting "new player" message with existingBricks = ' + bricksString(bricks));
    socket.emit('new player', { existingBricks: bricksString(bricks) });
  }

  function onSocketDisconnect() {
    console.log('onSocketDisconnect invoked');
  }

  function onNewPlayer(data) {

    // Notify new player of client's ball position and velocity, but only do so if player hasn't released ball

    if (!ballOnPaddle) {
      socket.emit('existing ball', {
        velocityX: ball.body.velocity.x,
        velocityY: ball.body.velocity.y,
        posX: ball.body.position.x,
        posY: ball.body.position.y
      });
    }

    // Commented out due to errors with Converting circular structure to JSON
    // console.log('onNewPlayer invoked. data = ' + JSON.stringify(data));
    remotePlayers[data.id] = { score: data.score };
    // console.log(data.id + ' added to remotePlayers: ' + JSON.stringify(remotePlayers));
  }

  function onRemovePlayer(data) {

    remotePlayers[data.id]["remotePlayerBall"].kill();

    if (delete remotePlayers[data.id]) {
      console.log(data.id + ' removed from remotePlayers: ' + JSON.stringify(remotePlayers));
    } else {
      console.log(data.id + ' not found in remotePlayers');
    }
  }

  function onInitialBricks(data) {
    console.log('onInitialBricks invoked. data = ' + JSON.stringify(data));
    var i;
    for (var row = 0; row < BRICK_ROWS; row++) {
      for (var col = 0; col < BRICK_COLS; col++) {
        i = row * BRICK_COLS + col;
        if (data.initialBricks.charAt(i) === "0") {
          bricks.children[i].kill();
        }
      }
    }
  }

  function onBrickKillToOtherClients(data) {
    console.log('onBrickKillToOtherClients invoked');
    console.log(data.exitVelocityX);
    console.log(data.exitVelocityY);

    // Change the velocity of the remote ball
    var b = remotePlayers[data.remotePlayerID]["remotePlayerBall"];
    b.body.velocity.x = data.exitVelocityX;
    b.body.velocity.y = data.exitVelocityY;

    bricks.children[data.brickIndex].kill();
  }

  function update() {
    paddle.body.x = game.input.x - 0.5 * PADDLE_WIDTH;

    if (paddle.body.x < 0) {
      paddle.body.x = 0;
    } else if (paddle.body.x > game.width - PADDLE_WIDTH) {
      paddle.body.x = game.width - PADDLE_WIDTH;
    }

    if (ballOnPaddle) {
      ball.body.x = paddle.body.x + 0.5 * PADDLE_WIDTH - 0.5 * BALL_WIDTH;
    } else {
      game.physics.arcade.collide(ball, paddle, ballHitPaddle, null, this);
      game.physics.arcade.collide(ball, bricks, ballHitBrick, null, this);
    }

    if (bricks.countLiving() === 0) {
      startNewRound();
    }
  }

  function releaseBall() {
    if (ballOnPaddle) {
      ballOnPaddle = false;
      ball.body.velocity.x = BALL_RELEASE_VELOCITY_X * ( Math.random() * 4 - 1 );
      ball.body.velocity.y = BALL_RELEASE_VELOCITY_Y;
      ball.animations.play('spin');
      infoText.visible = false;

      // Tell other clients of the release of ball
      socket.emit('paddle release ball', {
        exitVelocityX: ball.body.velocity.x,
        exitVelocityY: ball.body.velocity.y,
        posX: ball.body.x,
      });
    }
  }

  function ballLost() {
    socket.emit('kill remote ball');

    lives--;
    livesText.text = 'lives: ' + lives;
    if (lives === 0) {
      gameOver();
    } else {
      putBallOnPaddle();
    }
  }

  function putBallOnPaddle() {
    ballOnPaddle = true;
    ball.reset(paddle.body.x + 0.5 * PADDLE_WIDTH - 0.5 * BALL_WIDTH, PADDLE_Y - BALL_HEIGHT);
    ball.animations.stop();
  }

  function startNewRound() {
    socket.emit('kill remote ball');

    console.log('startNewRound invoked');
    bricks.callAll('revive');
    if (lives !==0 ) {
      putBallOnPaddle();
      score += 1000;
      scoreText.text = 'score: ' + score;
      infoText.text = 'Next Round';
    }
  }

  function gameOver() {
    ball.body.velocity.setTo(0, 0);

    infoText.text = 'Game Over!';
    infoText.visible = true;
  }

  function ballHitBrick(_ball, _brick) {
    socket.emit('brick kill from client', {
      brickIndex: _brick.brickIndex,
      exitVelocityX: ball.body.velocity.x,
      exitVelocityY: ball.body.velocity.y
    });

    _brick.kill();

    score += 10;
    scoreText.text = 'score: ' + score;
  }

  function ballHitPaddle(_ball, _paddle) {
    var diff = 0;

    if (_ball.body.x < _paddle.body.x) {
      //  Ball is on the left-hand side of the paddle
      diff = _paddle.body.x - _ball.body.x;
      _ball.body.velocity.x = (BALL_VELOCITY_MULTIPLIER_X * diff * -1);
    } else if (_ball.body.x > _paddle.body.x) {
      //  Ball is on the right-hand side of the paddle
      diff = _ball.body.x -_paddle.body.x;
      _ball.body.velocity.x = (BALL_VELOCITY_MULTIPLIER_X * diff);
    } else {
      //  Ball is perfectly in the middle
      //  Add a little random X to stop it bouncing straight up!
      _ball.body.velocity.x = BALL_VELOCITY_MULTIPLIER_X * 0.2 + Math.random() * BALL_VELOCITY_MULTIPLIER_X * 0.8;
    }

    console.log(_ball.body.velocity.x);
    console.log(_ball.body.velocity.y);

    socket.emit('ball hit paddle', {
      exitVelocityX: _ball.body.velocity.x,
      exitVelocityY: _ball.body.velocity.y
    });
  }

  function bricksString(bricksGroup) {
    var i;
    var length = bricksGroup.children.length;
    var result = "";
    for (i = 0; i < length; i++) {
      if (bricksGroup.children[i].alive) {
        result += "1";
      } else {
        result += "0";
      }
    }
    return result;
  }

}());
<|endoftext|>