diff --git a/README.md b/README.md
index bcd9aad86f0c83bf29c400c3449a0a44a2525a96..0f59ec0810e5e606e30e3d3012cdd1edc48d8b2c 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,36 @@
 BigBlueButton
 =============
-BigBlueButton is an open source web conferencing system for on-line learning.  
+BigBlueButton is an open source web conferencing system for on-line learning.  We believe that every student with a web browser should have access to a high-quality on-line learning experience.  We intend to make that possible with BigBlueButton. 
 
-We believe that every student with a web browser should have access to a high-quality on-line learning experience.  We intend to make that possible with BigBlueButton. 
-
-BigBlueButton supports real-time sharing of slides (PDF and any document readable by LibreOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop.  It can record and playback all content shared in a session.  The use cases for BigBlueButton are
+BigBlueButton supports real-time sharing of slides (PDF and any document readable by OpenOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop. It can record and playback all content shared in a session.  The BigBlueButton project is is supported by a [community of developers] (http://www.bigbluebutton.org/support/) that care about good design and a streamlined user experience. 
 
+The use cases for BigBlueButton are
   * One-to-one on-line tutoring
   * Small group collaboration 
-  * On-line classes (50 or less)
+  * On-line classes (25 or less)
+
+BigBlueButton is built on the [shoulders of giants] (http://www.bigbluebutton.org/components/).
+
+Getting Started
+===============
+All the core information is at the [Google Code project page] (http://code.google.com/p/bigbluebutton/).  Here are a few quick links
+
+If you want to see how BigBlueButton works, check out these two videos
+  * [presenter] (http://www.bigbluebutton.org/videos/)
+  * [viewer] (http://www.bigbluebutton.org/videos/)
+
+After watching the videos, if you want to immediately try out BigBlueButton, the project maintains a live [demo server] (http://demo.bigbluebutton.org) that anyone can join.  
+
+To quickly get started running your own BigBlueButton server
+  * [Install on Ubunt 10.04 64-bit] (http://code.google.com/p/bigbluebutton/wiki/InstallationUbuntu)
+  * [Download the BigBlueButton 0.81 Virtual Machine] (http://code.google.com/p/bigbluebutton/wiki/BigBlueButtonVM)
+
+See also [history of project] (http://www.bigbluebutton.org/history/).
+
+If you like the work we've done with BigBlueButton and would like to contribute improvemets to the project, see [Contribute to BigBlueButton] (http://code.google.com/p/bigbluebutton/wiki/FAQ#Contributing_to_BigBlueButton).
 
-For more information on the latest release -- including installation instructions, demo server, API, and overview of architecture -- see [http://docs.bigbluebutton.org/](http://docs.bigbluebutton.org/).
+License
+=======
+BigBlueButton is licensed under the LGPL 3.0.
 
 BigBlueButton and the BigBlueButton Logo are trademarks of [BigBlueButton Inc] (http://bigbluebutton.org) .
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
index 147e96fc7ac3214e0ceef55ded889b7b8f7eed5e..3ae50c5bb609ab6e4a6faed6038264639fd005b1 100755
--- a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
@@ -25,14 +25,15 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.Timer;
 import java.util.TimerTask;
 
+import org.apache.commons.lang3.StringUtils;
 import org.bigbluebutton.app.video.h263.H263Converter;
 import org.red5.logging.Red5LoggerFactory;
 import org.red5.server.adapter.MultiThreadedApplicationAdapter;
 import org.red5.server.api.IConnection;
 import org.red5.server.api.Red5;
-import org.red5.server.api.scope.IScope;
 import org.red5.server.api.scope.IBasicScope;
 import org.red5.server.api.scope.IBroadcastScope;
+import org.red5.server.api.scope.IScope;
 import org.red5.server.api.scope.ScopeType;
 import org.red5.server.api.stream.IBroadcastStream;
 import org.red5.server.api.stream.IPlayItem;
@@ -41,7 +42,6 @@ import org.red5.server.api.stream.IStreamListener;
 import org.red5.server.api.stream.ISubscriberStream;
 import org.red5.server.stream.ClientBroadcastStream;
 import org.slf4j.Logger;
-import org.apache.commons.lang3.StringUtils;
 import com.google.gson.Gson;
 
 public class VideoApplication extends MultiThreadedApplicationAdapter {
@@ -53,15 +53,15 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 	private boolean recordVideoStream = false;
 	private EventRecordingService recordingService;
 	private final Map<String, IStreamListener> streamListeners = new HashMap<String, IStreamListener>();
-
-    private Map<String, CustomStreamRelay> remoteStreams = new ConcurrentHashMap<String, CustomStreamRelay>();
-    private Map<String, Integer> listenersOnRemoteStream = new ConcurrentHashMap<String, Integer>();
+	
+	private Map<String, CustomStreamRelay> remoteStreams = new ConcurrentHashMap<String, CustomStreamRelay>();
+	private Map<String, Integer> listenersOnRemoteStream = new ConcurrentHashMap<String, Integer>();
 
 	// Proxy disconnection timer
 	private Timer timer;
 	// Proxy disconnection timeout
 	private long relayTimeout;
-
+
 	private final Map<String, H263Converter> h263Converters = new HashMap<String, H263Converter>();
 
     @Override
@@ -191,16 +191,14 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     	super.streamPublishStart(stream);
     }
     
-
     public IBroadcastScope getBroadcastScope(IScope scope, String name) {
-    IBasicScope basicScope = scope.getBasicScope(ScopeType.BROADCAST, name);
-    if (!(basicScope instanceof IBroadcastScope)) {
-        return null;
-    } else {
-        return (IBroadcastScope) basicScope;
+        IBasicScope basicScope = scope.getBasicScope(ScopeType.BROADCAST, name);
+        if (basicScope instanceof IBroadcastScope) {
+            return (IBroadcastScope) basicScope;
+        } else {
+            return null;
+        }
     }
-}
-
 
     @Override
     public void streamBroadcastStart(IBroadcastStream stream) {
@@ -220,14 +218,11 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     private Long genTimestamp() {
     	return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
     }
-
-	private boolean isH263Stream(ISubscriberStream stream) {
-		String streamName = stream.getBroadcastStreamPublishName();
-		if(streamName.startsWith(H263Converter.H263PREFIX)) {
-			return true;
-		}
-		return false;
-	}
+    
+    private boolean isH263Stream(ISubscriberStream stream) {
+        String streamName = stream.getBroadcastStreamPublishName();
+        return streamName.startsWith(H263Converter.H263PREFIX);
+    }
 
     @Override
     public void streamBroadcastClose(IBroadcastStream stream) {
@@ -258,10 +253,10 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
         recordingService.record(scopeName, event);    		
       }
 
-		if(h263Converters.containsKey(stream.getName())) {
-			// Stop converter
-			h263Converters.remove(stream.getName()).stopConverter();
-		}
+      if (h263Converters.containsKey(stream.getName())) {
+        // Stop converter
+        h263Converters.remove(stream.getName()).stopConverter();
+      }
     }
     
     /**
@@ -290,15 +285,16 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 	public void setEventRecordingService(EventRecordingService s) {
 		recordingService = s;
 	}
-
+	
 	public void setRelayTimeout(long timeout) {
 		this.relayTimeout = timeout;
 	}
-    @Override
-    public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) {
-        // log w3c connect event
-        String streamName = item.getName();
-        streamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
+
+	@Override
+	public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) {
+		// log w3c connect event
+		String streamName = item.getName();
+		streamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
 
 		if(isH263Stream(stream)) {
 			log.trace("Detected H263 stream request [{}]", streamName);
@@ -315,7 +311,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 				}
 			}
 		}
-        if(streamName.contains("/")) {
+		if(streamName.contains("/")) {
 			synchronized(remoteStreams) {
 				if(remoteStreams.containsKey(streamName) == false) {
 					String[] parts = streamName.split("/");
@@ -346,9 +342,8 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 		log.info("W3C x-category:stream x-event:play c-ip:{} x-sname:{} x-name:{}", new Object[] { Red5.getConnectionLocal().getRemoteAddress(), stream.getName(), item.getName() });
 	}
 
-    @Override
-    public void streamSubscriberClose(ISubscriberStream stream) {
-
+	@Override
+	public void streamSubscriberClose(ISubscriberStream stream) {
 		String streamName = stream.getBroadcastStreamPublishName();
 		streamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
 
@@ -382,7 +377,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 				}
 			}
 		}
-    }
+	}
 
 	private final class DisconnectProxyTask extends TimerTask {
 		// Stream name that should be disconnected
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java
index ef1602b6cddc74a32690a647aba53c0d502c747e..206fe69b5e4ea39b7838e5ffc546bef8f983ac13 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/BigBlueButtonApplication.java
@@ -91,14 +91,12 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
     
 	@Override
 	public boolean roomStart(IScope room) {
-		connInvokerService.addScope(room.getName(), room);
 		return super.roomStart(room);
 	}	
 	
 	@Override
 	public void roomStop(IScope room) {
 		recorderApplication.destroyRecordSession(room.getName());	
-		connInvokerService.removeScope(room.getName());
 		super.roomStop(room);
 	}
     	
@@ -154,8 +152,6 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
 		
 		bbbGW.initAudioSettings(room, internalUserID, muted);
 
-		boolean success = connInvokerService.addConnection(internalUserID, connection);
-
 	    String meetingId = bbbSession.getRoom();
 	    
 	    String connType = getConnectionType(Red5.getConnectionLocal().getType());
@@ -182,7 +178,7 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
 		
 		log.info("User joining bbb-apps: data={}", logStr);
 		
-		return success && super.roomConnect(connection, params);
+		return super.roomConnect(connection, params);
         
 	}
 
@@ -204,8 +200,6 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
 		String clientId = Red5.getConnectionLocal().getClient().getId();
 		log.info("***** " + APP + "[clientid=" + clientId + "] disconnnected from " + remoteHost + ":" + remotePort + ".");
 
-		connInvokerService.removeConnection(getBbbSession().getInternalUserID());
-
 	    BigBlueButtonSession bbbSession = (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION);
 	          
 	    String meetingId = bbbSession.getRoom();
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java
index 2ed65996ae4ba4cb0405949c5dbaa23f8519ff05..9988ef9e794f3955fb2725a1639ef42f63455490 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/meeting/messaging/red5/ConnectionInvokerService.java
@@ -49,38 +49,17 @@ public class ConnectionInvokerService {
 	
 	private BlockingQueue<ClientMessage> messages;
 	
-	private ConcurrentHashMap<String, IConnection> connections;
-	private ConcurrentHashMap<String, IScope> scopes;
-	
 	private volatile boolean sendMessages = false;
 	private IScope bbbAppScope;
 
 	public ConnectionInvokerService() {
 		messages = new LinkedBlockingQueue<ClientMessage>();
-
-		connections = new ConcurrentHashMap<String, IConnection>();
-		scopes = new ConcurrentHashMap<String, IScope>();
 	}
 
 	public void setAppScope(IScope scope) {
 		bbbAppScope = scope;
 	}
 
-	public boolean addConnection(String id, IConnection conn) {
-		if (connections == null) {
-			System.out.println("Connections is null!!!!");
-			return false;
-		}
-		if (id == null) {
-			System.out.println("CONN ID IS NULL!!!");
-			
-		}
-		if (conn == null) {
-			System.out.println("CONN IS NULL");
-		}
-		return connections.putIfAbsent(id, conn) == null;
-	}
-	
 	public void start() {
 		sendMessages = true;
 		Runnable sender = new Runnable() {
@@ -105,18 +84,6 @@ public class ConnectionInvokerService {
 		sendMessages = false;
 	}
 	
-	public void removeConnection(String id) {
-		connections.remove(id);
-	}
-	
-	public void addScope(String id, IScope scope) {
-		scopes.putIfAbsent(id, scope);
-	}
-	
-	public void removeScope(String id) {
-		scopes.remove(id);
-	}
-	
 	public void sendMessage(final ClientMessage message) {
 		messages.offer(message);
 	}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java
index 78c58fa1023f7249ca43181de434980d7c57f227..33f022c4037b4d5789e54afedaed3f48605c732c 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/presentation/ConversionUpdatesProcessor.java
@@ -19,8 +19,7 @@
 package org.bigbluebutton.conference.service.presentation;
 
 import org.slf4j.Logger;
-import org.red5.logging.Red5LoggerFactory;
-
+import org.red5.logging.Red5LoggerFactory;

 public class ConversionUpdatesProcessor {
 	private static Logger log = Red5LoggerFactory.getLogger(ConversionUpdatesProcessor.class, "bigbluebutton");
 
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java
index 8f80bdb8bd8eb1f8a8d9a0cdac0c9151e3830b0e..47bc7b68c60f50e5301787ac2ac46fa8150a62b3 100644
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/whiteboard/WhiteboardListener.java
@@ -20,6 +20,7 @@ public class WhiteboardListener implements MessageHandler{
 	@Override
 	public void handleMessage(String pattern, String channel, String message) {
 		if (channel.equalsIgnoreCase(MessagingConstants.TO_WHITEBOARD_CHANNEL)) {
+			System.out.println("AntonChannel=(whiteboard)" + channel);
 
 			JsonParser parser = new JsonParser();
 			JsonObject obj = (JsonObject) parser.parse(message);
@@ -43,7 +44,7 @@ public class WhiteboardListener implements MessageHandler{
 					else {
 						System.out.println("\n DID NOT FIND A whiteboardID \n");
 					}
-					System.out.println("\n user<" + requesterID + "> requested the shapes.\n");
+					System.out.println("\n\n\n user<" + requesterID + "> requested the shapes.\n\n");
 				}
 			}
 		}
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
index 3b3702d983e303d6aa4eacd0e8dfdd68e82e9f00..9980fda2e5471b0db2b45cab71cc8833279ed060 100755
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
@@ -158,9 +158,6 @@ class BigBlueButtonActor(outGW: MessageOutGateway) extends Actor with LogHelper
 
       //send chat history
       this ! (new GetChatHistoryRequest(id, "nodeJSapp", "nodeJSapp"))
-
-      //send lock settings
-      this ! (new GetLockSettings(id, "nodeJSapp"))
     }
 
     outGW.send(new GetAllMeetingsReply(resultArray))
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
index a360550d2f7a40b186765e0a48086134121146cc..ffcede9aed2188cf8ccc78526269f17c612738b9 100755
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
@@ -197,14 +197,10 @@ class BigBlueButtonInGW(bbbGW: BigBlueButtonGateway, presUtil: PreuploadedPresen
   }
 
   def userConnectedToGlobalAudio(voiceConf: String, userid: String, name: String) {
-    // we are required to pass the meeting_id as first parameter (just to satisfy trait)
-    // but it's not used anywhere. That's why we pass voiceConf twice instead
     bbbGW.accept(new UserConnectedToGlobalAudio(voiceConf, voiceConf, userid, name))
   }
   
   def userDisconnectedFromGlobalAudio(voiceConf: String, userid: String, name: String) {
-    // we are required to pass the meeting_id as first parameter (just to satisfy trait)
-    // but it's not used anywhere. That's why we pass voiceConf twice instead
     bbbGW.accept(new UserDisconnectedFromGlobalAudio(voiceConf, voiceConf, userid, name))
   }
 
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
index 96dd63e40b910ab637d829aa32d3dea912fde6da..9a7ba08db674443002dd98e4faf95fa3aa18b697 100755
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
@@ -93,7 +93,6 @@ class MeetingActor(val meetingID: String, val externalMeetingID: String, val mee
 	    case msg: MuteUserRequest                        => handleMuteUserRequest(msg)
 	    case msg: EjectUserFromVoiceRequest              => handleEjectUserRequest(msg)
 	    case msg: SetLockSettings                        => handleSetLockSettings(msg)
-	    case msg: GetLockSettings                        => handleGetLockSettings(msg)
       case msg: LockUserRequest                        => handleLockUserRequest(msg)
 	    case msg: InitLockSettings                       => handleInitLockSettings(msg)
       case msg: InitAudioSettings                      => handleInitAudioSettings(msg)
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala
index 190167883f8ae228613d8c8a3e876a0ce0da9362..9f1820498c362508273e6517d8f8a7e9ff7e52eb 100755
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/layout/red5/LayoutClientMessageSender.scala
@@ -30,10 +30,10 @@ class LayoutClientMessageSender(service: ConnectionInvokerService) extends OutMe
 	private def handleBroadcastLayoutEvent(msg: BroadcastLayoutEvent) {
 	  val message = new java.util.HashMap[String, Object]()  	
 	  message.put("locked", msg.locked:java.lang.Boolean);
-	  message.put("setByUserID", msg.requesterID);
+	  message.put("setByUserID", msg.setByUserID);
 	  message.put("layout", msg.layoutID);
 	  
-	  msg.applyTo.filter(_.userID != msg.requesterID) foreach {u =>
+	  msg.applyTo foreach {u =>
 	    var m = new DirectClientMessage(msg.meetingID, u.userID, "syncLayout", message);
 	    service.sendMessage(m);	    
 	  }  
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
index 53334d73a55923b0191fbccff2ed0872d98da4f1..4311242bdd2a2337e919fd92e9e92c11763cf318 100644
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/UsersApp.scala
@@ -82,11 +82,18 @@ trait UsersApp {
         //send the reply
         outGW.send(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, true, msg.correlationId, msg.sessionId))
 
+        //send the list of users in the meeting
+        outGW.send(new GetUsersReply(meetingID, msg.userId, users.getUsers, msg.sessionId))
+
+        //send chat history
+        this ! (new GetChatHistoryRequest(meetingID, msg.userId, msg.userId))
+
         //join the user
         handleUserJoin(new UserJoining(meetingID, msg.userId, msg.token))
 
         //send the presentation
         logger.info("ValidateToken success: mid=[" + meetingID + "] uid=[" + msg.userId + "]")
+        this ! (new GetPresentationInfo(meetingID, msg.userId, msg.userId))
       }
       case None => {
         logger.info("ValidateToken failed: mid=[" + meetingID + "] uid=[" + msg.userId + "]")
@@ -97,7 +104,7 @@ trait UsersApp {
     /**
      * Send a reply to BigBlueButtonActor to let it know this MeetingActor hasn't hung!
      * Sometimes, the actor seems to hang and doesn't anymore accept messages. This is a simple
-     * audit to check whether the actor is still alive. (ralam feb 25, 2015)
+     * audit to check whether the actor is still alive. (ralam feb 25, 2015)
      */
     reply(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, false, msg.correlationId))
   }
@@ -147,14 +154,11 @@ trait UsersApp {
       case None => // do nothing
     }
   }
-
+  
   def handleGetLockSettings(msg: GetLockSettings) {
-    //println("*************** Reply with current lock settings ********************")
-
-    //reusing the existing handle for NewPermissionsSettings to reply to the GetLockSettings request
-    outGW.send(new NewPermissionsSetting(meetingID, msg.userId, permissions, users.getUsers))
+    logger.info("Not implemented: handleGetLockSettings")
   }
-
+  
   def handleSetLockSettings(msg: SetLockSettings) {
 //    println("*************** Received new lock settings ********************")
     if (!permissionsEqual(msg.settings)) {
@@ -316,7 +320,7 @@ trait UsersApp {
 	    if (u.presenter) {
 	      /* The current presenter has left the meeting. Find a moderator and make
 	       * him presenter. This way, if there is a moderator in the meeting, there
-	       * will always be a presenter.
+	       * will always be a presenter.
 	       */
 	      val moderator = users.findAModerator()
 	      moderator.foreach { mod =>
diff --git a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala
index ae70ada5d8b37fbde94695a615a4126f0fd8ef23..693c75c283e55dfeed45db62f5718537a3d8a4f2 100644
--- a/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala
+++ b/bigbluebutton-apps/src/main/scala/org/bigbluebutton/core/apps/users/redis/UsersMessageToJsonConverter.scala
@@ -137,7 +137,7 @@ object UsersMessageToJsonConverter {
     payload.put(Constants.STATUS, msg.status)
     payload.put(Constants.VALUE, msg.value.toString)
 
-		val header = Util.buildHeader(MessageNames.USER_STATUS_CHANGED, msg.version, None)
+    val header = Util.buildHeader(MessageNames.USER_STATUS_CHANGED, msg.version, None)
     Util.buildJson(header, payload)
 	}
 
diff --git a/bigbluebutton-client/branding/default/style/css/BBBBlack.css b/bigbluebutton-client/branding/default/style/css/BBBBlack.css
index 10d9f8d963f4e2a7fb5acba0b3bad44fc5f0f456..af1050468f696c7d82e06ae9a9ba8736debd3af6 100755
--- a/bigbluebutton-client/branding/default/style/css/BBBBlack.css
+++ b/bigbluebutton-client/branding/default/style/css/BBBBlack.css
@@ -46,7 +46,7 @@ ToolTip {
   paddingRight: 3;
 }
 
-Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .bandwidthButtonStyle {
+Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle {
   textIndent: 0;
   paddingLeft: 10;
   paddingRight: 10;
@@ -643,11 +643,4 @@ MDIWindow { /*None of the following properties are overridden by the MDIWindow c
 	fontFamily: Arial;
 	fontSize: 20;  
 	fontWeight: bold;
-}
-
-.bandwidthButtonStyle {
-  paddingTop: 0;
-  paddingBottom: 0;
-  height: 22;
-  icon:   Embed('assets/images/bandwidth.png');
-}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties
index cc2875fd2db577c9c05e3d9b1aaca156fa169c88..b401d55f497bc61d5514f7146ab74deb73203a62 100755
--- a/bigbluebutton-client/locale/en_US/bbbResources.properties
+++ b/bigbluebutton-client/locale/en_US/bbbResources.properties
@@ -394,7 +394,7 @@ bbb.logout.appshutdown = The server app has been shut down
 bbb.logout.asyncerror = An Async Error occured
 bbb.logout.connectionclosed = The connection to the server has been closed
 bbb.logout.connectionfailed = The connection to the server has failed
-bbb.logout.rejected = The connection to the server has been rejected\n\nIt may occur when you try to use the same session in multiple tabs in your browser
+bbb.logout.rejected = The connection to the server has been rejected
 bbb.logout.invalidapp = The red5 app does not exist
 bbb.logout.unknown = Your client has lost connection with the server
 bbb.logout.guestkickedout = The moderator didn't allow you to join this meeting
diff --git a/bigbluebutton-client/locale/pt_BR/bbbResources.properties b/bigbluebutton-client/locale/pt_BR/bbbResources.properties
index ab62ac3bc1cf4bca773d760faf9e45853a2869f1..66d4bb885b31cf1a34650ef98555d02629854c04 100755
--- a/bigbluebutton-client/locale/pt_BR/bbbResources.properties
+++ b/bigbluebutton-client/locale/pt_BR/bbbResources.properties
@@ -393,7 +393,7 @@ bbb.logout.appshutdown = A aplicação no servidor foi interrompida
 bbb.logout.asyncerror = Um erro assíncrono ocorreu
 bbb.logout.connectionclosed = A conexão com o servidor foi fechada
 bbb.logout.connectionfailed = A conexão com o servidor falhou
-bbb.logout.rejected = A conexão com o servidor foi rejeitada\n\nIsso pode ocorrer quando você tenta utilizar a mesma sessão em múltiplas abas no seu navegador
+bbb.logout.rejected = A conexão com o servidor foi rejeitada
 bbb.logout.invalidapp = O aplicativo red5 não existe
 bbb.logout.unknown = Seu cliente perdeu conexão com o servidor
 bbb.logout.guestkickedout = O moderador não permitiu sua entrada na sala
diff --git a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
index 0a5eb75c596717292650e718ad33f2be41ba081f..245ba860eefa73f063fd1990c5a5db9a85ff62ce 100755
--- a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
+++ b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
@@ -37,26 +37,15 @@ function webRTCCallback(message) {
 	}
 }
 
-function callIntoConference(voiceBridge, callback, isListenOnly) {
-	// root of the call initiation process from the html5 client
-	// Flash will not pass in the listen only field. For html5 it is optional. Assume NOT listen only if no state passed
-	if (isListenOnly == null) {
-		isListenOnly = false;
-	}
-
+function callIntoConference(voiceBridge, callback) {
 	if (!callerIdName) {
 		BBB.getMyUserInfo(function(userInfo) {
 			console.log("User info callback [myUserID=" + userInfo.myUserID
 				+ ",myUsername=" + userInfo.myUsername + ",myAvatarURL=" + userInfo.myAvatarURL
 				+ ",myRole=" + userInfo.myRole + ",amIPresenter=" + userInfo.amIPresenter
-				+ ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge
-				+ ",isListenOnly=" + isListenOnly + "].");
+				+ ",dialNumber=" + userInfo.dialNumber + ",voiceBridge=" + userInfo.voiceBridge + "].");
 			userID = userInfo.myUserID;
 			callerIdName = userInfo.myUserID + "-bbbID-" + userInfo.myUsername;
-			if (isListenOnly) {
-				//prepend the callerIdName so it is recognized as a global audio user
-				callerIdName = "GLOBAL_AUDIO_" + callerIdName;
-			}
 			conferenceVoiceBridge = userInfo.voiceBridge
 			if (voiceBridge === "9196") {
 				voiceBridge = voiceBridge + conferenceVoiceBridge;
@@ -64,7 +53,7 @@ function callIntoConference(voiceBridge, callback, isListenOnly) {
 				voiceBridge = conferenceVoiceBridge;
 			}
 			console.log(callerIdName);
-			webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
+			webrtc_call(callerIdName, voiceBridge, callback);
 		});
 	} else {
 		if (voiceBridge === "9196") {
@@ -72,7 +61,7 @@ function callIntoConference(voiceBridge, callback, isListenOnly) {
 		} else {
 			voiceBridge = conferenceVoiceBridge;
 		}
-		webrtc_call(callerIdName, voiceBridge, callback, isListenOnly);
+		webrtc_call(callerIdName, voiceBridge, callback);
 	}
 }
 
@@ -220,30 +209,25 @@ function getUserMicMedia(getUserMicMediaSuccess, getUserMicMediaFailure) {
 	}
 };
 
-function webrtc_call(username, voiceBridge, callback, isListenOnly) {
+function webrtc_call(username, voiceBridge, callback) {
 	if (!isWebRTCAvailable()) {
 		callback({'status': 'failed', 'errorcode': 1003}); // Browser version not supported
 		return;
 	}
-	if (isListenOnly == null) { // assume NOT listen only unless otherwise stated
-		isListenOnly = false;
-	}
-
+	
 	var server = window.document.location.hostname;
 	console.log("user " + username + " calling to " +  voiceBridge);
-
+	
 	var makeCallFunc = function() {
-		// only make the call when both microphone and useragent have been created
-		// for listen only, stating listen only is a viable substitute for acquiring user media control
-		if ((isListenOnly||userMicMedia) && userAgent)
-			make_call(username, voiceBridge, server, callback, false, isListenOnly);
+		if (userMicMedia && userAgent) // only make the call when both microphone and useragent have been created
+			make_call(username, voiceBridge, server, callback, false);
 	};
+	
 	if (!userAgent) {
 		createUA(username, server, callback, makeCallFunc);
 	}
-	// if the user requests to proceed as listen only (does not require media) or media is already acquired,
-	// proceed with making the call
-	if (isListenOnly || userMicMedia !== undefined) {
+	
+	if (userMicMedia !== undefined) {
 		makeCallFunc();
 	} else {
 		callback({'status':'mediarequest'});
@@ -260,15 +244,11 @@ function webrtc_call(username, voiceBridge, callback, isListenOnly) {
 	}
 }
 
-function make_call(username, voiceBridge, server, callback, recall, isListenOnly) {
-	if (isListenOnly == null) {
-		isListenOnly = false;
-	}
-
+function make_call(username, voiceBridge, server, callback, recall) {
 	if (userAgent == null) {
 		console.log("userAgent is still null. Delaying call");
 		var callDelayTimeout = setTimeout( function() {
-			make_call(username, voiceBridge, server, callback, recall, isListenOnly);
+			make_call(username, voiceBridge, server, callback, recall);
 		}, 100);
 		return;
 	}
@@ -277,7 +257,7 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly
 		console.log("Trying to make call, but UserAgent hasn't connected yet. Delaying call");
 		userAgent.once('connected', function() {
 			console.log("UserAgent has now connected, retrying the call");
-			make_call(username, voiceBridge, server, callback, recall, isListenOnly);
+			make_call(username, voiceBridge, server, callback, recall);
 		});
 		return;
 	}
@@ -289,53 +269,16 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly
 
 	// Make an audio/video call:
 	console.log("Setting options.. ");
-
-	var options = {};
-	if (isListenOnly) {
-		// create necessary options for a listen only stream
-		var stream = null;
-		// handle the web browser
-		// create a stream object through the browser separated from user media
-		if (typeof webkitMediaStream !== 'undefined') {
-			// Google Chrome
-			stream = new webkitMediaStream;
-		} else {
-			// Firefox
-			audioContext = new window.AudioContext;
-			stream = audioContext.createMediaStreamDestination().stream;
-		}
-
-		options = {
-			media: {
-				stream: stream, // use the stream created above
-				render: {
-					remote: {
-						// select an element to render the incoming stream data
-						audio: document.getElementById('remote-media')
-					}
-				}
-			},
-			// a list of our RTC Connection constraints
-			RTCConstraints: {
-				// our constraints are mandatory. We must received audio and must not receive audio
-				mandatory: {
-					OfferToReceiveAudio: true,
-					OfferToReceiveVideo: false
-				}
-			}
-		};
-	} else {
-		options = {
-			media: {
-				stream: userMicMedia,
-				render: {
-					remote: {
-						audio: document.getElementById('remote-media')
-					}
+	var options = {
+		media: {
+			stream: userMicMedia,
+			render: {
+				remote: {
+					audio: document.getElementById('remote-media')
 				}
 			}
-		};
-	}
+		}
+	};
 	
 	callTimeout = setTimeout(function() {
 		console.log('Ten seconds without updates sending timeout code');
@@ -489,7 +432,3 @@ function webrtc_hangup(callback) {
 function isWebRTCAvailable() {
 	return SIP.WebRTC.isSupported();
 }
-
-function getCallStatus() {
-	return currentSession;
-}
diff --git a/bigbluebutton-client/resources/prod/lib/deployJava.js b/bigbluebutton-client/resources/prod/lib/deployJava.js
index 8cfb0afcc17cec02a76399ad7b9402745be9cde6..7d06cb5ca13b4a0b22cd28cbce230d4d5b8bd1b5 100755
--- a/bigbluebutton-client/resources/prod/lib/deployJava.js
+++ b/bigbluebutton-client/resources/prod/lib/deployJava.js
@@ -1,2 +1,2 @@
-/* Copy of the file found at http://www.java.com/js/deployJava.js - January 18, 2015 */
+/* Copy of the file found at http://www.java.com/js/deployJava.js - January 18, 2015 */
 var deployJava=function(){var l={core:["id","class","title","style"],i18n:["lang","dir"],events:["onclick","ondblclick","onmousedown","onmouseup","onmouseover","onmousemove","onmouseout","onkeypress","onkeydown","onkeyup"],applet:["codebase","code","name","archive","object","width","height","alt","align","hspace","vspace"],object:["classid","codebase","codetype","data","type","archive","declare","standby","height","width","usemap","name","tabindex","align","border","hspace","vspace"]};var b=l.object.concat(l.core,l.i18n,l.events);var m=l.applet.concat(l.core);function g(o){if(!d.debug){return}if(console.log){console.log(o)}else{alert(o)}}function k(p,o){if(p==null||p.length==0){return true}var r=p.charAt(p.length-1);if(r!="+"&&r!="*"&&(p.indexOf("_")!=-1&&r!="_")){p=p+"*";r="*"}p=p.substring(0,p.length-1);if(p.length>0){var q=p.charAt(p.length-1);if(q=="."||q=="_"){p=p.substring(0,p.length-1)}}if(r=="*"){return(o.indexOf(p)==0)}else{if(r=="+"){return p<=o}}return false}function e(){var o="//java.com/js/webstart.png";try{return document.location.protocol.indexOf("http")!=-1?o:"http:"+o}catch(p){return"http:"+o}}function n(p){var o="http://java.com/dt-redirect";if(p==null||p.length==0){return o}if(p.charAt(0)=="&"){p=p.substring(1,p.length)}return o+"?"+p}function j(q,p){var o=q.length;for(var r=0;r<o;r++){if(q[r]===p){return true}}return false}function c(o){return j(m,o.toLowerCase())}function i(o){return j(b,o.toLowerCase())}function a(o){if("MSIE"!=deployJava.browserName){return true}if(deployJava.compareVersionToPattern(deployJava.getPlugin().version,["10","0","0"],false,true)){return true}if(o==null){return false}return !k("1.6.0_33+",o)}var d={debug:null,version:"20120801",firefoxJavaVersion:null,myInterval:null,preInstallJREList:null,returnPage:null,brand:null,locale:null,installType:null,EAInstallEnabled:false,EarlyAccessURL:null,oldMimeType:"application/npruntime-scriptable-plugin;DeploymentToolkit",mimeType:"application/java-deployment-toolkit",launchButtonPNG:e(),browserName:null,browserName2:null,getJREs:function(){var t=new Array();if(this.isPluginInstalled()){var r=this.getPlugin();var o=r.jvms;for(var q=0;q<o.getLength();q++){t[q]=o.get(q).version}}else{var p=this.getBrowser();if(p=="MSIE"){if(this.testUsingActiveX("1.7.0")){t[0]="1.7.0"}else{if(this.testUsingActiveX("1.6.0")){t[0]="1.6.0"}else{if(this.testUsingActiveX("1.5.0")){t[0]="1.5.0"}else{if(this.testUsingActiveX("1.4.2")){t[0]="1.4.2"}else{if(this.testForMSVM()){t[0]="1.1"}}}}}}else{if(p=="Netscape Family"){this.getJPIVersionUsingMimeType();if(this.firefoxJavaVersion!=null){t[0]=this.firefoxJavaVersion}else{if(this.testUsingMimeTypes("1.7")){t[0]="1.7.0"}else{if(this.testUsingMimeTypes("1.6")){t[0]="1.6.0"}else{if(this.testUsingMimeTypes("1.5")){t[0]="1.5.0"}else{if(this.testUsingMimeTypes("1.4.2")){t[0]="1.4.2"}else{if(this.browserName2=="Safari"){if(this.testUsingPluginsArray("1.7.0")){t[0]="1.7.0"}else{if(this.testUsingPluginsArray("1.6")){t[0]="1.6.0"}else{if(this.testUsingPluginsArray("1.5")){t[0]="1.5.0"}else{if(this.testUsingPluginsArray("1.4.2")){t[0]="1.4.2"}}}}}}}}}}}}}if(this.debug){for(var q=0;q<t.length;++q){g("[getJREs()] We claim to have detected Java SE "+t[q])}}return t},installJRE:function(r,p){var o=false;if(this.isPluginInstalled()&&this.isAutoInstallEnabled(r)){var q=false;if(this.isCallbackSupported()){q=this.getPlugin().installJRE(r,p)}else{q=this.getPlugin().installJRE(r)}if(q){this.refresh();if(this.returnPage!=null){document.location=this.returnPage}}return q}else{return this.installLatestJRE()}},isAutoInstallEnabled:function(o){if(!this.isPluginInstalled()){return false}if(typeof o=="undefined"){o=null}return a(o)},isCallbackSupported:function(){return this.isPluginInstalled()&&this.compareVersionToPattern(this.getPlugin().version,["10","2","0"],false,true)},installLatestJRE:function(q){if(this.isPluginInstalled()&&this.isAutoInstallEnabled()){var r=false;if(this.isCallbackSupported()){r=this.getPlugin().installLatestJRE(q)}else{r=this.getPlugin().installLatestJRE()}if(r){this.refresh();if(this.returnPage!=null){document.location=this.returnPage}}return r}else{var p=this.getBrowser();var o=navigator.platform.toLowerCase();if((this.EAInstallEnabled=="true")&&(o.indexOf("win")!=-1)&&(this.EarlyAccessURL!=null)){this.preInstallJREList=this.getJREs();if(this.returnPage!=null){this.myInterval=setInterval("deployJava.poll()",3000)}location.href=this.EarlyAccessURL;return false}else{if(p=="MSIE"){return this.IEInstall()}else{if((p=="Netscape Family")&&(o.indexOf("win32")!=-1)){return this.FFInstall()}else{location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):""))}}return false}}},runApplet:function(p,u,r){if(r=="undefined"||r==null){r="1.1"}var t="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var o=r.match(t);if(this.returnPage==null){this.returnPage=document.location}if(o!=null){var q=this.getBrowser();if(q!="?"){if(this.versionCheck(r+"+")){this.writeAppletTag(p,u)}else{if(this.installJRE(r+"+")){this.refresh();location.href=document.location;this.writeAppletTag(p,u)}}}else{this.writeAppletTag(p,u)}}else{g("[runApplet()] Invalid minimumVersion argument to runApplet():"+r)}},writeAppletTag:function(r,w){var o="<"+"applet ";var q="";var t="<"+"/"+"applet"+">";var x=true;if(null==w||typeof w!="object"){w=new Object()}for(var p in r){if(!c(p)){w[p]=r[p]}else{o+=(" "+p+'="'+r[p]+'"');if(p=="code"){x=false}}}var v=false;for(var u in w){if(u=="codebase_lookup"){v=true}if(u=="object"||u=="java_object"||u=="java_code"){x=false}q+='<param name="'+u+'" value="'+w[u]+'"/>'}if(!v){q+='<param name="codebase_lookup" value="false"/>'}if(x){o+=(' code="dummy"')}o+=">";document.write(o+"\n"+q+"\n"+t)},versionCheck:function(p){var v=0;var x="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?(\\*|\\+)?$";var y=p.match(x);if(y!=null){var r=false;var u=false;var q=new Array();for(var t=1;t<y.length;++t){if((typeof y[t]=="string")&&(y[t]!="")){q[v]=y[t];v++}}if(q[q.length-1]=="+"){u=true;r=false;q.length--}else{if(q[q.length-1]=="*"){u=false;r=true;q.length--}else{if(q.length<4){u=false;r=true}}}var w=this.getJREs();for(var t=0;t<w.length;++t){if(this.compareVersionToPattern(w[t],q,r,u)){return true}}return false}else{var o="Invalid versionPattern passed to versionCheck: "+p;g("[versionCheck()] "+o);alert(o);return false}},isWebStartInstalled:function(r){var q=this.getBrowser();if(q=="?"){return true}if(r=="undefined"||r==null){r="1.4.2"}var p=false;var t="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var o=r.match(t);if(o!=null){p=this.versionCheck(r+"+")}else{g("[isWebStartInstaller()] Invalid minimumVersion argument to isWebStartInstalled(): "+r);p=this.versionCheck("1.4.2+")}return p},getJPIVersionUsingMimeType:function(){for(var p=0;p<navigator.mimeTypes.length;++p){var q=navigator.mimeTypes[p].type;var o=q.match(/^application\/x-java-applet;jpi-version=(.*)$/);if(o!=null){this.firefoxJavaVersion=o[1];if("Opera"!=this.browserName2){break}}}},launchWebStartApplication:function(r){var o=navigator.userAgent.toLowerCase();this.getJPIVersionUsingMimeType();if(this.isWebStartInstalled("1.7.0")==false){if((this.installJRE("1.7.0+")==false)||((this.isWebStartInstalled("1.7.0")==false))){return false}}var u=null;if(document.documentURI){u=document.documentURI}if(u==null){u=document.URL}var p=this.getBrowser();var q;if(p=="MSIE"){q="<"+'object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" '+'width="0" height="0">'+"<"+'PARAM name="launchjnlp" value="'+r+'"'+">"+"<"+'PARAM name="docbase" value="'+u+'"'+">"+"<"+"/"+"object"+">"}else{if(p=="Netscape Family"){q="<"+'embed type="application/x-java-applet;jpi-version='+this.firefoxJavaVersion+'" '+'width="0" height="0" '+'launchjnlp="'+r+'"'+'docbase="'+u+'"'+" />"}}if(document.body=="undefined"||document.body==null){document.write(q);document.location=u}else{var t=document.createElement("div");t.id="div1";t.style.position="relative";t.style.left="-10000px";t.style.margin="0px auto";t.className="dynamicDiv";t.innerHTML=q;document.body.appendChild(t)}},createWebStartLaunchButtonEx:function(q,p){if(this.returnPage==null){this.returnPage=q}var o="javascript:deployJava.launchWebStartApplication('"+q+"');";document.write("<"+'a href="'+o+"\" onMouseOver=\"window.status=''; "+'return true;"><'+"img "+'src="'+this.launchButtonPNG+'" '+'border="0" /><'+"/"+"a"+">")},createWebStartLaunchButton:function(q,p){if(this.returnPage==null){this.returnPage=q}var o="javascript:"+"if (!deployJava.isWebStartInstalled(&quot;"+p+"&quot;)) {"+"if (deployJava.installLatestJRE()) {"+"if (deployJava.launch(&quot;"+q+"&quot;)) {}"+"}"+"} else {"+"if (deployJava.launch(&quot;"+q+"&quot;)) {}"+"}";document.write("<"+'a href="'+o+"\" onMouseOver=\"window.status=''; "+'return true;"><'+"img "+'src="'+this.launchButtonPNG+'" '+'border="0" /><'+"/"+"a"+">")},launch:function(o){document.location=o;return true},isPluginInstalled:function(){var o=this.getPlugin();if(o&&o.jvms){return true}else{return false}},isAutoUpdateEnabled:function(){if(this.isPluginInstalled()){return this.getPlugin().isAutoUpdateEnabled()}return false},setAutoUpdateEnabled:function(){if(this.isPluginInstalled()){return this.getPlugin().setAutoUpdateEnabled()}return false},setInstallerType:function(o){this.installType=o;if(this.isPluginInstalled()){return this.getPlugin().setInstallerType(o)}return false},setAdditionalPackages:function(o){if(this.isPluginInstalled()){return this.getPlugin().setAdditionalPackages(o)}return false},setEarlyAccess:function(o){this.EAInstallEnabled=o},isPlugin2:function(){if(this.isPluginInstalled()){if(this.versionCheck("1.6.0_10+")){try{return this.getPlugin().isPlugin2()}catch(o){}}}return false},allowPlugin:function(){this.getBrowser();var o=("Safari"!=this.browserName2&&"Opera"!=this.browserName2);return o},getPlugin:function(){this.refresh();var o=null;if(this.allowPlugin()){o=document.getElementById("deployJavaPlugin")}return o},compareVersionToPattern:function(v,p,r,t){if(v==undefined||p==undefined){return false}var w="^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";var x=v.match(w);if(x!=null){var u=0;var y=new Array();for(var q=1;q<x.length;++q){if((typeof x[q]=="string")&&(x[q]!="")){y[u]=x[q];u++}}var o=Math.min(y.length,p.length);if(t){for(var q=0;q<o;++q){if(y[q]<p[q]){return false}else{if(y[q]>p[q]){return true}}}return true}else{for(var q=0;q<o;++q){if(y[q]!=p[q]){return false}}if(r){return true}else{return(y.length==p.length)}}}else{return false}},getBrowser:function(){if(this.browserName==null){var o=navigator.userAgent.toLowerCase();g("[getBrowser()] navigator.userAgent.toLowerCase() -> "+o);if((o.indexOf("msie")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="MSIE";this.browserName2="MSIE"}else{if(o.indexOf("trident")!=-1||o.indexOf("Trident")!=-1){this.browserName="MSIE";this.browserName2="MSIE"}else{if(o.indexOf("iphone")!=-1){this.browserName="Netscape Family";this.browserName2="iPhone"}else{if((o.indexOf("firefox")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="Netscape Family";this.browserName2="Firefox"}else{if(o.indexOf("chrome")!=-1){this.browserName="Netscape Family";this.browserName2="Chrome"}else{if(o.indexOf("safari")!=-1){this.browserName="Netscape Family";this.browserName2="Safari"}else{if((o.indexOf("mozilla")!=-1)&&(o.indexOf("opera")==-1)){this.browserName="Netscape Family";this.browserName2="Other"}else{if(o.indexOf("opera")!=-1){this.browserName="Netscape Family";this.browserName2="Opera"}else{this.browserName="?";this.browserName2="unknown"}}}}}}}}g("[getBrowser()] Detected browser name:"+this.browserName+", "+this.browserName2)}return this.browserName},testUsingActiveX:function(o){var q="JavaWebStart.isInstalled."+o+".0";if(typeof ActiveXObject=="undefined"||!ActiveXObject){g("[testUsingActiveX()] Browser claims to be IE, but no ActiveXObject object?");return false}try{return(new ActiveXObject(q)!=null)}catch(p){return false}},testForMSVM:function(){var p="{08B0E5C0-4FCB-11CF-AAA5-00401C608500}";if(typeof oClientCaps!="undefined"){var o=oClientCaps.getComponentVersion(p,"ComponentID");if((o=="")||(o=="5,0,5000,0")){return false}else{return true}}else{return false}},testUsingMimeTypes:function(p){if(!navigator.mimeTypes){g("[testUsingMimeTypes()] Browser claims to be Netscape family, but no mimeTypes[] array?");return false}for(var q=0;q<navigator.mimeTypes.length;++q){s=navigator.mimeTypes[q].type;var o=s.match(/^application\/x-java-applet\x3Bversion=(1\.8|1\.7|1\.6|1\.5|1\.4\.2)$/);if(o!=null){if(this.compareVersions(o[1],p)){return true}}}return false},testUsingPluginsArray:function(p){if((!navigator.plugins)||(!navigator.plugins.length)){return false}var o=navigator.platform.toLowerCase();for(var q=0;q<navigator.plugins.length;++q){s=navigator.plugins[q].description;if(s.search(/^Java Switchable Plug-in (Cocoa)/)!=-1){if(this.compareVersions("1.5.0",p)){return true}}else{if(s.search(/^Java/)!=-1){if(o.indexOf("win")!=-1){if(this.compareVersions("1.5.0",p)||this.compareVersions("1.6.0",p)){return true}}}}}if(this.compareVersions("1.5.0",p)){return true}return false},IEInstall:function(){location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):""));return false},done:function(p,o){},FFInstall:function(){location.href=n(((this.returnPage!=null)?("&returnPage="+this.returnPage):"")+((this.locale!=null)?("&locale="+this.locale):"")+((this.brand!=null)?("&brand="+this.brand):"")+((this.installType!=null)?("&type="+this.installType):""));return false},compareVersions:function(r,t){var p=r.split(".");var o=t.split(".");for(var q=0;q<p.length;++q){p[q]=Number(p[q])}for(var q=0;q<o.length;++q){o[q]=Number(o[q])}if(p.length==2){p[2]=0}if(p[0]>o[0]){return true}if(p[0]<o[0]){return false}if(p[1]>o[1]){return true}if(p[1]<o[1]){return false}if(p[2]>o[2]){return true}if(p[2]<o[2]){return false}return true},enableAlerts:function(){this.browserName=null;this.debug=true},poll:function(){this.refresh();var o=this.getJREs();if((this.preInstallJREList.length==0)&&(o.length!=0)){clearInterval(this.myInterval);if(this.returnPage!=null){location.href=this.returnPage}}if((this.preInstallJREList.length!=0)&&(o.length!=0)&&(this.preInstallJREList[0]!=o[0])){clearInterval(this.myInterval);if(this.returnPage!=null){location.href=this.returnPage}}},writePluginTag:function(){var o=this.getBrowser();if(o=="MSIE"){document.write("<"+'object classid="clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA" '+'id="deployJavaPlugin" width="0" height="0">'+"<"+"/"+"object"+">")}else{if(o=="Netscape Family"&&this.allowPlugin()){this.writeEmbedTag()}}},refresh:function(){navigator.plugins.refresh(false);var o=this.getBrowser();if(o=="Netscape Family"&&this.allowPlugin()){var p=document.getElementById("deployJavaPlugin");if(p==null){this.writeEmbedTag()}}},writeEmbedTag:function(){var o=false;if(navigator.mimeTypes!=null){for(var p=0;p<navigator.mimeTypes.length;p++){if(navigator.mimeTypes[p].type==this.mimeType){if(navigator.mimeTypes[p].enabledPlugin){document.write("<"+'embed id="deployJavaPlugin" type="'+this.mimeType+'" hidden="true" />');o=true}}}if(!o){for(var p=0;p<navigator.mimeTypes.length;p++){if(navigator.mimeTypes[p].type==this.oldMimeType){if(navigator.mimeTypes[p].enabledPlugin){document.write("<"+'embed id="deployJavaPlugin" type="'+this.oldMimeType+'" hidden="true" />')}}}}}}};d.writePluginTag();if(d.locale==null){var h=null;if(h==null){try{h=navigator.userLanguage}catch(f){}}if(h==null){try{h=navigator.systemLanguage}catch(f){}}if(h==null){try{h=navigator.language}catch(f){}}if(h!=null){h.replace("-","_");d.locale=h}}return d}();
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
index a682d081050d66db7b2cae10951bd2c63acf7900..2767503df12902a9b6b9d359e39964675e6904a5 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
@@ -1,198 +1,198 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.main.model.modules
-{
-  import com.asfusion.mate.events.Dispatcher; 
-  import flash.events.TimerEvent;
-  import flash.utils.Timer;  
-  import org.bigbluebutton.common.LogUtil;
-  import org.bigbluebutton.core.BBB;
-  import org.bigbluebutton.core.UsersUtil;
-  import org.bigbluebutton.core.vo.Config;
-  import org.bigbluebutton.core.vo.ConfigBuilder;
-  import org.bigbluebutton.main.api.JSLog;
-  import org.bigbluebutton.main.events.BBBEvent;
-  import org.bigbluebutton.main.events.ConfigEvent;
-  import org.bigbluebutton.main.events.ModuleLoadEvent;
-  import org.bigbluebutton.main.events.PortTestEvent;
-  import org.bigbluebutton.main.events.UserServicesEvent;
-  import org.bigbluebutton.main.model.ConfigParameters;
-  import org.bigbluebutton.main.model.modules.EnterApiService;
-  
-  public class ModulesDispatcher
-  {
-    private static const LOG:String = "Main::ModulesDispatcher - ";   
-    private var dispatcher:Dispatcher;
-    private var enterApiService: EnterApiService;
-    private var meetingInfo:Object = new Object();
-    private var enterApiUrl:String;
-    
-    public function ModulesDispatcher()
-    {
-      dispatcher = new Dispatcher();
-      
-    }
-    
-    public function sendLoadProgressEvent(moduleName:String, loadProgress:Number):void{
-      var loadEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_PROGRESS);
-      loadEvent.moduleName = moduleName;
-      loadEvent.progress = loadProgress;
-      dispatcher.dispatchEvent(loadEvent);
-    }
-    
-    public function sendModuleLoadReadyEvent(moduleName:String):void{
-      var loadReadyEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_READY);
-      loadReadyEvent.moduleName = moduleName;
-      dispatcher.dispatchEvent(loadReadyEvent);	
-    }
-    
-    public function sendAllModulesLoadedEvent():void{
-      dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.ALL_MODULES_LOADED));
-      
-      var loginEvent:BBBEvent = new BBBEvent(BBBEvent.LOGIN_EVENT);
-      dispatcher.dispatchEvent(loginEvent);	
-    }
-    
-    public function sendStartUserServicesEvent(application:String, host:String, isTunnelling:Boolean):void{
-      var e:UserServicesEvent = new UserServicesEvent(UserServicesEvent.START_USER_SERVICES);
-      e.applicationURI = application;
-      e.hostURI = host;
-      e.isTunnelling = isTunnelling;
-      dispatcher.dispatchEvent(e);
-    }
-    
-    public function sendPortTestEvent():void {     
-      getMeetingAndUserInfo();
-    }
-    
-    private function getMeetingAndUserInfo():void {
-      enterApiService = new EnterApiService();
-      enterApiService.addResultListener(resultListener);
-      enterApiService.load(enterApiUrl);
-    }
-      
-    private function resultListener(success:Boolean, result:Object):void {
-      if (success) {
-        trace(LOG + "Saving meeting and user info " + JSON.stringify(result)); 
-        
-        meetingInfo.username = result.username;
-        meetingInfo.userId = result.userId;
-        meetingInfo.meetingName = result.meetingName;
-        meetingInfo.meetingId = result.meetingId;
-        
-        doPortTesting();
-      } else {
-        var logData:Object = new Object();
-        JSLog.critical("Failed to get meeting and user info from Enter API", logData);
-        
-        dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
-      }
-    }
-    
-    private function doPortTesting():void {
-      trace(LOG + "Sending TEST_RTMP Event");
-      var e:PortTestEvent = new PortTestEvent(PortTestEvent.TEST_RTMP);
-      dispatcher.dispatchEvent(e);       
-    }
-    
-    private function timerHandler(e:TimerEvent):void{
-      trace(LOG + "Sending PORT_TEST_UPDATE Event");
-      var evt:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_UPDATE);
-      dispatcher.dispatchEvent(evt);
-    }
-    
-    public function sendTunnelingFailedEvent(server: String, app: String):void{
-      trace(LOG + "Sending TunnelingFailed Event");
-      var logData:Object = new Object();
-      logData.server = server;
-      logData.app = app;
-      logData.userId = meetingInfo.userId;
-      logData.username = meetingInfo.username;
-      logData.meetingName = meetingInfo.meetingName;
-      logData.meetingId = meetingInfo.meetingId;
-      trace(LOG + "Cannot connect to Red5 using RTMP and RTMPT", JSON.stringify(logData));
-      JSLog.critical("Cannot connect to Red5 using RTMP and RTMPT", logData);
-      
-      dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
-    }
-    
-    public function sendPortTestSuccessEvent(port:String, host:String, protocol:String, app:String):void{
-      trace(LOG + "Sending PORT_TEST_SUCCESS Event");
-      var logData:Object = new Object();
-      logData.port = port;
-      logData.server = host;
-      logData.protocol = protocol;
-      logData.app = app;      
-      logData.userId = meetingInfo.userId;
-      logData.username = meetingInfo.username;
-      logData.meetingName = meetingInfo.meetingName;
-      logData.meetingId = meetingInfo.meetingId;
-      JSLog.debug("Successfully connected on test connection.", logData);
-      
-      var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS);
-      portEvent.port = port;
-      portEvent.hostname = host;
-      portEvent.protocol = protocol;
-      portEvent.app = app;
-      dispatcher.dispatchEvent(portEvent);
-      
-    }
-    
-    public function sendPortTestFailedEvent(port:String, host:String, protocol:String, app:String):void{
-      trace(LOG + "Sending PORT_TEST_FAILED Event");
-      var portFailEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_FAILED);
-      portFailEvent.port = port;
-      portFailEvent.hostname = host;
-      portFailEvent.protocol = protocol;
-      portFailEvent.app = app;
-      dispatcher.dispatchEvent(portFailEvent);
-      
-    }
-    
-    public function sendModuleLoadingStartedEvent(modules:XMLList):void{
-      var event:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOADING_STARTED);
-      event.modules = modules;
-      dispatcher.dispatchEvent(event);
-    }
-    
-    public function sendConfigParameters(c:ConfigParameters):void{
-      enterApiUrl = c.host;
-      
-      var event:ConfigEvent = new ConfigEvent(ConfigEvent.CONFIG_EVENT);
-      var config:Config;
-      config = new ConfigBuilder(c.version, c.localeVersion)
-        .withApplication(c.application)
-        .withHelpUrl(c.helpURL)
-        .withHost(c.host)
-        .withLanguageEnabled(c.languageEnabled)
-        .withShortcutKeysShowButton(c.shortcutKeysShowButton)
-        .withNumModule(c.numModules)
-        .withPortTestApplication(c.portTestApplication)
-        .withPortTestHost(c.portTestHost)
-        .withShowDebug(c.showDebug)
-        .withSkinning(c.skinning)
-        .withCopyright(c.copyright)
-        .withLogo(c.logo)
-        .withBackground(c.background)
-        .build()
-      event.config = config;
-      dispatcher.dispatchEvent(event);
-    }
-  }
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ * 
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.bigbluebutton.main.model.modules
+{
+  import com.asfusion.mate.events.Dispatcher; 
+  import flash.events.TimerEvent;
+  import flash.utils.Timer;  
+  import org.bigbluebutton.common.LogUtil;
+  import org.bigbluebutton.core.BBB;
+  import org.bigbluebutton.core.UsersUtil;
+  import org.bigbluebutton.core.vo.Config;
+  import org.bigbluebutton.core.vo.ConfigBuilder;
+  import org.bigbluebutton.main.api.JSLog;
+  import org.bigbluebutton.main.events.BBBEvent;
+  import org.bigbluebutton.main.events.ConfigEvent;
+  import org.bigbluebutton.main.events.ModuleLoadEvent;
+  import org.bigbluebutton.main.events.PortTestEvent;
+  import org.bigbluebutton.main.events.UserServicesEvent;
+  import org.bigbluebutton.main.model.ConfigParameters;
+  import org.bigbluebutton.main.model.modules.EnterApiService;
+  
+  public class ModulesDispatcher
+  {
+    private static const LOG:String = "Main::ModulesDispatcher - ";   
+    private var dispatcher:Dispatcher;
+    private var enterApiService: EnterApiService;
+    private var meetingInfo:Object = new Object();
+    private var enterApiUrl:String;
+    
+    public function ModulesDispatcher()
+    {
+      dispatcher = new Dispatcher();
+      
+    }
+    
+    public function sendLoadProgressEvent(moduleName:String, loadProgress:Number):void{
+      var loadEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_PROGRESS);
+      loadEvent.moduleName = moduleName;
+      loadEvent.progress = loadProgress;
+      dispatcher.dispatchEvent(loadEvent);
+    }
+    
+    public function sendModuleLoadReadyEvent(moduleName:String):void{
+      var loadReadyEvent:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOAD_READY);
+      loadReadyEvent.moduleName = moduleName;
+      dispatcher.dispatchEvent(loadReadyEvent);	
+    }
+    
+    public function sendAllModulesLoadedEvent():void{
+      dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.ALL_MODULES_LOADED));
+      
+      var loginEvent:BBBEvent = new BBBEvent(BBBEvent.LOGIN_EVENT);
+      dispatcher.dispatchEvent(loginEvent);	
+    }
+    
+    public function sendStartUserServicesEvent(application:String, host:String, isTunnelling:Boolean):void{
+      var e:UserServicesEvent = new UserServicesEvent(UserServicesEvent.START_USER_SERVICES);
+      e.applicationURI = application;
+      e.hostURI = host;
+      e.isTunnelling = isTunnelling;
+      dispatcher.dispatchEvent(e);
+    }
+    
+    public function sendPortTestEvent():void {     
+      getMeetingAndUserInfo();
+    }
+    
+    private function getMeetingAndUserInfo():void {
+      enterApiService = new EnterApiService();
+      enterApiService.addResultListener(resultListener);
+      enterApiService.load(enterApiUrl);
+    }
+      
+    private function resultListener(success:Boolean, result:Object):void {
+      if (success) {
+        trace(LOG + "Saving meeting and user info " + JSON.stringify(result)); 
+        
+        meetingInfo.username = result.username;
+        meetingInfo.userId = result.userId;
+        meetingInfo.meetingName = result.meetingName;
+        meetingInfo.meetingId = result.meetingId;
+        
+        doPortTesting();
+      } else {
+        var logData:Object = new Object();
+        JSLog.critical("Failed to get meeting and user info from Enter API", logData);
+        
+        dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
+      }
+    }
+    
+    private function doPortTesting():void {
+      trace(LOG + "Sending TEST_RTMP Event");
+      var e:PortTestEvent = new PortTestEvent(PortTestEvent.TEST_RTMP);
+      dispatcher.dispatchEvent(e);       
+    }
+    
+    private function timerHandler(e:TimerEvent):void{
+      trace(LOG + "Sending PORT_TEST_UPDATE Event");
+      var evt:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_UPDATE);
+      dispatcher.dispatchEvent(evt);
+    }
+    
+    public function sendTunnelingFailedEvent(server: String, app: String):void{
+      trace(LOG + "Sending TunnelingFailed Event");
+      var logData:Object = new Object();
+      logData.server = server;
+      logData.app = app;
+      logData.userId = meetingInfo.userId;
+      logData.username = meetingInfo.username;
+      logData.meetingName = meetingInfo.meetingName;
+      logData.meetingId = meetingInfo.meetingId;
+      trace(LOG + "Cannot connect to Red5 using RTMP and RTMPT", JSON.stringify(logData));
+      JSLog.critical("Cannot connect to Red5 using RTMP and RTMPT", logData);
+      
+      dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
+    }
+    
+    public function sendPortTestSuccessEvent(port:String, host:String, protocol:String, app:String):void{
+      trace(LOG + "Sending PORT_TEST_SUCCESS Event");
+      var logData:Object = new Object();
+      logData.port = port;
+      logData.server = host;
+      logData.protocol = protocol;
+      logData.app = app;      
+      logData.userId = meetingInfo.userId;
+      logData.username = meetingInfo.username;
+      logData.meetingName = meetingInfo.meetingName;
+      logData.meetingId = meetingInfo.meetingId;
+      JSLog.debug("Successfully connected on test connection.", logData);
+      
+      var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS);
+      portEvent.port = port;
+      portEvent.hostname = host;
+      portEvent.protocol = protocol;
+      portEvent.app = app;
+      dispatcher.dispatchEvent(portEvent);
+      
+    }
+    
+    public function sendPortTestFailedEvent(port:String, host:String, protocol:String, app:String):void{
+      trace(LOG + "Sending PORT_TEST_FAILED Event");
+      var portFailEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_FAILED);
+      portFailEvent.port = port;
+      portFailEvent.hostname = host;
+      portFailEvent.protocol = protocol;
+      portFailEvent.app = app;
+      dispatcher.dispatchEvent(portFailEvent);
+      
+    }
+    
+    public function sendModuleLoadingStartedEvent(modules:XMLList):void{
+      var event:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOADING_STARTED);
+      event.modules = modules;
+      dispatcher.dispatchEvent(event);
+    }
+    
+    public function sendConfigParameters(c:ConfigParameters):void{
+      enterApiUrl = c.host;
+      
+      var event:ConfigEvent = new ConfigEvent(ConfigEvent.CONFIG_EVENT);
+      var config:Config;
+      config = new ConfigBuilder(c.version, c.localeVersion)
+        .withApplication(c.application)
+        .withHelpUrl(c.helpURL)
+        .withHost(c.host)
+        .withLanguageEnabled(c.languageEnabled)
+        .withShortcutKeysShowButton(c.shortcutKeysShowButton)
+        .withNumModule(c.numModules)
+        .withPortTestApplication(c.portTestApplication)
+        .withPortTestHost(c.portTestHost)
+        .withShowDebug(c.showDebug)
+        .withSkinning(c.skinning)
+        .withCopyright(c.copyright)
+        .withLogo(c.logo)
+        .withBackground(c.background)
+        .build()
+      event.config = config;
+      dispatcher.dispatchEvent(event);
+    }
+  }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
index 80cefc3ef989b4e47b26258fce789119ef14eb70..27b806cf04f6f6b87e4e39382103bfb2d9df9ea8 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
@@ -1,412 +1,412 @@
-/**
-* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-* 
-* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-*
-* This program is free software; you can redistribute it and/or modify it under the
-* terms of the GNU Lesser General Public License as published by the Free Software
-* Foundation; either version 3.0 of the License, or (at your option) any later
-* version.
-* 
-* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License along
-* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-*
-*/
-package org.bigbluebutton.main.model.users
-{
-	import com.adobe.protocols.dict.events.ErrorEvent;
-	import com.asfusion.mate.events.Dispatcher;
-	
-	import flash.events.*;
-	import flash.net.NetConnection;
-	import flash.net.Responder;
-	import flash.utils.Timer;
-	
-	import org.bigbluebutton.common.LogUtil;
-	import org.bigbluebutton.core.UsersUtil;
-	import org.bigbluebutton.core.services.BandwidthMonitor;
-	import org.bigbluebutton.main.api.JSLog;
-	import org.bigbluebutton.main.events.InvalidAuthTokenEvent;
-	import org.bigbluebutton.main.model.ConferenceParameters;
-	import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
-	import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
-		
-	public class NetConnectionDelegate
-	{
-		public static const LOG:String = "NetConnectionDelegate - ";
-		
-		private var _netConnection:NetConnection;	
-		private var connectionId:Number;
-		private var connected:Boolean = false;
-		
-		private var _userid:Number = -1;
-		private var _role:String = "unknown";
-		private var _applicationURI:String;
-		private var _conferenceParameters:ConferenceParameters;
-		
-		// These two are just placeholders. We'll get this from the server later and
-		// then pass to other modules.
-		private var _authToken:String = "AUTHORIZED";
-		private var _room:String;
-		private var tried_tunneling:Boolean = false;
-		private var logoutOnUserCommand:Boolean = false;
-		private var guestKickedOutCommand:Boolean = false;
-		private var backoff:Number = 2000;
-		
-		private var dispatcher:Dispatcher;    
-    private var _messageListeners:Array = new Array();
-    
-    private var authenticated: Boolean = false;
-    
-		public function NetConnectionDelegate():void
-		{
-			dispatcher = new Dispatcher();
-			
-			_netConnection = new NetConnection();				
-			_netConnection.proxyType = "best";
-			_netConnection.client = this;
-			_netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus );
-			_netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError );
-			_netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError );
-			_netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError );
-		}
-		
-    public function setUri(uri:String):void {
-      _applicationURI = uri;
-
-      var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/;
-      var result:Array = pattern.exec(uri);
-      BandwidthMonitor.getInstance().serverURL = result.server;
-    }
-       
-        
-		public function get connection():NetConnection {
-			return _netConnection;
-		}
-        
-    public function addMessageListener(listener:IMessageListener):void {
-      _messageListeners.push(listener);
-    }
-        
-    public function removeMessageListener(listener:IMessageListener):void {
-      for (var ob:int=0; ob<_messageListeners.length; ob++) {
-        if (_messageListeners[ob] == listener) {
-          _messageListeners.splice (ob,1);
-          break;
-        }
-      }
-    }
-        
-    private function notifyListeners(messageName:String, message:Object):void {
-      if (messageName != null && messageName != "") {
-        for (var notify:String in _messageListeners) {
-          _messageListeners[notify].onMessage(messageName, message);
-        }                
-      } else {
-        LogUtil.debug("Message name is undefined");
-      }
-    }   
-        
-    public function onMessageFromServer(messageName:String, msg:Object):void {
-      trace(LOG + "Got message from server [" + messageName + "]"); 
-      if (!authenticated && (messageName == "validateAuthTokenReply")) {
-        handleValidateAuthTokenReply(msg)
-      } else if (messageName == "validateAuthTokenTimedOut") {
-        handleValidateAuthTokenTimedOut(msg)
-      } else if (authenticated) {
-        notifyListeners(messageName, msg);
-      } else {
-        trace(LOG + "Ignoring message=[" + messageName + "] as our token hasn't been validated yet.");
-      }     
-    }
-		
-    private function validateToken():void {
-      var message:Object = new Object();
-      message["userId"] = _conferenceParameters.internalUserID;
-      message["authToken"] = _conferenceParameters.authToken;
-      
-      sendMessage(
-        "validateToken",// Remote function name
-        // result - On successful result
-        function(result:Object):void { 
-          trace(LOG + "validating token for [" + _conferenceParameters.internalUserID + "]"); 
-        },	
-        // status - On error occurred
-        function(status:Object):void { 
-          LogUtil.error("Error occurred:"); 
-          for (var x:Object in status) { 
-            LogUtil.error(x + " : " + status[x]); 
-          } 
-        },
-        message
-      ); //_netConnection.call      
-    }
-      
-    private function handleValidateAuthTokenTimedOut(msg: Object):void {
-      trace(LOG + "*** handleValidateAuthTokenTimedOut " + msg.msg + " **** \n");      
-      var map:Object = JSON.parse(msg.msg);  
-      var tokenValid: Boolean = map.valid as Boolean;
-      var userId: String = map.userId as String;
-
-      var logData:Object = new Object();
-      logData.user = UsersUtil.getUserData();
-      JSLog.critical("Validate auth token timed out.", logData);
-      
-      if (tokenValid) {
-        authenticated = true;
-        trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n");
-      } else {
-        trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n");
-        dispatcher.dispatchEvent(new InvalidAuthTokenEvent());
-      }
-    }
-    
-    private function handleValidateAuthTokenReply(msg: Object):void {
-      trace(LOG + "*** handleValidateAuthTokenReply " + msg.msg + " **** \n");      
-      var map:Object = JSON.parse(msg.msg);  
-      var tokenValid: Boolean = map.valid as Boolean;
-      var userId: String = map.userId as String;
-      
-      if (tokenValid) {
-        authenticated = true;
-        trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n");
-      } else {
-        trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n");
-        dispatcher.dispatchEvent(new InvalidAuthTokenEvent());
-      }
-    }
-    
-    private function sendConnectionSuccessEvent(userid:String):void{      
-      var e:UsersConnectionEvent = new UsersConnectionEvent(UsersConnectionEvent.CONNECTION_SUCCESS);
-      e.userid = userid;
-      dispatcher.dispatchEvent(e);
-      
-    }
-    
-		public function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object=null):void {
-      trace(LOG + "SENDING [" + service + "]");
-			var responder:Responder =	new Responder(                    
-					function(result:Object):void { // On successful result
-						onSuccess("Successfully sent [" + service + "]."); 
-					},	                   
-					function(status:Object):void { // status - On error occurred
-						var errorReason:String = "Failed to send [" + service + "]:\n"; 
-						for (var x:Object in status) { 
-							errorReason += "\t" + x + " : " + status[x]; 
-						} 
-					}
-				);
-			
-			if (message == null) {
-				_netConnection.call(service, responder);			
-			} else {
-				_netConnection.call(service, responder, message);
-			}
-		}
-		
-		/**
-		 * Connect to the server.
-		 * uri: The uri to the conference application.
-		 * username: Fullname of the participant.
-		 * role: MODERATOR/VIEWER
-		 * conference: The conference room
-		 * mode: LIVE/PLAYBACK - Live:when used to collaborate, Playback:when being used to playback a recorded conference.
-		 * room: Need the room number when playing back a recorded conference. When LIVE, the room is taken from the URI.
-		 */
-		public function connect(params:ConferenceParameters, tunnel:Boolean = false):void {	
-			_conferenceParameters = params;
-			
-			tried_tunneling = tunnel;	
-            
-			try {	
-				var uri:String = _applicationURI + "/" + _conferenceParameters.room;
-				
-				trace(LOG + "::Connecting to " + uri + " [" + _conferenceParameters.username + "," + _conferenceParameters.role + "," + 
-					_conferenceParameters.conference + "," + _conferenceParameters.record + "," + _conferenceParameters.room + ", " + _conferenceParameters.lockSettings.lockOnJoin + "]");	
-				_netConnection.connect(uri, _conferenceParameters.username, _conferenceParameters.role,
-											_conferenceParameters.room, _conferenceParameters.voicebridge, 
-											_conferenceParameters.record, _conferenceParameters.externUserID,
-											_conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, _conferenceParameters.lockSettings,
-											_conferenceParameters.guest);
-			} catch(e:ArgumentError) {
-				// Invalid parameters.
-				switch (e.errorID) {
-					case 2004 :						
-						LogUtil.debug("Error! Invalid server location: " + uri);											   
-						break;						
-					default :
-						LogUtil.debug("UNKNOWN Error! Invalid server location: " + uri);
-					   break;
-				}
-			}	
-		}
-			
-		public function disconnect(logoutOnUserCommand:Boolean):void {
-			this.logoutOnUserCommand = logoutOnUserCommand;
-			_netConnection.close();
-		}
-
-		public function guestDisconnect() : void
-		{
-			this.guestKickedOutCommand = true;
-			_netConnection.close();
-		}
-		
-    
-    public function forceClose():void {
-      _netConnection.close();
-    }
-    
-		protected function netStatus(event:NetStatusEvent):void {
-			handleResult( event );
-		}
-		
-    private var autoReconnectTimer:Timer = new Timer(1000, 1);
-    
-		public function handleResult(event:Object):void {
-			var info : Object = event.info;
-			var statusCode : String = info.code;
-
-      var logData:Object = new Object();
-      logData.user = UsersUtil.getUserData();
-      
-			switch (statusCode) {
-				case "NetConnection.Connect.Success":
-					trace(LOG + ":Connection to viewers application succeeded.");
-          JSLog.debug("Successfully connected to BBB App.", logData);
-          
-          validateToken();
-			
-					break;
-			
-				case "NetConnection.Connect.Failed":					
-					if (tried_tunneling) {
-            trace(LOG + ":Connection to viewers application failed...even when tunneling");
-						sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED);
-					} else {
-						disconnect(false);
-            trace(LOG + ":Connection to viewers application failed...try tunneling");
-						var rtmptRetryTimer:Timer = new Timer(1000, 1);
-            rtmptRetryTimer.addEventListener("timer", rtmptRetryTimerHandler);
-            rtmptRetryTimer.start();						
-					}									
-					break;
-					
-				case "NetConnection.Connect.Closed":	
-          trace(LOG + "Connection to viewers application closed");
-          sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_CLOSED);		
-											
-					break;
-					
-				case "NetConnection.Connect.InvalidApp":	
-          trace(LOG + ":viewers application not found on server");			
-					sendConnectionFailedEvent(ConnectionFailedEvent.INVALID_APP);				
-					break;
-					
-				case "NetConnection.Connect.AppShutDown":
-          trace(LOG + ":viewers application has been shutdown");
-					sendConnectionFailedEvent(ConnectionFailedEvent.APP_SHUTDOWN);	
-					break;
-					
-				case "NetConnection.Connect.Rejected":
-          trace(LOG + ":Connection to the server rejected. Uri: " + _applicationURI + ". Check if the red5 specified in the uri exists and is running" );
-					sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_REJECTED);		
-					break;
-				
-				case "NetConnection.Connect.NetworkChange":
-          JSLog.warn("Detected network change to BBB App", logData);
-          trace(LOG + "Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
-					break;
-					
-				default :
-          trace(LOG + ":Default status to the viewers application" );
-				   sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
-				   break;
-			}
-		}
-		
-    private function autoReconnectTimerHandler(event:TimerEvent):void {
-      trace(LOG + "autoReconnectTimerHandler: " + event);
-      connect(_conferenceParameters, tried_tunneling);
-    }
-        
-		private function rtmptRetryTimerHandler(event:TimerEvent):void {
-      trace(LOG + "rtmptRetryTimerHandler: " + event);
-      connect(_conferenceParameters, true);
-    }
-			
-		protected function netSecurityError(event: SecurityErrorEvent):void {
-      trace(LOG + "Security error - " + event.text);
-			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
-		}
-		
-		protected function netIOError(event: IOErrorEvent):void {
-      trace(LOG + "Input/output error - " + event.text);
-			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
-		}
-			
-		protected function netASyncError(event: AsyncErrorEvent):void  {
-      trace(LOG + "Asynchronous code error - " + event.toString() );
-      
-			LogUtil.debug("Asynchronous code error - " + event.toString() );
-			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
-		}	
-			
-		private function sendConnectionFailedEvent(reason:String):void{
-      var logData:Object = new Object();
-      
-			if (this.guestKickedOutCommand) {
-				logData.reason = "Guest kicked out";
-				logData.user = UsersUtil.getUserData();
-				JSLog.warn("User disconnected from BBB App.", logData);
-				sendGuestUserKickedOutEvent();
-			} else if (this.logoutOnUserCommand) {
-        logData.reason = "User requested.";
-        logData.user = UsersUtil.getUserData();
-        JSLog.debug("User logged out from BBB App.", logData);
-				sendUserLoggedOutEvent();
-			} else {
-        logData.reason = reason;
-        logData.user = UsersUtil.getUserData();
-        JSLog.warn("User disconnected from BBB App.", logData);
-        var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason);
-        dispatcher.dispatchEvent(e);        
-      }
-		}
-		
-		private function sendUserLoggedOutEvent():void{
-			var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.USER_LOGGED_OUT);
-			dispatcher.dispatchEvent(e);
-		}
-
-		private function sendGuestUserKickedOutEvent():void {
-			var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.MODERATOR_DENIED_ME);
-			dispatcher.dispatchEvent(e);
-		}
-		
-		private function attemptReconnect(backoff:Number):void{
-			var retryTimer:Timer = new Timer(backoff, 1);
-			retryTimer.addEventListener(TimerEvent.TIMER, function():void{
-				connect(_conferenceParameters, tried_tunneling);
-			});
-			retryTimer.start();
-			if (this.backoff < 16000) this.backoff = backoff *2;
-		}
-		
-		public function onBWCheck(... rest):Number { 
-			return 0; 
-		} 
-    
-		public function onBWDone(... rest):void { 
-			var p_bw:Number; 
-			if (rest.length > 0) p_bw = rest[0]; 
-			// your application should do something here 
-			// when the bandwidth check is complete 
-			trace("bandwidth = " + p_bw + " Kbps."); 
-		}
-	}
-}
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+* 
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+* 
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.model.users
+{
+	import com.adobe.protocols.dict.events.ErrorEvent;
+	import com.asfusion.mate.events.Dispatcher;
+	
+	import flash.events.*;
+	import flash.net.NetConnection;
+	import flash.net.Responder;
+	import flash.utils.Timer;
+	
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.UsersUtil;
+	import org.bigbluebutton.core.services.BandwidthMonitor;
+	import org.bigbluebutton.main.api.JSLog;
+	import org.bigbluebutton.main.events.InvalidAuthTokenEvent;
+	import org.bigbluebutton.main.model.ConferenceParameters;
+	import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
+	import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
+		
+	public class NetConnectionDelegate
+	{
+		public static const LOG:String = "NetConnectionDelegate - ";
+		
+		private var _netConnection:NetConnection;	
+		private var connectionId:Number;
+		private var connected:Boolean = false;
+		
+		private var _userid:Number = -1;
+		private var _role:String = "unknown";
+		private var _applicationURI:String;
+		private var _conferenceParameters:ConferenceParameters;
+		
+		// These two are just placeholders. We'll get this from the server later and
+		// then pass to other modules.
+		private var _authToken:String = "AUTHORIZED";
+		private var _room:String;
+		private var tried_tunneling:Boolean = false;
+		private var logoutOnUserCommand:Boolean = false;
+		private var guestKickedOutCommand:Boolean = false;
+		private var backoff:Number = 2000;
+		
+		private var dispatcher:Dispatcher;    
+    private var _messageListeners:Array = new Array();
+    
+    private var authenticated: Boolean = false;
+    
+		public function NetConnectionDelegate():void
+		{
+			dispatcher = new Dispatcher();
+			
+			_netConnection = new NetConnection();				
+			_netConnection.proxyType = "best";
+			_netConnection.client = this;
+			_netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus );
+			_netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, netASyncError );
+			_netConnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, netSecurityError );
+			_netConnection.addEventListener( IOErrorEvent.IO_ERROR, netIOError );
+		}
+		
+    public function setUri(uri:String):void {
+      _applicationURI = uri;
+
+      var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/;
+      var result:Array = pattern.exec(uri);
+      BandwidthMonitor.getInstance().serverURL = result.server;
+    }
+       
+        
+		public function get connection():NetConnection {
+			return _netConnection;
+		}
+        
+    public function addMessageListener(listener:IMessageListener):void {
+      _messageListeners.push(listener);
+    }
+        
+    public function removeMessageListener(listener:IMessageListener):void {
+      for (var ob:int=0; ob<_messageListeners.length; ob++) {
+        if (_messageListeners[ob] == listener) {
+          _messageListeners.splice (ob,1);
+          break;
+        }
+      }
+    }
+        
+    private function notifyListeners(messageName:String, message:Object):void {
+      if (messageName != null && messageName != "") {
+        for (var notify:String in _messageListeners) {
+          _messageListeners[notify].onMessage(messageName, message);
+        }                
+      } else {
+        LogUtil.debug("Message name is undefined");
+      }
+    }   
+        
+    public function onMessageFromServer(messageName:String, msg:Object):void {
+      trace(LOG + "Got message from server [" + messageName + "]"); 
+      if (!authenticated && (messageName == "validateAuthTokenReply")) {
+        handleValidateAuthTokenReply(msg)
+      } else if (messageName == "validateAuthTokenTimedOut") {
+        handleValidateAuthTokenTimedOut(msg)
+      } else if (authenticated) {
+        notifyListeners(messageName, msg);
+      } else {
+        trace(LOG + "Ignoring message=[" + messageName + "] as our token hasn't been validated yet.");
+      }     
+    }
+		
+    private function validateToken():void {
+      var message:Object = new Object();
+      message["userId"] = _conferenceParameters.internalUserID;
+      message["authToken"] = _conferenceParameters.authToken;
+      
+      sendMessage(
+        "validateToken",// Remote function name
+        // result - On successful result
+        function(result:Object):void { 
+          trace(LOG + "validating token for [" + _conferenceParameters.internalUserID + "]"); 
+        },	
+        // status - On error occurred
+        function(status:Object):void { 
+          LogUtil.error("Error occurred:"); 
+          for (var x:Object in status) { 
+            LogUtil.error(x + " : " + status[x]); 
+          } 
+        },
+        message
+      ); //_netConnection.call      
+    }
+      
+    private function handleValidateAuthTokenTimedOut(msg: Object):void {
+      trace(LOG + "*** handleValidateAuthTokenTimedOut " + msg.msg + " **** \n");      
+      var map:Object = JSON.parse(msg.msg);  
+      var tokenValid: Boolean = map.valid as Boolean;
+      var userId: String = map.userId as String;
+
+      var logData:Object = new Object();
+      logData.user = UsersUtil.getUserData();
+      JSLog.critical("Validate auth token timed out.", logData);
+      
+      if (tokenValid) {
+        authenticated = true;
+        trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n");
+      } else {
+        trace(LOG + "*** handleValidateAuthTokenTimedOut. valid=[ " + tokenValid + "] **** \n");
+        dispatcher.dispatchEvent(new InvalidAuthTokenEvent());
+      }
+    }
+    
+    private function handleValidateAuthTokenReply(msg: Object):void {
+      trace(LOG + "*** handleValidateAuthTokenReply " + msg.msg + " **** \n");      
+      var map:Object = JSON.parse(msg.msg);  
+      var tokenValid: Boolean = map.valid as Boolean;
+      var userId: String = map.userId as String;
+      
+      if (tokenValid) {
+        authenticated = true;
+        trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n");
+      } else {
+        trace(LOG + "*** handleValidateAuthTokenReply. valid=[ " + tokenValid + "] **** \n");
+        dispatcher.dispatchEvent(new InvalidAuthTokenEvent());
+      }
+    }
+    
+    private function sendConnectionSuccessEvent(userid:String):void{      
+      var e:UsersConnectionEvent = new UsersConnectionEvent(UsersConnectionEvent.CONNECTION_SUCCESS);
+      e.userid = userid;
+      dispatcher.dispatchEvent(e);
+      
+    }
+    
+		public function sendMessage(service:String, onSuccess:Function, onFailure:Function, message:Object=null):void {
+      trace(LOG + "SENDING [" + service + "]");
+			var responder:Responder =	new Responder(                    
+					function(result:Object):void { // On successful result
+						onSuccess("Successfully sent [" + service + "]."); 
+					},	                   
+					function(status:Object):void { // status - On error occurred
+						var errorReason:String = "Failed to send [" + service + "]:\n"; 
+						for (var x:Object in status) { 
+							errorReason += "\t" + x + " : " + status[x]; 
+						} 
+					}
+				);
+			
+			if (message == null) {
+				_netConnection.call(service, responder);			
+			} else {
+				_netConnection.call(service, responder, message);
+			}
+		}
+		
+		/**
+		 * Connect to the server.
+		 * uri: The uri to the conference application.
+		 * username: Fullname of the participant.
+		 * role: MODERATOR/VIEWER
+		 * conference: The conference room
+		 * mode: LIVE/PLAYBACK - Live:when used to collaborate, Playback:when being used to playback a recorded conference.
+		 * room: Need the room number when playing back a recorded conference. When LIVE, the room is taken from the URI.
+		 */
+		public function connect(params:ConferenceParameters, tunnel:Boolean = false):void {	
+			_conferenceParameters = params;
+			
+			tried_tunneling = tunnel;	
+            
+			try {	
+				var uri:String = _applicationURI + "/" + _conferenceParameters.room;
+				
+				trace(LOG + "::Connecting to " + uri + " [" + _conferenceParameters.username + "," + _conferenceParameters.role + "," + 
+					_conferenceParameters.conference + "," + _conferenceParameters.record + "," + _conferenceParameters.room + ", " + _conferenceParameters.lockSettings.lockOnJoin + "]");	
+				_netConnection.connect(uri, _conferenceParameters.username, _conferenceParameters.role,
+											_conferenceParameters.room, _conferenceParameters.voicebridge, 
+											_conferenceParameters.record, _conferenceParameters.externUserID,
+											_conferenceParameters.internalUserID, _conferenceParameters.muteOnStart, _conferenceParameters.lockSettings,
+											_conferenceParameters.guest);
+			} catch(e:ArgumentError) {
+				// Invalid parameters.
+				switch (e.errorID) {
+					case 2004 :						
+						LogUtil.debug("Error! Invalid server location: " + uri);											   
+						break;						
+					default :
+						LogUtil.debug("UNKNOWN Error! Invalid server location: " + uri);
+					   break;
+				}
+			}	
+		}
+			
+		public function disconnect(logoutOnUserCommand:Boolean):void {
+			this.logoutOnUserCommand = logoutOnUserCommand;
+			_netConnection.close();
+		}
+
+		public function guestDisconnect() : void
+		{
+			this.guestKickedOutCommand = true;
+			_netConnection.close();
+		}
+		
+    
+    public function forceClose():void {
+      _netConnection.close();
+    }
+    
+		protected function netStatus(event:NetStatusEvent):void {
+			handleResult( event );
+		}
+		
+    private var autoReconnectTimer:Timer = new Timer(1000, 1);
+    
+		public function handleResult(event:Object):void {
+			var info : Object = event.info;
+			var statusCode : String = info.code;
+
+      var logData:Object = new Object();
+      logData.user = UsersUtil.getUserData();
+      
+			switch (statusCode) {
+				case "NetConnection.Connect.Success":
+					trace(LOG + ":Connection to viewers application succeeded.");
+          JSLog.debug("Successfully connected to BBB App.", logData);
+          
+          validateToken();
+			
+					break;
+			
+				case "NetConnection.Connect.Failed":					
+					if (tried_tunneling) {
+            trace(LOG + ":Connection to viewers application failed...even when tunneling");
+						sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_FAILED);
+					} else {
+						disconnect(false);
+            trace(LOG + ":Connection to viewers application failed...try tunneling");
+						var rtmptRetryTimer:Timer = new Timer(1000, 1);
+            rtmptRetryTimer.addEventListener("timer", rtmptRetryTimerHandler);
+            rtmptRetryTimer.start();						
+					}									
+					break;
+					
+				case "NetConnection.Connect.Closed":	
+          trace(LOG + "Connection to viewers application closed");
+          sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_CLOSED);		
+											
+					break;
+					
+				case "NetConnection.Connect.InvalidApp":	
+          trace(LOG + ":viewers application not found on server");			
+					sendConnectionFailedEvent(ConnectionFailedEvent.INVALID_APP);				
+					break;
+					
+				case "NetConnection.Connect.AppShutDown":
+          trace(LOG + ":viewers application has been shutdown");
+					sendConnectionFailedEvent(ConnectionFailedEvent.APP_SHUTDOWN);	
+					break;
+					
+				case "NetConnection.Connect.Rejected":
+          trace(LOG + ":Connection to the server rejected. Uri: " + _applicationURI + ". Check if the red5 specified in the uri exists and is running" );
+					sendConnectionFailedEvent(ConnectionFailedEvent.CONNECTION_REJECTED);		
+					break;
+				
+				case "NetConnection.Connect.NetworkChange":
+          JSLog.warn("Detected network change to BBB App", logData);
+          trace(LOG + "Detected network change. User might be on a wireless and temporarily dropped connection. Doing nothing. Just making a note.");
+					break;
+					
+				default :
+          trace(LOG + ":Default status to the viewers application" );
+				   sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
+				   break;
+			}
+		}
+		
+    private function autoReconnectTimerHandler(event:TimerEvent):void {
+      trace(LOG + "autoReconnectTimerHandler: " + event);
+      connect(_conferenceParameters, tried_tunneling);
+    }
+        
+		private function rtmptRetryTimerHandler(event:TimerEvent):void {
+      trace(LOG + "rtmptRetryTimerHandler: " + event);
+      connect(_conferenceParameters, true);
+    }
+			
+		protected function netSecurityError(event: SecurityErrorEvent):void {
+      trace(LOG + "Security error - " + event.text);
+			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
+		}
+		
+		protected function netIOError(event: IOErrorEvent):void {
+      trace(LOG + "Input/output error - " + event.text);
+			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
+		}
+			
+		protected function netASyncError(event: AsyncErrorEvent):void  {
+      trace(LOG + "Asynchronous code error - " + event.toString() );
+      
+			LogUtil.debug("Asynchronous code error - " + event.toString() );
+			sendConnectionFailedEvent(ConnectionFailedEvent.UNKNOWN_REASON);
+		}	
+			
+		private function sendConnectionFailedEvent(reason:String):void{
+      var logData:Object = new Object();
+      
+			if (this.guestKickedOutCommand) {
+				logData.reason = "Guest kicked out";
+				logData.user = UsersUtil.getUserData();
+				JSLog.warn("User disconnected from BBB App.", logData);
+				sendGuestUserKickedOutEvent();
+			} else if (this.logoutOnUserCommand) {
+        logData.reason = "User requested.";
+        logData.user = UsersUtil.getUserData();
+        JSLog.debug("User logged out from BBB App.", logData);
+				sendUserLoggedOutEvent();
+			} else {
+        logData.reason = reason;
+        logData.user = UsersUtil.getUserData();
+        JSLog.warn("User disconnected from BBB App.", logData);
+        var e:ConnectionFailedEvent = new ConnectionFailedEvent(reason);
+        dispatcher.dispatchEvent(e);        
+      }
+		}
+		
+		private function sendUserLoggedOutEvent():void{
+			var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.USER_LOGGED_OUT);
+			dispatcher.dispatchEvent(e);
+		}
+
+		private function sendGuestUserKickedOutEvent():void {
+			var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.MODERATOR_DENIED_ME);
+			dispatcher.dispatchEvent(e);
+		}
+		
+		private function attemptReconnect(backoff:Number):void{
+			var retryTimer:Timer = new Timer(backoff, 1);
+			retryTimer.addEventListener(TimerEvent.TIMER, function():void{
+				connect(_conferenceParameters, tried_tunneling);
+			});
+			retryTimer.start();
+			if (this.backoff < 16000) this.backoff = backoff *2;
+		}
+		
+		public function onBWCheck(... rest):Number { 
+			return 0; 
+		} 
+    
+		public function onBWDone(... rest):void { 
+			var p_bw:Number; 
+			if (rest.length > 0) p_bw = rest[0]; 
+			// your application should do something here 
+			// when the bandwidth check is complete 
+			trace("bandwidth = " + p_bw + " Kbps."); 
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
index 2c4aa7cbc90a0908d1006d0b349a10256c4cfd77..698863eca218604bd6526020f8a89f49309158ce 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
@@ -160,7 +160,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<mx:HBox width="100%" horizontalAlign="right" horizontalGap="18" paddingTop="20">
 			<mx:Button id="saveBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.save')}" 
 					   click="onSaveClicked()" tabIndex="{baseIndex+8}"
-					   toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.tooltip')}"/>
+					   toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.toolTip')}"/>
 			
 			<mx:Button id="cancelBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.cancel')}" 
 					   click="onCancelClicked()" tabIndex="{baseIndex+9}"
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
index 4fec5fa0264c62da36642644adf7d8bb4c1450f6..c4f7100c6df3d68875381c722c18b629ee1809af 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
@@ -1,109 +1,109 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-
-BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-
-This program is free software; you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free Software
-Foundation; either version 3.0 of the License, or (at your option) any later
-version.
-
-BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-
--->
-
-<EventMap xmlns="http://mate.asfusion.com/"
-	xmlns:mx="http://www.adobe.com/2006/mxml">
-	<mx:Script>
-		<![CDATA[
-      import com.asfusion.mate.events.Dispatcher;     
-      import mx.events.FlexEvent;     
-      import org.bigbluebutton.common.events.OpenWindowEvent;
-      import org.bigbluebutton.core.EventConstants;
-      import org.bigbluebutton.main.events.ModuleStartedEvent;
-      import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
-      import org.bigbluebutton.modules.chat.events.ChatEvent;
-      import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
-      import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
-      import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
-      import org.bigbluebutton.modules.chat.events.StartChatModuleEvent;
-      import org.bigbluebutton.modules.chat.events.StopChatModuleEvent;
-      import org.bigbluebutton.modules.chat.events.TranscriptEvent;
-      import org.bigbluebutton.modules.chat.services.ChatMessageService;
-      import org.bigbluebutton.modules.chat.services.MessageReceiver;
-      import org.bigbluebutton.modules.chat.services.MessageSender;
-      import org.bigbluebutton.modules.chat.services.ChatCopy;
-      import org.bigbluebutton.modules.chat.services.ChatSaver;
-      import org.bigbluebutton.modules.chat.views.ChatView;
-      import org.bigbluebutton.modules.chat.views.ChatWindow;
-		]]>
-	</mx:Script>
-	
-	<EventHandlers type="{FlexEvent.PREINITIALIZE}">
-		<ObjectBuilder generator="{ChatEventMapDelegate}" constructorArguments="{scope.dispatcher}"/>
-	</EventHandlers>
-	
-	<EventHandlers type="{StartChatModuleEvent.START_CHAT_MODULE_EVENT}">
-		<MethodInvoker generator="{ChatEventMapDelegate}" method="openChatWindow" />
-    <ObjectBuilder generator="{ChatMessageService}"/>
-  </EventHandlers>
-    
-  <EventHandlers type="{StopChatModuleEvent.STOP_CHAT_MODULE_EVENT}">        
-   		<MethodInvoker generator="{ChatEventMapDelegate}" method="closeChatWindow" />
-  </EventHandlers>
-
-  <EventHandlers type="{EventConstants.SEND_PUBLIC_CHAT_REQ}">        
-    <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessageFromApi" arguments="{event.message}"/>		
-  </EventHandlers>
-  
-  <EventHandlers type="{EventConstants.SEND_PRIVATE_CHAT_REQ}">        
-    <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessageFromApi" arguments="{event.message}"/>		
-  </EventHandlers>
-  
-    <EventHandlers type="{SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT}">        
- 		<MethodInvoker generator="{ChatMessageService}" method="sendPublicMessage" arguments="{event.chatMessage}"/>		
-    </EventHandlers>
-    
-    <EventHandlers type="{SendPrivateChatMessageEvent.SEND_PRIVATE_CHAT_MESSAGE_EVENT}">        
- 		<MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessage" arguments="{event.chatMessage}"/>		
-    </EventHandlers>
-    		
-	<EventHandlers type="{TranscriptEvent.LOAD_TRANSCRIPT}" >
-    <MethodInvoker generator="{ChatMessageService}" method="getPublicChatMessages"/>
-	</EventHandlers>    
-  
-  <EventHandlers type="{TranscriptEvent.TRANSCRIPT_EVENT}" >
-    <MethodInvoker generator="{ChatMessageService}" method="sendWelcomeMessage"/>
-  </EventHandlers>      
-  
-  <EventHandlers type="{ChatSaveEvent.SAVE_CHAT_EVENT}">
-    <MethodInvoker generator="{ChatSaver}" method="saveChatToFile" arguments="{event}"/>
-  </EventHandlers>
-
-  <EventHandlers type="{ChatCopyEvent.COPY_CHAT_EVENT}">
-    <MethodInvoker generator="{ChatCopy}" method="copyAllText" arguments="{event}"/>
-  </EventHandlers>
-
-  <Injectors target="{ChatMessageService}">
-    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
-    <PropertyInjector targetKey="receiver" source="{MessageReceiver}"/>
-    <PropertyInjector targetKey="sender" source="{MessageSender}"/>
-  </Injectors>
-
-  <Injectors target="{MessageReceiver}">
-    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
-  </Injectors>
- 
-  <Injectors target="{MessageSender}">
-    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
-  </Injectors>
-  
-</EventMap>
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<EventMap xmlns="http://mate.asfusion.com/"
+	xmlns:mx="http://www.adobe.com/2006/mxml">
+	<mx:Script>
+		<![CDATA[
+      import com.asfusion.mate.events.Dispatcher;     
+      import mx.events.FlexEvent;     
+      import org.bigbluebutton.common.events.OpenWindowEvent;
+      import org.bigbluebutton.core.EventConstants;
+      import org.bigbluebutton.main.events.ModuleStartedEvent;
+      import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
+      import org.bigbluebutton.modules.chat.events.ChatEvent;
+      import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
+      import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
+      import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
+      import org.bigbluebutton.modules.chat.events.StartChatModuleEvent;
+      import org.bigbluebutton.modules.chat.events.StopChatModuleEvent;
+      import org.bigbluebutton.modules.chat.events.TranscriptEvent;
+      import org.bigbluebutton.modules.chat.services.ChatMessageService;
+      import org.bigbluebutton.modules.chat.services.MessageReceiver;
+      import org.bigbluebutton.modules.chat.services.MessageSender;
+      import org.bigbluebutton.modules.chat.services.ChatCopy;
+      import org.bigbluebutton.modules.chat.services.ChatSaver;
+      import org.bigbluebutton.modules.chat.views.ChatView;
+      import org.bigbluebutton.modules.chat.views.ChatWindow;
+		]]>
+	</mx:Script>
+	
+	<EventHandlers type="{FlexEvent.PREINITIALIZE}">
+		<ObjectBuilder generator="{ChatEventMapDelegate}" constructorArguments="{scope.dispatcher}"/>
+	</EventHandlers>
+	
+	<EventHandlers type="{StartChatModuleEvent.START_CHAT_MODULE_EVENT}">
+		<MethodInvoker generator="{ChatEventMapDelegate}" method="openChatWindow" />
+    <ObjectBuilder generator="{ChatMessageService}"/>
+  </EventHandlers>
+    
+  <EventHandlers type="{StopChatModuleEvent.STOP_CHAT_MODULE_EVENT}">        
+   		<MethodInvoker generator="{ChatEventMapDelegate}" method="closeChatWindow" />
+  </EventHandlers>
+
+  <EventHandlers type="{EventConstants.SEND_PUBLIC_CHAT_REQ}">        
+    <MethodInvoker generator="{ChatMessageService}" method="sendPublicMessageFromApi" arguments="{event.message}"/>		
+  </EventHandlers>
+  
+  <EventHandlers type="{EventConstants.SEND_PRIVATE_CHAT_REQ}">        
+    <MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessageFromApi" arguments="{event.message}"/>		
+  </EventHandlers>
+  
+    <EventHandlers type="{SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT}">        
+ 		<MethodInvoker generator="{ChatMessageService}" method="sendPublicMessage" arguments="{event.chatMessage}"/>		
+    </EventHandlers>
+    
+    <EventHandlers type="{SendPrivateChatMessageEvent.SEND_PRIVATE_CHAT_MESSAGE_EVENT}">        
+ 		<MethodInvoker generator="{ChatMessageService}" method="sendPrivateMessage" arguments="{event.chatMessage}"/>		
+    </EventHandlers>
+    		
+	<EventHandlers type="{TranscriptEvent.LOAD_TRANSCRIPT}" >
+    <MethodInvoker generator="{ChatMessageService}" method="getPublicChatMessages"/>
+	</EventHandlers>    
+  
+  <EventHandlers type="{TranscriptEvent.TRANSCRIPT_EVENT}" >
+    <MethodInvoker generator="{ChatMessageService}" method="sendWelcomeMessage"/>
+  </EventHandlers>      
+  
+  <EventHandlers type="{ChatSaveEvent.SAVE_CHAT_EVENT}">
+    <MethodInvoker generator="{ChatSaver}" method="saveChatToFile" arguments="{event}"/>
+  </EventHandlers>
+
+  <EventHandlers type="{ChatCopyEvent.COPY_CHAT_EVENT}">
+    <MethodInvoker generator="{ChatCopy}" method="copyAllText" arguments="{event}"/>
+  </EventHandlers>
+
+  <Injectors target="{ChatMessageService}">
+    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
+    <PropertyInjector targetKey="receiver" source="{MessageReceiver}"/>
+    <PropertyInjector targetKey="sender" source="{MessageSender}"/>
+  </Injectors>
+
+  <Injectors target="{MessageReceiver}">
+    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
+  </Injectors>
+ 
+  <Injectors target="{MessageSender}">
+    <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
+  </Injectors>
+  
+</EventMap>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
index 21353a36eba7c081470da3b560dc845d5c8a8d70..cf3d4f34d527e2a993f0cdd95326b5e8d7a645a4 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
@@ -27,7 +27,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   
   <mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
   <mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
-
+  
     <mx:Script>
         <![CDATA[
           import com.asfusion.mate.events.Dispatcher;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
index 87bc8ec6a5c2c8c638241b888ae564dfea6aca6b..db0c33329623cbb8c6acef399c0d534f0be41391 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
@@ -27,7 +27,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     xmlns:flexlib="http://code.google.com/p/flexlib/"
     width="100%" height="100%" xmlns:containers="flexlib.containers.*"
     verticalScrollPolicy="off">
-
+
   <mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
   <mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
   <mate:Listener type="{EventConstants.START_PRIVATE_CHAT}" method="handleStartPrivateChatMessageEvent"/>
@@ -90,7 +90,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
 		  private static const PUBLIC_TAB_NEW:String = ResourceUtil.getInstance().getString("bbb.accessibility.chat.chatView.publicTabNew");
 		  private var publicWaiting:Boolean = false;
-		  private var publicFocus:Boolean = false;
+		  private var publicFocus:Boolean = false;
 		  private var noticeLabel:String; 
 			
 		  [Embed(source="../sounds/notice.mp3")] 
@@ -98,7 +98,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		  private var noticeSound:Sound = new noticeSoundClass() as Sound;
 		  // All author and license information for the use of this sound can be found in:
 		  // src/org/bigbluebutton/modules/chat/sounds/license.txt
-
+
 			// Initialization
 			private function init():void {
 				chatOptions = new ChatOptions();
@@ -107,7 +107,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				baseIndex = chatOptions.getBaseIndex() + 4;
 			}
 			
-
+
       private function onCreationComplete():void{				
 				openChatBoxFor(PUBLIC_CHAT_USERID, true);
 		    makePublicChatUncloseable();
@@ -341,7 +341,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			
 			// Activates an audio alert for screen-reader users on public message reception
-			private function publicNotification():void {
+			private function publicNotification():void {
 				publicWaiting = true;
 				if (Accessibility.active){
 					noticeSound.play();
@@ -359,7 +359,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				}
 			}
 			
-			public function publicChatFocus(event:FocusEvent):void{
+			public function publicChatFocus(event:FocusEvent):void{
 				publicFocus = true;					
 				publicWaiting = false;
 			}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/UploadEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/UploadEvent.as
old mode 100644
new mode 100755
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
index 2af363e4fe7c9269754dbb097fb981b89675950a..d34439227d593e742c006cf208a523529c1f1000 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
@@ -68,8 +68,8 @@ package org.bigbluebutton.modules.present.managers
 		
 		private function openWindow(window:IBbbModuleWindow):void{
 			var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-			event.window = window;
-			globalDispatcher.dispatchEvent(event);
+			event.window = window;
+			globalDispatcher.dispatchEvent(event);
 		}
 	
 		public function handleOpenUploadWindow(e:UploadEvent):void{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
index 7033929c211aa57b2ef974cabac35925d1d3f1f5..50ea8fdd258754ddd97e1b3e3bfbecc7b1abfa39 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoProxy.as
@@ -1,382 +1,382 @@
-/**
-* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-* 
-* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-*
-* This program is free software; you can redistribute it and/or modify it under the
-* terms of the GNU Lesser General Public License as published by the Free Software
-* Foundation; either version 3.0 of the License, or (at your option) any later
-* version.
-* 
-* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License along
-* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-*
-*/
-package org.bigbluebutton.modules.videoconf.business
-{
-	import com.asfusion.mate.events.Dispatcher;
-	
-	import flash.events.AsyncErrorEvent;
-	import flash.events.IOErrorEvent;
-	import flash.events.NetStatusEvent;
-	import flash.events.SecurityErrorEvent;
-	import flash.media.H264Level;
-	import flash.media.H264Profile;
-	import flash.media.H264VideoStreamSettings;
-	import flash.net.NetConnection;
-	import flash.net.NetStream;
-	import flash.system.Capabilities;
-	import flash.utils.Dictionary;
-
-	import mx.collections.ArrayCollection;
-	
-	import org.bigbluebutton.common.LogUtil;
-	import org.bigbluebutton.core.BBB;
-	import org.bigbluebutton.core.UsersUtil;
-	import org.bigbluebutton.core.managers.UserManager;
-	import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
-	import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
-	import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
-	import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady;
-	import org.bigbluebutton.modules.videoconf.services.messaging.MessageSender;
-	import org.bigbluebutton.modules.videoconf.services.messaging.MessageReceiver;
-	import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent;
-
-	
-	public class VideoProxy
-	{		
-		public var videoOptions:VideoConfOptions;
-		
-		// NetConnection used for stream publishing
-		private var nc:NetConnection;
-		// NetStream used for stream publishing
-		private var ns:NetStream;
-		private var _url:String;
-		private var camerasPublishing:Object = new Object();
-		private var connected:Boolean = false;
-
-		// Message sender to request stream path
-		private var msgSender:MessageSender;
-		// Message receiver to receive the stream path
-		private var msgReceiver:MessageReceiver;
-
-		// Dictionary<url,NetConnection> used for stream playing
-		private var playConnectionDict:Dictionary;
-		// Dictionary<url,Array<streamName>> used to keep track of streams using a URL
-		private var urlStreamsDict:Dictionary;
-		// Dictionary<streamName,streamNamePrefix> used for stream playing
-		private var streamNamePrefixDict:Dictionary;
-		// Dictionary<streamName,url>
-		private var streamUrlDict:Dictionary;
-
-		private function parseOptions():void {
-			videoOptions = new VideoConfOptions();
-			videoOptions.parseOptions();	
-		}
-		
-		public function VideoProxy(url:String)
-		{
-      _url = url;
-			parseOptions();			
-			nc = new NetConnection();
-			nc.proxyType = "best";
-			nc.client = this;
-			nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
-			nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
-			nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
-			nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
-			playConnectionDict = new Dictionary();
-			urlStreamsDict = new Dictionary();
-			streamNamePrefixDict = new Dictionary();
-			streamUrlDict = new Dictionary();
-			msgReceiver = new MessageReceiver(this);
-			msgSender = new MessageSender();
-		}
-		
-    public function connect():void {
-      nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
-		playConnectionDict[_url] = nc;
-		urlStreamsDict[_url] = new Array();
-    }
-    
-		private function onAsyncError(event:AsyncErrorEvent):void{
-		}
-		
-		private function onIOError(event:NetStatusEvent):void{
-		}
-		
-    private function onConnectedToVideoApp():void{
-      var dispatcher:Dispatcher = new Dispatcher();
-      dispatcher.dispatchEvent(new ConnectedEvent(ConnectedEvent.VIDEO_CONNECTED));
-    }
-
-		private function onNetStatus(event:NetStatusEvent):void{
-			switch(event.info.code){
-				case "NetConnection.Connect.Success":
-					connected = true;
-					//ns = new NetStream(nc);
-          onConnectedToVideoApp();
-					break;
-        default:
-					LogUtil.debug("[" + event.info.code + "] for [" + _url + "]");
-					connected = false;
-					break;
-			}
-		}
-
-		private function onSecurityError(event:NetStatusEvent):void{
-		}
-		
-		public function get publishConnection():NetConnection{
-			return this.nc;
-		}
-
-		private function onPlayNetStatus(event:NetStatusEvent):void {
-			var url:String = event.target.uri;
-			var streams:Array = urlStreamsDict[url];
-			var dispatcher:Dispatcher = new Dispatcher();
-			var prefix:String;
-			var stream:String;
-			switch(event.info.code){
-				case "NetConnection.Connect.Success":
-					// Notify streams from this connection
-					var conn:NetConnection = playConnectionDict[url];
-					for each (stream in streams) {
-						prefix = streamNamePrefixDict[stream];
-						dispatcher.dispatchEvent(new PlayConnectionReady(stream, conn, prefix));
-					}
-					break;
-				case "NetConnection.Connect.Failed":
-				case "NetConnection.Connect.Closed":
-					trace("[" + event.info.code + "] for a play connection at [" + url + "]");
-					trace("Affected streams: ["+streams+"]");
-					for each (stream in streams) {
-						prefix = streamNamePrefixDict[stream];
-						delete streamNamePrefixDict[stream];
-						delete streamUrlDict[stream];
-						dispatcher.dispatchEvent(new PlayConnectionClosedEvent(stream, prefix));
-					}
-					delete playConnectionDict[url];
-					delete urlStreamsDict[url];
-					break;
-				default:
-					LogUtil.debug("[" + event.info.code + "] for a play connection at [" + url + "]");
-					break;
-			}
-		}
-
-		public function createPlayConnectionFor(streamName:String):void {
-			LogUtil.debug("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]");
-			// Check if a connection already exists
-			if(!streamUrlDict[streamName]) {
-				trace("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]");
-				// Ask red5 the path to stream
-				msgSender.getStreamPath(streamName);
-			}
-			else {
-				trace("VideoProxy::createPlayConnectionFor:: Found connection for stream [" + streamName + "]");
-			}
-		}
-
-		public function handleStreamPathReceived(streamName:String, connectionPath:String):void {
-			trace("VideoProxy::handleStreamPathReceived:: Path for stream [" + streamName + "]: [" + connectionPath + "]");
-
-			var newUrl:String;
-			var streamPrefix:String;
-
-			// Check whether the is through proxy servers or not
-			if(connectionPath == "") {
-				newUrl = _url;
-				streamPrefix = "";
-			}
-			else {
-				var ipRegex:RegExp = /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/;
-				var serverIp:String = connectionPath.split("/")[0];
-				newUrl = _url.replace(ipRegex, serverIp);
-				streamPrefix = connectionPath.replace(serverIp, "");
-			}
-
-			if(streamPrefix != "")
-				streamPrefix = streamPrefix + "/";
-
-			// Store URL for this stream
-			streamUrlDict[streamName] = newUrl;
-
-			// Set current streamPrefix to use the current path
-			streamNamePrefixDict[streamName] = streamPrefix;
-
-			if(urlStreamsDict[newUrl] == null) {
-				urlStreamsDict[newUrl] = new Array();
-				urlStreamsDict[streamPrefix+streamName] = urlStreamsDict[newUrl];
-			}
-			urlStreamsDict[newUrl].push(streamName);
-
-			// If connection with this URL does not exist
-			if(!playConnectionDict[newUrl]){
-				// Create new NetConnection and store it
-				var connection:NetConnection = new NetConnection();
-				connection.client = this;
-				connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
-				connection.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
-				connection.addEventListener(NetStatusEvent.NET_STATUS, onPlayNetStatus);
-				connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
-				connection.connect(newUrl, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
-				trace("VideoProxy::handleStreamPathReceived:: Creating NetConnection for [" + newUrl + "]");
-				playConnectionDict[newUrl] = connection;
-			}
-			else {
-				if(playConnectionDict[newUrl].connected) {
-					// Connection is ready, send event
-					var dispatcher:Dispatcher = new Dispatcher();
-					dispatcher.dispatchEvent(new PlayConnectionReady(streamName, playConnectionDict[newUrl], streamPrefix));
-				}
-				trace("VideoProxy::handleStreamPathReceived:: Found NetConnection for [" + newUrl + "]");
-			}
-		}
-
-		public function getConnectionForStream(stream:String):NetConnection {
-			var url:String = streamUrlDict[stream];
-			return playConnectionDict[url];
-		}
-
-		public function getPrefixForStream(stream:String):String {
-			if(streamNamePrefixDict[stream])
-				return streamNamePrefixDict[stream];
-			else
-				return "";
-		}
-
-		public function closePlayConnectionFor(streamName:String):void {
-			var temp:Array = streamName.split("/");
-			var stream:String = temp[temp.length-1];
-			var streamUrl:String = streamUrlDict[stream];
-
-			// Remove the url entry for this stream
-			delete streamUrlDict[stream];
-
-			// Check if the connection should be closed
-			var streams:Array = urlStreamsDict[streamUrl];
-			if(streams != null) {
-				streams = streams.filter(function(item:*, index:int, array:Array):Boolean { return item != stream });
-				urlStreamsDict[streamUrl] = streams;
-			}
-			// Do not close publish connection, no matter what
-			if(playConnectionDict[streamUrl] == nc)
-				return;
-			if(streams == null || streams.length <= 0) {
-				trace("VideoProxy:: closePlayConnectionFor:: Closing connection with: [" + streamUrl + "]");
-				// No one else is using this NetConnection
-				var connection:NetConnection = playConnectionDict[streamUrl];
-				if(connection != null) connection.close();
-				delete playConnectionDict[streamUrl];
-				delete urlStreamsDict[streamUrl];
-			}
-			else {
-				trace("VideoProxy:: closePlayConnectionFor:: Connection with: [" + streamUrl + "] has [" + streams.length + "] streams");
-			}
-		}
-
-		public function startPublishing(e:StartBroadcastEvent):void{
-			var ns:NetStream = new NetStream(nc);
-			ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
-			ns.addEventListener( IOErrorEvent.IO_ERROR, onIOError );
-			ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError );
-			ns.client = this;
-			ns.attachCamera(e.camera);
-//		Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011)	
-//			if (Capabilities.version.search("11,0") != -1) {
-			if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) {
-//			if (BBB.getFlashPlayerVersion() >= 11) {
-				LogUtil.info("Using H264 codec for video.");
-				var h264:H264VideoStreamSettings = new H264VideoStreamSettings();
-				var h264profile:String = H264Profile.MAIN;
-				if (e.videoProfile.h264Profile != "main") {
-					h264profile = H264Profile.BASELINE;
-				}
-				var h264Level:String = H264Level.LEVEL_4_1;
-				switch (e.videoProfile.h264Level) {
-					case "1": h264Level = H264Level.LEVEL_1; break;
-					case "1.1": h264Level = H264Level.LEVEL_1_1; break;
-					case "1.2": h264Level = H264Level.LEVEL_1_2; break;
-					case "1.3": h264Level = H264Level.LEVEL_1_3; break;
-					case "1b": h264Level = H264Level.LEVEL_1B; break;
-					case "2": h264Level = H264Level.LEVEL_2; break;
-					case "2.1": h264Level = H264Level.LEVEL_2_1; break;
-					case "2.2": h264Level = H264Level.LEVEL_2_2; break;
-					case "3": h264Level = H264Level.LEVEL_3; break;
-					case "3.1": h264Level = H264Level.LEVEL_3_1; break;
-					case "3.2": h264Level = H264Level.LEVEL_3_2; break;
-					case "4": h264Level = H264Level.LEVEL_4; break;
-					case "4.1": h264Level = H264Level.LEVEL_4_1; break;
-					case "4.2": h264Level = H264Level.LEVEL_4_2; break;
-					case "5": h264Level = H264Level.LEVEL_5; break;
-					case "5.1": h264Level = H264Level.LEVEL_5_1; break;
-				}
-				
-				LogUtil.info("Codec used: " + h264Level);
-				
-				h264.setProfileLevel(h264profile, h264Level);
-				ns.videoStreamSettings = h264;
-			}
-			
-			ns.publish(e.stream);
-			camerasPublishing[e.stream] = ns;
-		}
-		
-		public function stopBroadcasting(stream:String):void{
-      trace("Closing netstream for webcam publishing");
-      			if (camerasPublishing[stream] != null) {
-	      			var ns:NetStream = camerasPublishing[stream];
-				ns.attachCamera(null);
-				ns.close();
-				ns = null;
-				delete camerasPublishing[stream];
-			}	
-		}
-
-		public function stopAllBroadcasting():void {
-			for each (var ns:NetStream in camerasPublishing)
-			{
-				ns.attachCamera(null);
-				ns.close();
-				ns = null;
-			}
-			camerasPublishing = new Object();
-		}
-
-		public function disconnect():void {
-			trace("VideoProxy:: disconnecting from Video application");
-			stopAllBroadcasting();
-			// Close publish NetConnection
-			if (nc != null) nc.close();
-			// Close play NetConnections
-			for (var k:Object in playConnectionDict) {
-				var connection:NetConnection = playConnectionDict[k];
-				connection.close();
-			}
-			// Reset dictionaries
-			playConnectionDict = new Dictionary();
-			streamNamePrefixDict = new Dictionary();
-			urlStreamsDict = new Dictionary();
-			streamUrlDict = new Dictionary();
-		}
-		
-		public function onBWCheck(... rest):Number { 
-			return 0; 
-		} 
-		
-		public function onBWDone(... rest):void { 
-			var p_bw:Number; 
-			if (rest.length > 0) p_bw = rest[0]; 
-			// your application should do something here 
-			// when the bandwidth check is complete 
-			trace("bandwidth = " + p_bw + " Kbps."); 
-		}
-		
-
-	}
-}
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+* 
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+* 
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.modules.videoconf.business
+{
+	import com.asfusion.mate.events.Dispatcher;
+	
+	import flash.events.AsyncErrorEvent;
+	import flash.events.IOErrorEvent;
+	import flash.events.NetStatusEvent;
+	import flash.events.SecurityErrorEvent;
+	import flash.media.H264Level;
+	import flash.media.H264Profile;
+	import flash.media.H264VideoStreamSettings;
+	import flash.net.NetConnection;
+	import flash.net.NetStream;
+	import flash.system.Capabilities;
+	import flash.utils.Dictionary;
+
+	import mx.collections.ArrayCollection;
+	
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.BBB;
+	import org.bigbluebutton.core.UsersUtil;
+	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
+	import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
+	import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
+	import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady;
+	import org.bigbluebutton.modules.videoconf.services.messaging.MessageSender;
+	import org.bigbluebutton.modules.videoconf.services.messaging.MessageReceiver;
+	import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent;
+
+	
+	public class VideoProxy
+	{		
+		public var videoOptions:VideoConfOptions;
+		
+		// NetConnection used for stream publishing
+		private var nc:NetConnection;
+		// NetStream used for stream publishing
+		private var ns:NetStream;
+		private var _url:String;
+		private var camerasPublishing:Object = new Object();
+		private var connected:Boolean = false;
+
+		// Message sender to request stream path
+		private var msgSender:MessageSender;
+		// Message receiver to receive the stream path
+		private var msgReceiver:MessageReceiver;
+
+		// Dictionary<url,NetConnection> used for stream playing
+		private var playConnectionDict:Dictionary;
+		// Dictionary<url,Array<streamName>> used to keep track of streams using a URL
+		private var urlStreamsDict:Dictionary;
+		// Dictionary<streamName,streamNamePrefix> used for stream playing
+		private var streamNamePrefixDict:Dictionary;
+		// Dictionary<streamName,url>
+		private var streamUrlDict:Dictionary;
+
+		private function parseOptions():void {
+			videoOptions = new VideoConfOptions();
+			videoOptions.parseOptions();	
+		}
+		
+		public function VideoProxy(url:String)
+		{
+      _url = url;
+			parseOptions();			
+			nc = new NetConnection();
+			nc.proxyType = "best";
+			nc.client = this;
+			nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
+			nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+			nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
+			nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+			playConnectionDict = new Dictionary();
+			urlStreamsDict = new Dictionary();
+			streamNamePrefixDict = new Dictionary();
+			streamUrlDict = new Dictionary();
+			msgReceiver = new MessageReceiver(this);
+			msgSender = new MessageSender();
+		}
+		
+    public function connect():void {
+      nc.connect(_url, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
+		playConnectionDict[_url] = nc;
+		urlStreamsDict[_url] = new Array();
+    }
+    
+		private function onAsyncError(event:AsyncErrorEvent):void{
+		}
+		
+		private function onIOError(event:NetStatusEvent):void{
+		}
+		
+    private function onConnectedToVideoApp():void{
+      var dispatcher:Dispatcher = new Dispatcher();
+      dispatcher.dispatchEvent(new ConnectedEvent(ConnectedEvent.VIDEO_CONNECTED));
+    }
+
+		private function onNetStatus(event:NetStatusEvent):void{
+			switch(event.info.code){
+				case "NetConnection.Connect.Success":
+					connected = true;
+					//ns = new NetStream(nc);
+          onConnectedToVideoApp();
+					break;
+        default:
+					LogUtil.debug("[" + event.info.code + "] for [" + _url + "]");
+					connected = false;
+					break;
+			}
+		}
+
+		private function onSecurityError(event:NetStatusEvent):void{
+		}
+		
+		public function get publishConnection():NetConnection{
+			return this.nc;
+		}
+
+		private function onPlayNetStatus(event:NetStatusEvent):void {
+			var url:String = event.target.uri;
+			var streams:Array = urlStreamsDict[url];
+			var dispatcher:Dispatcher = new Dispatcher();
+			var prefix:String;
+			var stream:String;
+			switch(event.info.code){
+				case "NetConnection.Connect.Success":
+					// Notify streams from this connection
+					var conn:NetConnection = playConnectionDict[url];
+					for each (stream in streams) {
+						prefix = streamNamePrefixDict[stream];
+						dispatcher.dispatchEvent(new PlayConnectionReady(stream, conn, prefix));
+					}
+					break;
+				case "NetConnection.Connect.Failed":
+				case "NetConnection.Connect.Closed":
+					trace("[" + event.info.code + "] for a play connection at [" + url + "]");
+					trace("Affected streams: ["+streams+"]");
+					for each (stream in streams) {
+						prefix = streamNamePrefixDict[stream];
+						delete streamNamePrefixDict[stream];
+						delete streamUrlDict[stream];
+						dispatcher.dispatchEvent(new PlayConnectionClosedEvent(stream, prefix));
+					}
+					delete playConnectionDict[url];
+					delete urlStreamsDict[url];
+					break;
+				default:
+					LogUtil.debug("[" + event.info.code + "] for a play connection at [" + url + "]");
+					break;
+			}
+		}
+
+		public function createPlayConnectionFor(streamName:String):void {
+			LogUtil.debug("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]");
+			// Check if a connection already exists
+			if(!streamUrlDict[streamName]) {
+				trace("VideoProxy::createPlayConnectionFor:: Requesting path for stream [" + streamName + "]");
+				// Ask red5 the path to stream
+				msgSender.getStreamPath(streamName);
+			}
+			else {
+				trace("VideoProxy::createPlayConnectionFor:: Found connection for stream [" + streamName + "]");
+			}
+		}
+
+		public function handleStreamPathReceived(streamName:String, connectionPath:String):void {
+			trace("VideoProxy::handleStreamPathReceived:: Path for stream [" + streamName + "]: [" + connectionPath + "]");
+
+			var newUrl:String;
+			var streamPrefix:String;
+
+			// Check whether the is through proxy servers or not
+			if(connectionPath == "") {
+				newUrl = _url;
+				streamPrefix = "";
+			}
+			else {
+				var ipRegex:RegExp = /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/;
+				var serverIp:String = connectionPath.split("/")[0];
+				newUrl = _url.replace(ipRegex, serverIp);
+				streamPrefix = connectionPath.replace(serverIp, "");
+			}
+
+			if(streamPrefix != "")
+				streamPrefix = streamPrefix + "/";
+
+			// Store URL for this stream
+			streamUrlDict[streamName] = newUrl;
+
+			// Set current streamPrefix to use the current path
+			streamNamePrefixDict[streamName] = streamPrefix;
+
+			if(urlStreamsDict[newUrl] == null) {
+				urlStreamsDict[newUrl] = new Array();
+				urlStreamsDict[streamPrefix+streamName] = urlStreamsDict[newUrl];
+			}
+			urlStreamsDict[newUrl].push(streamName);
+
+			// If connection with this URL does not exist
+			if(!playConnectionDict[newUrl]){
+				// Create new NetConnection and store it
+				var connection:NetConnection = new NetConnection();
+				connection.client = this;
+				connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
+				connection.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+				connection.addEventListener(NetStatusEvent.NET_STATUS, onPlayNetStatus);
+				connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+				connection.connect(newUrl, UsersUtil.getInternalMeetingID(), UsersUtil.getMyUserID());
+				trace("VideoProxy::handleStreamPathReceived:: Creating NetConnection for [" + newUrl + "]");
+				playConnectionDict[newUrl] = connection;
+			}
+			else {
+				if(playConnectionDict[newUrl].connected) {
+					// Connection is ready, send event
+					var dispatcher:Dispatcher = new Dispatcher();
+					dispatcher.dispatchEvent(new PlayConnectionReady(streamName, playConnectionDict[newUrl], streamPrefix));
+				}
+				trace("VideoProxy::handleStreamPathReceived:: Found NetConnection for [" + newUrl + "]");
+			}
+		}
+
+		public function getConnectionForStream(stream:String):NetConnection {
+			var url:String = streamUrlDict[stream];
+			return playConnectionDict[url];
+		}
+
+		public function getPrefixForStream(stream:String):String {
+			if(streamNamePrefixDict[stream])
+				return streamNamePrefixDict[stream];
+			else
+				return "";
+		}
+
+		public function closePlayConnectionFor(streamName:String):void {
+			var temp:Array = streamName.split("/");
+			var stream:String = temp[temp.length-1];
+			var streamUrl:String = streamUrlDict[stream];
+
+			// Remove the url entry for this stream
+			delete streamUrlDict[stream];
+
+			// Check if the connection should be closed
+			var streams:Array = urlStreamsDict[streamUrl];
+			if(streams != null) {
+				streams = streams.filter(function(item:*, index:int, array:Array):Boolean { return item != stream });
+				urlStreamsDict[streamUrl] = streams;
+			}
+			// Do not close publish connection, no matter what
+			if(playConnectionDict[streamUrl] == nc)
+				return;
+			if(streams == null || streams.length <= 0) {
+				trace("VideoProxy:: closePlayConnectionFor:: Closing connection with: [" + streamUrl + "]");
+				// No one else is using this NetConnection
+				var connection:NetConnection = playConnectionDict[streamUrl];
+				if(connection != null) connection.close();
+				delete playConnectionDict[streamUrl];
+				delete urlStreamsDict[streamUrl];
+			}
+			else {
+				trace("VideoProxy:: closePlayConnectionFor:: Connection with: [" + streamUrl + "] has [" + streams.length + "] streams");
+			}
+		}
+
+		public function startPublishing(e:StartBroadcastEvent):void{
+			var ns:NetStream = new NetStream(nc);
+			ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
+			ns.addEventListener( IOErrorEvent.IO_ERROR, onIOError );
+			ns.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError );
+			ns.client = this;
+			ns.attachCamera(e.camera);
+//		Uncomment if you want to build support for H264. But you need at least FP 11. (ralam july 23, 2011)	
+//			if (Capabilities.version.search("11,0") != -1) {
+			if ((BBB.getFlashPlayerVersion() >= 11) && e.videoProfile.enableH264) {
+//			if (BBB.getFlashPlayerVersion() >= 11) {
+				LogUtil.info("Using H264 codec for video.");
+				var h264:H264VideoStreamSettings = new H264VideoStreamSettings();
+				var h264profile:String = H264Profile.MAIN;
+				if (e.videoProfile.h264Profile != "main") {
+					h264profile = H264Profile.BASELINE;
+				}
+				var h264Level:String = H264Level.LEVEL_4_1;
+				switch (e.videoProfile.h264Level) {
+					case "1": h264Level = H264Level.LEVEL_1; break;
+					case "1.1": h264Level = H264Level.LEVEL_1_1; break;
+					case "1.2": h264Level = H264Level.LEVEL_1_2; break;
+					case "1.3": h264Level = H264Level.LEVEL_1_3; break;
+					case "1b": h264Level = H264Level.LEVEL_1B; break;
+					case "2": h264Level = H264Level.LEVEL_2; break;
+					case "2.1": h264Level = H264Level.LEVEL_2_1; break;
+					case "2.2": h264Level = H264Level.LEVEL_2_2; break;
+					case "3": h264Level = H264Level.LEVEL_3; break;
+					case "3.1": h264Level = H264Level.LEVEL_3_1; break;
+					case "3.2": h264Level = H264Level.LEVEL_3_2; break;
+					case "4": h264Level = H264Level.LEVEL_4; break;
+					case "4.1": h264Level = H264Level.LEVEL_4_1; break;
+					case "4.2": h264Level = H264Level.LEVEL_4_2; break;
+					case "5": h264Level = H264Level.LEVEL_5; break;
+					case "5.1": h264Level = H264Level.LEVEL_5_1; break;
+				}
+				
+				LogUtil.info("Codec used: " + h264Level);
+				
+				h264.setProfileLevel(h264profile, h264Level);
+				ns.videoStreamSettings = h264;
+			}
+			
+			ns.publish(e.stream);
+			camerasPublishing[e.stream] = ns;
+		}
+		
+		public function stopBroadcasting(stream:String):void{
+      trace("Closing netstream for webcam publishing");
+      			if (camerasPublishing[stream] != null) {
+	      			var ns:NetStream = camerasPublishing[stream];
+				ns.attachCamera(null);
+				ns.close();
+				ns = null;
+				delete camerasPublishing[stream];
+			}	
+		}
+
+		public function stopAllBroadcasting():void {
+			for each (var ns:NetStream in camerasPublishing)
+			{
+				ns.attachCamera(null);
+				ns.close();
+				ns = null;
+			}
+			camerasPublishing = new Object();
+		}
+
+		public function disconnect():void {
+			trace("VideoProxy:: disconnecting from Video application");
+			stopAllBroadcasting();
+			// Close publish NetConnection
+			if (nc != null) nc.close();
+			// Close play NetConnections
+			for (var k:Object in playConnectionDict) {
+				var connection:NetConnection = playConnectionDict[k];
+				connection.close();
+			}
+			// Reset dictionaries
+			playConnectionDict = new Dictionary();
+			streamNamePrefixDict = new Dictionary();
+			urlStreamsDict = new Dictionary();
+			streamUrlDict = new Dictionary();
+		}
+		
+		public function onBWCheck(... rest):Number { 
+			return 0; 
+		} 
+		
+		public function onBWDone(... rest):void { 
+			var p_bw:Number; 
+			if (rest.length > 0) p_bw = rest[0]; 
+			// your application should do something here 
+			// when the bandwidth check is complete 
+			trace("bandwidth = " + p_bw + " Kbps."); 
+		}
+		
+
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml
index 3e5f8d31eac28d0666c6a0069fb4b4bd5e92bcc7..62f23acc6cbc00dbb39825c7d490a8665be05717 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMap.mxml
@@ -1,144 +1,144 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-
-BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-
-This program is free software; you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free Software
-Foundation; either version 3.0 of the License, or (at your option) any later
-version.
-
-BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-
--->
-
-<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
-	<mx:Script>
-		<![CDATA[
-      import org.bigbluebutton.core.events.ConnectAppEvent;
-      import org.bigbluebutton.main.events.BBBEvent;
-      import org.bigbluebutton.main.events.MadePresenterEvent;
-      import org.bigbluebutton.main.events.StoppedViewingWebcamEvent;
-      import org.bigbluebutton.main.events.UserJoinedEvent;
-      import org.bigbluebutton.main.events.UserLeftEvent;
-      import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
-      import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
-      import org.bigbluebutton.modules.users.events.ViewCameraEvent;
-      import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
-      import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
-      import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
-      import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
-      import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
-      import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
-      import org.bigbluebutton.modules.videoconf.events.VideoModuleStartEvent;
-      import org.bigbluebutton.modules.videoconf.events.VideoModuleStopEvent;
-      import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady;
-      import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent;
-		]]>
-	</mx:Script>
-	
-  <EventHandlers type="{VideoModuleStartEvent.START}">
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="start" arguments="{event.uri}"/>
-    <EventAnnouncer generator="{ConnectAppEvent}" type="{ConnectAppEvent.CONNECT_VIDEO_APP}" />
-  </EventHandlers>
- 
-  <EventHandlers type="{VideoModuleStopEvent.STOP}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="stopModule"/>
-  </EventHandlers>
-  
-  <EventHandlers type="{BBBEvent.CAMERA_SETTING}" >
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCameraSetting" arguments="{event}"/>
-  </EventHandlers>
-  
-  <EventHandlers type="{ConnectAppEvent.CONNECT_VIDEO_APP}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="connectToVideoApp" />
-  </EventHandlers>
-  
-	<EventHandlers type="{ShareCameraRequestEvent.SHARE_CAMERA_REQUEST}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleShareCameraRequestEvent" arguments="{event}"/>
-	</EventHandlers>
-
-  <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_CAMERA_REQUEST}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopShareCameraRequestEvent" arguments="{event}"/>
-  </EventHandlers>
-
-  <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_ALL_CAMERA_REQUEST}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopAllShareCameraRequestEvent" arguments="{event}"/>
-  </EventHandlers>
-
-	<EventHandlers type="{StartBroadcastEvent.START_BROADCAST}" >
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="startPublishing" arguments="{event}" />
-	</EventHandlers>
-	
-	<EventHandlers type="{StopBroadcastEvent.STOP_BROADCASTING}" >
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="stopPublishing" arguments="{event}" />
-	</EventHandlers>
-	
-	<EventHandlers type="{StreamStartedEvent.STREAM_STARTED}">
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.user]}" />
-	</EventHandlers>
-
-	<EventHandlers type="{StreamStoppedEvent.STREAM_STOPPED}">
-		<MethodInvoker generator="{VideoEventMapDelegate}" method="handleStreamStoppedEvent" arguments="{[event.userID, event.stream]}" />
-	</EventHandlers>
-	
-	<EventHandlers type="{ViewCameraEvent.VIEW_CAMERA_EVENT}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.viewedName]}" />
-	</EventHandlers>
-
-  <EventHandlers type="{UserJoinedEvent.JOINED}">
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserJoinedEvent" arguments="{event}" />
-  </EventHandlers>
-
-  <EventHandlers type="{UserLeftEvent.LEFT}">
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserLeftEvent" arguments="{event}" />
-  </EventHandlers>
-  
-	<EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" >
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToPresenter" arguments="{event}"/>	
-	</EventHandlers>
-	
-	<EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}">
-    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToViewer" arguments="{event}"/>
-	</EventHandlers>
-
-  <EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp" />
-  </EventHandlers>
- 
-  <EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleClosePublishWindowEvent" arguments="{event}"/>
-  </EventHandlers>
-  
-  <EventHandlers type="{StoppedViewingWebcamEvent.STOPPED_VIEWING_WEBCAM}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStoppedViewingWebcamEvent"  arguments="{[event.webcamUserID, event.streamName]}"/>
-  </EventHandlers>
-  
-  <EventHandlers type="{BBBEvent.CAM_SETTINGS_CLOSED}">
-    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCamSettingsClosedEvent"  arguments="{event}"/>
-  </EventHandlers>
-  
-	<EventHandlers type="{PlayConnectionReady.PLAY_CONNECTION_READY}">
-		<MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionReady" arguments="{event}" />
-	</EventHandlers>
-
-	<EventHandlers type="{PlayConnectionClosedEvent.PLAY_CONNECTION_CLOSED_EVENT}">
-		<MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionClosed" arguments="{[event.streamName, event.prefix]}" />
-	</EventHandlers>
-  <!-- ~~~~~~~~~~~~~~~~~~    INJECTORS     ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
-  
-</EventMap>
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
+	<mx:Script>
+		<![CDATA[
+      import org.bigbluebutton.core.events.ConnectAppEvent;
+      import org.bigbluebutton.main.events.BBBEvent;
+      import org.bigbluebutton.main.events.MadePresenterEvent;
+      import org.bigbluebutton.main.events.StoppedViewingWebcamEvent;
+      import org.bigbluebutton.main.events.UserJoinedEvent;
+      import org.bigbluebutton.main.events.UserLeftEvent;
+      import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
+      import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
+      import org.bigbluebutton.modules.users.events.ViewCameraEvent;
+      import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
+      import org.bigbluebutton.modules.videoconf.events.ConnectedEvent;
+      import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
+      import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
+      import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
+      import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
+      import org.bigbluebutton.modules.videoconf.events.VideoModuleStartEvent;
+      import org.bigbluebutton.modules.videoconf.events.VideoModuleStopEvent;
+      import org.bigbluebutton.modules.videoconf.events.PlayConnectionReady;
+      import org.bigbluebutton.modules.videoconf.events.PlayConnectionClosedEvent;
+		]]>
+	</mx:Script>
+	
+  <EventHandlers type="{VideoModuleStartEvent.START}">
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="start" arguments="{event.uri}"/>
+    <EventAnnouncer generator="{ConnectAppEvent}" type="{ConnectAppEvent.CONNECT_VIDEO_APP}" />
+  </EventHandlers>
+ 
+  <EventHandlers type="{VideoModuleStopEvent.STOP}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="stopModule"/>
+  </EventHandlers>
+  
+  <EventHandlers type="{BBBEvent.CAMERA_SETTING}" >
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCameraSetting" arguments="{event}"/>
+  </EventHandlers>
+  
+  <EventHandlers type="{ConnectAppEvent.CONNECT_VIDEO_APP}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="connectToVideoApp" />
+  </EventHandlers>
+  
+	<EventHandlers type="{ShareCameraRequestEvent.SHARE_CAMERA_REQUEST}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleShareCameraRequestEvent" arguments="{event}"/>
+	</EventHandlers>
+
+  <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_CAMERA_REQUEST}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopShareCameraRequestEvent" arguments="{event}"/>
+  </EventHandlers>
+
+  <EventHandlers type="{StopShareCameraRequestEvent.STOP_SHARE_ALL_CAMERA_REQUEST}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStopAllShareCameraRequestEvent" arguments="{event}"/>
+  </EventHandlers>
+
+	<EventHandlers type="{StartBroadcastEvent.START_BROADCAST}" >
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="startPublishing" arguments="{event}" />
+	</EventHandlers>
+	
+	<EventHandlers type="{StopBroadcastEvent.STOP_BROADCASTING}" >
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="stopPublishing" arguments="{event}" />
+	</EventHandlers>
+	
+	<EventHandlers type="{StreamStartedEvent.STREAM_STARTED}">
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.user]}" />
+	</EventHandlers>
+
+	<EventHandlers type="{StreamStoppedEvent.STREAM_STOPPED}">
+		<MethodInvoker generator="{VideoEventMapDelegate}" method="handleStreamStoppedEvent" arguments="{[event.userID, event.stream]}" />
+	</EventHandlers>
+	
+	<EventHandlers type="{ViewCameraEvent.VIEW_CAMERA_EVENT}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="viewCamera" arguments="{[event.userID, event.stream, event.viewedName]}" />
+	</EventHandlers>
+
+  <EventHandlers type="{UserJoinedEvent.JOINED}">
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserJoinedEvent" arguments="{event}" />
+  </EventHandlers>
+
+  <EventHandlers type="{UserLeftEvent.LEFT}">
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleUserLeftEvent" arguments="{event}" />
+  </EventHandlers>
+  
+	<EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" >
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToPresenter" arguments="{event}"/>	
+	</EventHandlers>
+	
+	<EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}">
+    <ObjectBuilder generator="{VideoEventMapDelegate}" cache="global" constructorArguments="{scope.dispatcher}"/>
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="switchToViewer" arguments="{event}"/>
+	</EventHandlers>
+
+  <EventHandlers type="{ConnectedEvent.VIDEO_CONNECTED}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="connectedToVideoApp" />
+  </EventHandlers>
+ 
+  <EventHandlers type="{ClosePublishWindowEvent.CLOSE_PUBLISH_WINDOW}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleClosePublishWindowEvent" arguments="{event}"/>
+  </EventHandlers>
+  
+  <EventHandlers type="{StoppedViewingWebcamEvent.STOPPED_VIEWING_WEBCAM}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleStoppedViewingWebcamEvent"  arguments="{[event.webcamUserID, event.streamName]}"/>
+  </EventHandlers>
+  
+  <EventHandlers type="{BBBEvent.CAM_SETTINGS_CLOSED}">
+    <MethodInvoker generator="{VideoEventMapDelegate}" method="handleCamSettingsClosedEvent"  arguments="{event}"/>
+  </EventHandlers>
+  
+	<EventHandlers type="{PlayConnectionReady.PLAY_CONNECTION_READY}">
+		<MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionReady" arguments="{event}" />
+	</EventHandlers>
+
+	<EventHandlers type="{PlayConnectionClosedEvent.PLAY_CONNECTION_CLOSED_EVENT}">
+		<MethodInvoker generator="{VideoEventMapDelegate}" method="handlePlayConnectionClosed" arguments="{[event.streamName, event.prefix]}" />
+	</EventHandlers>
+  <!-- ~~~~~~~~~~~~~~~~~~    INJECTORS     ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
+  
+</EventMap>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as
index 2998091b912b54f91805e763a97b43ffdb1f382f..52873d7eb653c81b5cf68ccc7078fe7889249700 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/VideoConfOptions.as
@@ -79,7 +79,8 @@ package org.bigbluebutton.modules.videoconf.model
 		
 		[Bindable]
 		public var glowBlurSize:Number = 30.0;
-        [Bindable]
+
+		[Bindable]
 		public var priorityRatio:Number = 2/3;
 		
 		public function VideoConfOptions() {
@@ -165,7 +166,7 @@ package org.bigbluebutton.modules.videoconf.model
 					glowBlurSize = Number(vxml.@glowBlurSize.toString());
 				}
 				if (vxml.@priorityRatio != undefined) {
-                    priorityRatio = Number(vxml.@priorityRatio.toString());
+					priorityRatio = Number(vxml.@priorityRatio.toString());
 				}
 			}
 		}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml
index 5e547d63b8024b81ad4aaed14c3b2e1b16c173a6..4214254a5fa35dae9d2b97e9b4d325a022522375 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/AvatarWindow.mxml
@@ -36,39 +36,37 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	
 	<mate:Listener type="{BBBEvent.USER_VOICE_MUTED}" method="handleUserVoiceMutedEvent" />
 	<mate:Listener type="{EventConstants.USER_TALKING}" method="handleUserTalkingEvent" />
-  	<mate:Listener type="{SwitchedPresenterEvent.SWITCHED_PRESENTER}" method="handleSwitchedPresenterEvent" />
-  	<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="handleMadePresenterEvent" /> 
-  	<mate:Listener type="{BBBEvent.USER_VOICE_JOINED}" method="handleNewRoleEvent" />
-  	<mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleNewRoleEvent" />
+  <mate:Listener type="{SwitchedPresenterEvent.SWITCHED_PRESENTER}" method="handleSwitchedPresenterEvent" />
+  <mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="handleMadePresenterEvent" /> 
+  <mate:Listener type="{BBBEvent.USER_VOICE_JOINED}" method="handleNewRoleEvent" />
+  <mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleNewRoleEvent" />
 	<mate:Listener type="{CloseAllWindowsEvent.CLOSE_ALL_WINDOWS}" method="closeWindow" />
 	
 	<mx:Script>
 		<![CDATA[
-    		import flexlib.mdi.events.MDIWindowEvent;
+      import flexlib.mdi.events.MDIWindowEvent;
       
-			import mx.core.UIComponent;
-			import mx.events.ResizeEvent;
-      
-			import org.bigbluebutton.common.Images;
-			import org.bigbluebutton.common.LogUtil;
-			import org.bigbluebutton.common.Role;
-			import org.bigbluebutton.common.events.CloseWindowEvent;
-			import org.bigbluebutton.common.events.LocaleChangeEvent;
-			import org.bigbluebutton.core.EventConstants;
-			import org.bigbluebutton.core.UsersUtil;
-			import org.bigbluebutton.core.events.CoreEvent;
-			import org.bigbluebutton.core.events.SwitchedLayoutEvent;
-			import org.bigbluebutton.core.managers.UserManager;
-			import org.bigbluebutton.main.events.BBBEvent;
-			import org.bigbluebutton.main.events.MadePresenterEvent;
-			import org.bigbluebutton.main.events.SwitchedPresenterEvent;
-			import org.bigbluebutton.main.views.MainCanvas;
-			import org.bigbluebutton.modules.videoconf.business.TalkingButtonOverlay;
-			import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
-			import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
-			import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
-			import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
-			import org.bigbluebutton.util.i18n.ResourceUtil;
+      import mx.core.UIComponent;
+      import mx.events.ResizeEvent;     
+      import org.bigbluebutton.common.Images;
+      import org.bigbluebutton.common.LogUtil;
+      import org.bigbluebutton.common.Role;
+      import org.bigbluebutton.common.events.CloseWindowEvent;
+      import org.bigbluebutton.common.events.LocaleChangeEvent;
+      import org.bigbluebutton.core.EventConstants;
+      import org.bigbluebutton.core.UsersUtil;
+      import org.bigbluebutton.core.events.CoreEvent;
+      import org.bigbluebutton.core.managers.UserManager;
+      import org.bigbluebutton.main.events.BBBEvent;
+      import org.bigbluebutton.main.events.MadePresenterEvent;
+      import org.bigbluebutton.main.events.SwitchedPresenterEvent;
+      import org.bigbluebutton.main.views.MainCanvas;
+      import org.bigbluebutton.modules.videoconf.business.TalkingButtonOverlay;
+      import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
+      import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
+      import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
+      import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
 			
 			[Bindable] private var defaultWidth:Number = 320;
 			[Bindable] private var defaultHeight:Number = 240;
diff --git a/bigbluebutton-config/bigbluebutton-release b/bigbluebutton-config/bigbluebutton-release
index 3356e7cc65b1385060d0806c04803c63fe33ec8f..ef39c792a36e9e1b9a07c2c7b4e3455f3cee5455 100644
--- a/bigbluebutton-config/bigbluebutton-release
+++ b/bigbluebutton-config/bigbluebutton-release
@@ -1 +1 @@
-BIGBLUEBUTTON_RELEASE=0.9.0-RC
+BIGBLUEBUTTON_RELEASE=0.9.0
diff --git a/bigbluebutton-config/web/default.pdf b/bigbluebutton-config/web/default.pdf
old mode 100644
new mode 100755
diff --git a/bigbluebutton-html5/app/client/globals.coffee b/bigbluebutton-html5/app/client/globals.coffee
index a81f92b2eb199c3aa0aac2f9c27ff07771542a22..766906ff0b0db52fc1a0b9d7d4105a19ecacda4b 100755
--- a/bigbluebutton-html5/app/client/globals.coffee
+++ b/bigbluebutton-html5/app/client/globals.coffee
@@ -61,14 +61,6 @@
   currentPresentation = Meteor.Presentations.findOne({"presentation.current": true})
   currentPresentation?.presentation?.name
 
-# helper to determine whether user has joined any type of audio
-Handlebars.registerHelper "amIInAudio", ->
-  BBB.amIInAudio()
-
-# helper to determine whether the user is in the listen only audio stream
-Handlebars.registerHelper "amIListenOnlyAudio", ->
-  BBB.amIListenOnlyAudio()
-
 Handlebars.registerHelper "colourToHex", (value) =>
   @window.colourToHex(value)
 
@@ -112,7 +104,7 @@ Handlebars.registerHelper "getUsersInMeeting", ->
   raised.concat lowered
 
 Handlebars.registerHelper "getWhiteboardTitle", ->
-  (getPresentationFilename() or "Loading presentaion...")
+  "Presentation: " + (getPresentationFilename() or "Loading...")
 
 Handlebars.registerHelper "isCurrentUser", (userId) ->
   userId is null or userId is BBB.getCurrentUser()?.userId
@@ -124,6 +116,9 @@ Handlebars.registerHelper "isCurrentUserRaisingHand", ->
   user = BBB.getCurrentUser()
   user?.user?.raise_hand
 
+Handlebars.registerHelper "isCurrentUserSharingAudio", ->
+  BBB.amISharingAudio()
+
 Handlebars.registerHelper "isCurrentUserSharingVideo", ->
   BBB.amISharingVideo()
 
@@ -133,15 +128,16 @@ Handlebars.registerHelper "isCurrentUserTalking", ->
 Handlebars.registerHelper "isDisconnected", ->
   return !Meteor.status().connected
 
-Handlebars.registerHelper "isUserInAudio", (userId) ->
-  BBB.isUserInAudio(userId)
-
-Handlebars.registerHelper "isUserListenOnlyAudio", (userId) ->
-  BBB.isUserListenOnlyAudio(userId)
+Handlebars.registerHelper "isUserListenOnly", (userId) ->
+  user = Meteor.Users.findOne({userId:userId})
+  return user?.user?.listenOnly
 
 Handlebars.registerHelper "isUserMuted", (userId) ->
   BBB.isUserMuted(userId)
 
+Handlebars.registerHelper "isUserSharingAudio", (userId) ->
+  BBB.isUserSharingAudio(userId)
+
 Handlebars.registerHelper "isUserSharingVideo", (userId) ->
   BBB.isUserSharingWebcam(userId)
 
@@ -188,11 +184,6 @@ Handlebars.registerHelper "visibility", (section) ->
   str = str.replace http, "<a href='event:$1'><u>$1</u></a>"
   str = str.replace www, "$1<a href='event:http://$2'><u>$2</u></a>"
 
-@introToAudio = (event, {isListenOnly} = {}) ->
-  isListenOnly ?= true
-  joinVoiceCall event, isListenOnly: isListenOnly
-  displayWebRTCNotification()
-
 # check the chat history of the user and add tabs for the private chats
 @populateChatTabs = (msg) ->
   myUserId = getInSession "userId"
@@ -262,45 +253,16 @@ Handlebars.registerHelper "visibility", (section) ->
     setInSession "display_usersList", !getInSession "display_usersList"
   setTimeout(redrawWhiteboard, 0)
 
-# Periodically check the status of the WebRTC call, when a call has been established attempt to hangup,
-# retry if a call is in progress, send the leave voice conference message to BBB
-@exitVoiceCall = (event) ->
-  # To be called when the hangup is initiated
-  hangupCallback = ->
-    console.log "Exiting Voice Conference"
-
-  # Checks periodically until a call is established so we can successfully end the call
-  # clean state
-  getInSession("triedHangup", false)
-  # function to initiate call
-  (checkToHangupCall = (context) ->
-    # if an attempt to hang up the call is made when the current session is not yet finished, the request has no effect
-    # keep track in the session if we haven't tried a hangup
-    if BBB.getCallStatus() isnt null and !getInSession("triedHangup")
-      console.log "Attempting to hangup on WebRTC call"
-      if BBB.amIListenOnlyAudio() # notify BBB-apps we are leaving the call call if we are listen only
-        Meteor.call('listenOnlyRequestToggle', getInSession("meetingId"), getInSession("userId"), getInSession("authToken"), false)
-      BBB.leaveVoiceConference hangupCallback
-      getInSession("triedHangup", true) # we have hung up, prevent retries
-    else
-      console.log "RETRYING hangup on WebRTC call in #{Meteor.config.app.WebRTCHangupRetryInterval} ms"
-      setTimeout checkToHangupCall, Meteor.config.app.WebRTCHangupRetryInterval # try again periodically
-  )(@) # automatically run function
-  return false
-
-# close the daudio UI, then join the conference. If listen only send the request to the server
-@joinVoiceCall = (event, {isListenOnly} = {}) ->
-  $('#joinAudioDialog').dialog('close')
-  isListenOnly ?= true
-
-  # create voice call params
-  joinCallback = (message) ->
-    console.log "Beginning WebRTC Conference Call"
-
-  if isListenOnly
-    Meteor.call('listenOnlyRequestToggle', getInSession("meetingId"), getInSession("userId"), getInSession("authToken"), true)
-  BBB.joinVoiceConference joinCallback, isListenOnly # make the call #TODO should we apply role permissions to this action?
-
+@toggleVoiceCall = (event) ->
+  if BBB.amISharingAudio()
+    hangupCallback = ->
+      console.log "left voice conference"
+    BBB.leaveVoiceConference hangupCallback #TODO should we apply role permissions to this action?
+  else
+    # create voice call params
+    joinCallback = (message) ->
+      console.log "started webrtc_call"
+    BBB.joinVoiceConference joinCallback # make the call #TODO should we apply role permissions to this action?
   return false
 
 @toggleWhiteBoard = ->
diff --git a/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee b/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee
old mode 100755
new mode 100644
index 26aa86c2caf527605b607327e36aae45b2d773d7..18747f6a8267d0616e203b78aaf545b8c7de3928
--- a/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee
+++ b/bigbluebutton-html5/app/client/lib/bbb_api_bridge.coffee
@@ -57,48 +57,17 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
   BBB.isUserSharingWebcam = (userId, callback) ->
     BBB.getUser(userId)?.user?.webcam_stream?.length isnt 0
 
-  # returns whether the user has joined any type of audio
-  BBB.amIInAudio = (callback) ->
-    user = BBB.getCurrentUser()
-    user?.user?.listenOnly or user?.user?.voiceUser?.joined
-
-  # returns true if the user has joined the listen only audio stream
-  BBB.amIListenOnlyAudio = (callback) ->
-    BBB.isUserListenOnlyAudio BBB.getCurrentUser()?.userId
-
-  # returns whether the user has joined the voice conference and is sharing audio through a microphone
-  BBB.amISharingAudio = (callback) ->
-    BBB.isUserSharingAudio BBB.getCurrentUser()?.userId
-
-  # returns whether the user is currently talking
   BBB.amITalking = (callback) ->
     BBB.isUserTalking BBB.getCurrentUser()?.userId
 
-  BBB.isUserInAudio = (userId, callback) ->
-    user = BBB.getUser(userId)
-    user?.user?.listenOnly or user?.user?.voiceUser?.joined
-
-  BBB.isUserListenOnlyAudio = (userId, callback) ->
-    BBB.getUser(userId)?.user?.listenOnly
-
-  BBB.isUserSharingAudio = (userId, callback) ->
-    BBB.getUser(userId)?.user?.voiceUser?.joined
-
   BBB.isUserTalking = (userId, callback) ->
     BBB.getUser(userId)?.user?.voiceUser?.talking
 
-  # returns true if the current user is marked as locked
-  BBB.amILocked = () ->
-    return BBB.getCurrentUser()?.user.locked
-
-  # check whether the user is locked AND the current lock settings for the room
-  # includes locking the microphone of viewers (listenOnly is still alowed)
-  BBB.isMyMicLocked = () ->
-    lockedMicForRoom = Meteor.Meetings.findOne()?.roomLockSettings.disableMic
-    # note that voiceUser.locked is not used in BigBlueButton at this stage (April 2015)
-
-    return lockedMicForRoom and BBB.amILocked()
+  BBB.amISharingAudio = (callback) ->
+    BBB.isUserSharingAudio BBB.getCurrentUser()?.userId
 
+  BBB.isUserSharingAudio = (userId) ->
+    BBB.getUser(userId)?.user?.voiceUser?.joined
 
   ###
   Raise user's hand.
@@ -218,12 +187,9 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
 
   ###
   Join the voice conference.
-  isListenOnly: signifies whether the user joining the conference audio requests to join the listen only stream
   ###
-  BBB.joinVoiceConference = (callback, isListenOnly) ->
-    if BBB.isMyMicLocked()
-      callIntoConference(BBB.getMyVoiceBridge(), callback, true) #true because we force isListenOnly mode
-    callIntoConference(BBB.getMyVoiceBridge(), callback, isListenOnly)
+  BBB.joinVoiceConference = (callback) ->
+    callIntoConference(BBB.getMyVoiceBridge(), callback)
 
   ###
   Leave the voice conference.
@@ -231,12 +197,6 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
   BBB.leaveVoiceConference = (callback) ->
     webrtc_hangup callback # sign out of call
 
-  ###
-  Get a hold of the object containing the call information
-  ###
-  BBB.getCallStatus = ->
-    getCallStatus()
-
   ###
   Share user's webcam.
 
@@ -380,7 +340,7 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
   listeners = {}
 
   ###
-  3rd-party apps should use this method to register to listen for events.
+  3rd-party apps should user this method to register to listen for events.
   ###
   BBB.listen = (eventName, handler) ->
 
diff --git a/bigbluebutton-html5/app/client/main.coffee b/bigbluebutton-html5/app/client/main.coffee
index 0bb320728738052fdfc111dc98fb15dd8954e0dd..cec262d87a475ac47589c3e228d73c349f2ebfd6 100755
--- a/bigbluebutton-html5/app/client/main.coffee
+++ b/bigbluebutton-html5/app/client/main.coffee
@@ -7,84 +7,6 @@ safariIconPath = 'M16.154,5.135c-0.504,0-1,0.031-1.488,0.089l-0.036-0.18c-0.021-
 # RaphaelJS "Internet Explorer" icon
 ieIconPath = 'M27.998,2.266c-2.12-1.91-6.925,0.382-9.575,1.93c-0.76-0.12-1.557-0.185-2.388-0.185c-3.349,0-6.052,0.985-8.106,2.843c-2.336,2.139-3.631,4.94-3.631,8.177c0,0.028,0.001,0.056,0.001,0.084c3.287-5.15,8.342-7.79,9.682-8.487c0.212-0.099,0.338,0.155,0.141,0.253c-0.015,0.042-0.015,0,0,0c-2.254,1.35-6.434,5.259-9.146,10.886l-0.003-0.007c-1.717,3.547-3.167,8.529-0.267,10.358c2.197,1.382,6.13-0.248,9.295-2.318c0.764,0.108,1.567,0.165,2.415,0.165c5.84,0,9.937-3.223,11.399-7.924l-8.022-0.014c-0.337,1.661-1.464,2.548-3.223,2.548c-2.21,0-3.729-1.211-3.828-4.012l15.228-0.014c0.028-0.578-0.042-0.985-0.042-1.436c0-5.251-3.143-9.355-8.255-10.663c2.081-1.294,5.974-3.209,7.848-1.681c1.407,1.14,0.633,3.533,0.295,4.518c-0.056,0.254,0.24,0.296,0.296,0.057C28.814,5.573,29.026,3.194,27.998,2.266zM13.272,25.676c-2.469,1.475-5.873,2.539-7.539,1.289c-1.243-0.935-0.696-3.468,0.398-5.938c0.664,0.992,1.495,1.886,2.473,2.63C9.926,24.651,11.479,25.324,13.272,25.676zM12.714,13.046c0.042-2.435,1.787-3.49,3.617-3.49c1.928,0,3.49,1.112,3.49,3.49H12.714z'
 
-@displayWebRTCNotification = ->
-  if getInSession('webrtc_notification_is_displayed') is false # prevents the notification from displaying until the previous one is hidden
-    if !isWebRTCAvailable() # verifies if the browser supports WebRTC
-      $('.notification').addClass('webrtc-support-notification')
-      setInSession 'webrtc_notification_is_displayed', true
-      pp = new Raphael('browser-icon-container', 35, 35)
-      if getBrowserName() is 'Safari'
-        pp.path(safariIconPath).attr({fill: "#000", stroke: "none"})
-        $('#notification-text').html("Sorry,<br/>Safari doesn't support WebRTC")
-      else if getBrowserName() is 'IE'
-        pp.path(ieIconPath).attr({fill: "#000", stroke: "none"})
-        $('#notification-text').html("Sorry,<br/>IE doesn't support WebRTC")
-      else
-        pp.path(settingsIconPath).attr({fill: "#000", stroke: "none"})
-        $('.notification.ui-widget-content p').css('font-size', '11px') # to make sure the text fits the dialog box
-        $('#notification-text').html("Sorry,<br/>your browser doesn't support WebRTC")
-      $('#notification').dialog('open')
-      setTimeout () -> # waits 2 sec, then hides the notification
-        $('#notification').dialog('close')
-        $('.joinAudioButton').blur()
-        setTimeout () -> # waits 0.5 sec (time to hide the notification), then removes the icons
-          pp.remove()
-          $('.notification').removeClass('webrtc-support-notification')
-          setInSession 'webrtc_notification_is_displayed', false
-        , 500
-      , 2000
-    else
-      if !BBB.amIInAudio()
-        Tracker.autorun (comp) ->
-          if BBB.amIInAudio() # display notification when you are in audio
-            $('#notification').addClass('joined-audio-notification')
-            $("#browser-icon-container").remove() # remove the space taken up by the unused icon
-            setInSession 'webrtc_notification_is_displayed', true
-
-            if BBB.amIListenOnlyAudio() # notify the type of audio joined
-              $('#notification-text').html("You've joined the Listen Only Audio")
-            else
-              $('#notification-text').html("You've joined the audio")
-            
-            $('#notification').dialog('open')
-            setTimeout () ->
-              $('#notification').dialog('close') # close the entire notification
-              $('.joinAudioButton').blur()
-              setTimeout () ->
-                setInSession 'webrtc_notification_is_displayed', false
-              , 500
-            , 3000
-            comp.stop()
-
-# this method gets called from either mobile or desktop UI
-# this method will adjust the UI to compensate for the new audio button
-displayAudioSelectionMenu = ({isMobile} = {}) ->
-  isMobile ?= false
-  $('.joinAudioButton').blur()
-
-  if isMobile
-    toggleSlidingMenu()
-    $('.navbarTitle').css('width', '55%')
-
-  # pop open the dialog allowing users to choose the audio options
-  if isLandscapeMobile()
-    $('.joinAudio-dialog').addClass('landscape-mobile-joinAudio-dialog')
-  else
-    $('.joinAudio-dialog').addClass('desktop-joinAudio-dialog')
-
-  $("#joinAudioDialog").dialog("open")
-
-
-# helper function to reuse some code for the handling of audio join
-onAudioJoinHelper = () ->
-  # if the microphone is locked (lock settings), the viewer is only
-  # allowed to join the audio as listenOnly.
-  if BBB.isMyMicLocked()
-    introToAudio(null, isListenOnly: true)
-  else
-    displayAudioSelectionMenu(isMobile: isMobile())
-
-
 # Helper to load javascript libraries from the BBB server
 loadLib = (libname) ->
   successCallback = ->
@@ -97,6 +19,8 @@ loadLib = (libname) ->
 
 # These settings can just be stored locally in session, created at start up
 Meteor.startup ->
+
+
   # Load SIP libraries before the application starts
   loadLib('sip.js')
   loadLib('bbb_webrtc_bridge_sip.js')
@@ -121,8 +45,55 @@ Template.footer.helpers
     foot = "(c) #{info.copyrightYear} BigBlueButton Inc. [build #{info.bbbServerVersion} - #{info.dateOfBuild}] - For more information visit #{info.link}"
 
 Template.header.events
-  "click .joinAudioButton": (event) ->
-    onAudioJoinHelper()
+  "click .audioFeedIcon": (event) ->
+    if getInSession('webrtc_notification_is_displayed') is false # prevents the notification from displaying until the previous one is hidden
+      if !isWebRTCAvailable() # verifies if the browser supports WebRTC
+        $('.notification').addClass('webrtc-support-notification')
+        setInSession 'webrtc_notification_is_displayed', true
+        pp = new Raphael('browser-icon-container', 35, 35)
+        if getBrowserName() is 'Safari'
+          pp.path(safariIconPath).attr({fill: "#000", stroke: "none"})
+          $('#notification-text').html("Sorry,<br/>Safari doesn't support WebRTC")
+        else if getBrowserName() is 'IE'
+          pp.path(ieIconPath).attr({fill: "#000", stroke: "none"})
+          $('#notification-text').html("Sorry,<br/>IE doesn't support WebRTC")
+        else
+          pp.path(settingsIconPath).attr({fill: "#000", stroke: "none"})
+          $('.notification.ui-widget-content p').css('font-size', '11px') # to make sure the text fits the dialog box
+          $('#notification-text').html("Sorry,<br/>your browser doesn't support WebRTC")
+        $('#notification').dialog('open')
+        setTimeout () -> # waits 2 sec, then hides the notification
+          $('#notification').dialog('close')
+          $('.audioFeedIcon').blur()
+          setTimeout () -> # waits 0.5 sec (time to hide the notification), then removes the icons
+            pp.remove()
+            $('.notification').removeClass('webrtc-support-notification')
+            setInSession 'webrtc_notification_is_displayed', false
+          , 500
+        , 2000
+      else
+        if !BBB.amISharingAudio()
+          Tracker.autorun (comp) ->
+            if BBB.amISharingAudio()
+              $('.notification').addClass('joined-audio-notification')
+              setInSession 'webrtc_notification_is_displayed', true
+              $('#notification-text').html("You've joined the audio")
+              $('#notification').dialog('open')
+              setTimeout () ->
+                $('#notification').dialog('close')
+                $('.audioFeedIcon').blur()
+                setTimeout () ->
+                  $('.notification').removeClass('joined-audio-notification')
+                  setInSession 'webrtc_notification_is_displayed', false
+                , 500
+              , 2000
+              comp.stop()
+    $('.audioFeedIcon').blur()
+    toggleVoiceCall @
+    if BBB.amISharingAudio()
+      $('.navbarTitle').css('width', $('#navbar').width() - 358.4)
+    else
+      $('.navbarTitle').css('width', $('#navbar').width() - 409.6)
 
   "click .chatBarIcon": (event) ->
     $(".tooltip").hide()
@@ -143,9 +114,6 @@ Template.header.events
     $(".tooltip").hide()
     toggleNavbar()
 
-  "click .leaveAudioButton": (event) ->
-    exitVoiceCall event
-
   "click .lowerHand": (event) ->
     $(".tooltip").hide()
     Meteor.call('userLowerHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken"))
@@ -155,10 +123,11 @@ Template.header.events
     toggleMic @
 
   "click .raiseHand": (event) ->
+    #Meteor.log.info "navbar raise own hand from client"
+    console.log "navbar raise own hand from client"
     $(".tooltip").hide()
     Meteor.call('userRaiseHand', getInSession("meetingId"), getInSession("userId"), getInSession("userId"), getInSession("authToken"))
-
-  # "click .settingsIcon": (event) ->
+    # "click .settingsIcon": (event) ->
     #   alert "settings"
 
   "click .signOutIcon": (event) ->
@@ -168,10 +137,11 @@ Template.header.events
     else
       $('.logout-dialog').addClass('desktop-logout-dialog')
     $("#dialog").dialog("open")
-
   "click .hideNavbarIcon": (event) ->
     $(".tooltip").hide()
     toggleNavbar()
+  # "click .settingsIcon": (event) ->
+  #   alert "settings"
 
   "click .usersListIcon": (event) ->
     $(".tooltip").hide()
@@ -194,8 +164,14 @@ Template.header.events
     $("#navbarMinimizedButton").addClass("navbarMinimizedButtonLarge")
 
 Template.slidingMenu.events
-  'click .joinAudioButton': (event) ->
-    onAudioJoinHelper()
+  'click .audioFeedIcon': (event) ->
+    $('.audioFeedIcon').blur()
+    toggleSlidingMenu()
+    toggleVoiceCall @
+    if BBB.amISharingAudio()
+      $('.navbarTitle').css('width', '70%')
+    else
+      $('.navbarTitle').css('width', '55%')
 
   'click .chatBarIcon': (event) ->
     $('.tooltip').hide()
@@ -228,46 +204,11 @@ Template.slidingMenu.events
     toggleSlidingMenu()
     $('.collapseButton').blur()
 
-  "click .leaveAudioButton": (event) ->
-    exitVoiceCall event
-    toggleSlidingMenu()
-
 Template.main.helpers
-  setTitle: ->
-    document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}"
+	setTitle: ->
+		document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}"
 
 Template.main.rendered = ->
-  # the initialization code for the dialog presenting the user with microphone+listen only options
-  $("#joinAudioDialog").dialog(
-    modal: true
-    draggable: false
-    resizable: false
-    autoOpen: false
-    dialogClass: 'no-close logout-dialog joinAudioDialog'
-    buttons: [
-      {
-        text: 'Cancel'
-        click: () ->
-          $(this).dialog("close")
-          $(".tooltip").hide()
-        class: 'btn btn-xs btn-default joinAudioDialogButton'
-      }
-    ]
-    open: (event, ui) ->
-      $('.ui-widget-overlay').bind 'click', () ->
-        if isMobile()
-          $("#joinAudioDialog").dialog('close')
-    position: { my: "center", at: "center", of: window }
-  )
-
-  # jQuery click events are handled here. Meteor click handlers don't get called.
-  # we pass in a named boolean parameter the whether we wish to join audio as listen only or not
-  $("#microphone").click ->
-    introToAudio @, isListenOnly: false
-
-  $("#listen_only").click ->
-    introToAudio @, isListenOnly: true
-
   $("#dialog").dialog(
     modal: true
     draggable: false
@@ -316,20 +257,16 @@ Template.main.rendered = ->
     position:
       my: 'left top'
       at: 'left bottom'
-      of: '.joinAudioButton'
+      of: '.audioFeedIcon'
   )
 
   $(window).resize( ->
     $('#dialog').dialog('close')
-    $('#joinAudioDialog').dialog('close')
   )
 
   $('#shield').click () ->
     toggleSlidingMenu()
 
-  if Meteor.config.app.autoJoinAudio
-    onAudioJoinHelper()
-
 Template.makeButton.rendered = ->
   $('button[rel=tooltip]').tooltip()
 
diff --git a/bigbluebutton-html5/app/client/main.html b/bigbluebutton-html5/app/client/main.html
index c9ca307b9bbda94ef203aded8b6f6728999787d0..aa5828201191b56ad85513d7f558cb5f01e0b71c 100755
--- a/bigbluebutton-html5/app/client/main.html
+++ b/bigbluebutton-html5/app/client/main.html
@@ -1,7 +1,7 @@
 <template name="footer">
-  <div id="footer" class="myFooter gradientBar navbar-default">
-    {{{getFooterString}}}
-  </div>
+   <div id="footer" class="myFooter gradientBar navbar-default">
+      {{{getFooterString}}}
+   </div>
 </template>
 
 <template name="header">
@@ -9,7 +9,7 @@
     <div id="navbar" class="myNavbar gradientBar navbar navbar-default navbar-fixed-top" role="navigation">
       <div class="navbarUserButtons navbarSection">
         <div id="collapseButtonSection">
-          {{#if isPortraitMobile}}
+          {{#if isMobile}}
             <button class="navbar-toggle btn navbarButton collapseSlidingMenuButton">
               <div class="push-menu-icon">
                 <span class="icon-bar"></span>
@@ -36,9 +36,9 @@
 
             <!-- display/hide whiteboard toggle -->
             {{#if getInSession "display_whiteboard"}}
-              {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
+              {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
             {{else}}
-              {{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
+              {{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
             {{/if}}
 
             <!-- display/hide chat bar toggle -->
@@ -56,26 +56,20 @@
                  {{/if}} -->
           </div>
           <div class='audioControllersSection'>
-            <!-- We are in a form of audio -->
-            {{#if amIInAudio}}
+            <!-- Join/hang up audio call -->
+            {{#if isCurrentUserSharingAudio}}
               <div class='hiddenNavbarSection'>
-                <!-- display the button for leaving audio -->
                 {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon navbarButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
               </div>
-              {{#unless amIListenOnlyAudio}}
-                {{#if isCurrentUserMuted}}
-                  <!-- if you are muted the button representing your status will show volume off -->
-                  {{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}}
+              {{#if isCurrentUserMuted}}
+                {{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}}
+              {{else}}
+                {{#if isCurrentUserTalking}}
+                  {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
                 {{else}}
-                  {{#if isCurrentUserTalking}}
-                    <!-- you are talking. Display a high volume/volume up representing voice activity -->
-                    {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
-                  {{else}}
-                    <!-- you are not talking. Display low volume/volume down representing no voice activity -->
-                    {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
-                  {{/if}}
+                  {{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
                 {{/if}}
-              {{/unless}}
+              {{/if}}
             {{else}}
               <div class='hiddenNavbarSection'>
                 {{> makeButton btn_class="audioFeedIcon navbarButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
@@ -96,6 +90,7 @@
       <div class="navbarTitle navbarSection"><span>{{getMeetingName}}</span></div>
       <div class="navbarSettingsButtons navbarSection">
         <!-- {{> makeButton id="userId" btn_class="settingsIcon navbarButton" i_class="glyphicon glyphicon-cog" rel="tooltip" data_placement="bottom" title="Settings"}} -->
+        <!-- {{> makeButton btn_class="hideNavbarIcon navbarButton" i_class="glyphicon glyphicon-chevron-up" rel="tooltip" data_placement="bottom" title="Hide Navbar"}} -->
         {{> makeButton btn_class="signOutIcon navbarButton" i_class="glyphicon glyphicon-log-out" rel="tooltip" data_placement="bottom" title="Logout"}}
       </div>
     </div>
@@ -104,83 +99,56 @@
     {{> makeButton id="navbarMinimizedButton" btn_class="hideNavbarIcon navbarMinimizedButtonSmall" i_class="glyphicon glyphicon-chevron-down" rel="tooltip" data_placement="bottom" title="Display Navbar"}}
   {{/if}}
 </template>
-<!-- dialog that presents user with audio options
-     contains microphone and listen only with icons -->
-<template name="joinAudioDialog">
-  <div id="joinAudioDialog" title="How do you want to join the audio?">
-    <hr class="joinAudioDialogHr"/>
-    <div style="float:left; border-right: 2px solid darkgrey; width: 50%; height: 100%">
-      <i class="icon ion-mic-a joinAudioDialogIcon"></i>
-      <br/>
-      <button id="microphone" class="joinAudioDialogButton">Microphone</button>
-    </div>
-    <div style="float:left; width: 50%">
-      <i class="icon ion-volume-high joinAudioDialogIcon"></i>
-      <br/>
-      <button id="listen_only" class="joinAudioDialogButton">Listen Only</button>
-    </div>
-    <br style="clear:both;"/><br/>
-    <hr style="margin: 10px; border: 1px solid darkgrey;" />
-  </div>
-</template>
 
 <template name="main">
-  {{setTitle}}
-  <body>
-    <div id="dialog" title="Confirm Logout">
+{{setTitle}}
+<body>
+  <div id="dialog" title="Confirm Logout">
       <p>Are you sure you want to log out?</p>
-    </div>
-    {{> joinAudioDialog}}
-    <div id="notification">
+  </div>
+  <div id="notification">
       <div id="browser-icon-container"></div>
       <p id="notification-text"></p>
-    </div>
-
-    <div id="main" class="mainContainer row-fluid">
-      {{#if isDisconnected}}
-        {{>status}}
-      {{else}}
-        <div>{{> header}}</div>
-        {{> whiteboard id="whiteboard" title=getWhiteboardTitle name="whiteboard"}}
-        {{> chatbar id="chat" title="Chat" name="chatbar"}}
-        {{> usersList id="users" name="usersList"}}
-        <audio id="remote-media" autoplay="autoplay"></audio>
-        {{> footer}}
-      {{/if}}
-      <div id='shield'></div>
-    </div>
-    {{#if isPortraitMobile}}
-      {{> slidingMenu}}
+  </div>
+  <div id="main" class="mainContainer row-fluid">
+    {{#if isDisconnected}}
+      {{>status}}
+    {{else}}
+      <div>{{> header}}</div>
+      {{> whiteboard id="whiteboard" title=getWhiteboardTitle name="whiteboard"}}
+      {{> chatbar id="chat" title="Chat" name="chatbar"}}
+      {{> usersList id="users" name="usersList"}}
+      <audio id="remote-media" autoplay="autoplay"></audio>
+      {{> footer}}
     {{/if}}
-  </body>
+    <div id='shield'></div>
+  </div>
+  {{#if isMobile}}
+    {{> slidingMenu}}
+  {{/if}}
+</body>
 </template>
 
 <template name="recordingStatus">
-  <!-- Recording status of the meeting -->
-  {{#with getCurrentMeeting}}
-    {{#if intendedForRecording}}
-      {{#if currentlyBeingRecorded}}
-        <button class="recordingStatus recordingStatusTrue" rel="tooltip" data-placement="bottom" title="This Meeting is Being Recorded"><span class="glyphicon glyphicon-record"></span> Recording</button>
-      {{else}}
-        <button class="recordingStatus recordingStatusFalse" rel="tooltip" data-placement="bottom" title="This Meeting is Not Currently Being Recorded"><span class="glyphicon glyphicon-record"></span></button>
-      {{/if}}
-    {{/if}}
-  {{/with}}
+	<!-- Recording status of the meeting -->
+	{{#with getCurrentMeeting}}
+		{{#if intendedForRecording}}
+			{{#if currentlyBeingRecorded}}
+				<button class="recordingStatus recordingStatusTrue" rel="tooltip" data-placement="bottom" title="This Meeting is Being Recorded"><span class="glyphicon glyphicon-record"></span> Recording</button>
+			{{else}}
+				<button class="recordingStatus recordingStatusFalse" rel="tooltip" data-placement="bottom" title="This Meeting is Not Currently Being Recorded"><span class="glyphicon glyphicon-record"></span></button>
+			{{/if}}
+		{{/if}}
+	{{/with}}
 </template>
 
 <template name='slidingMenu'>
   <div class="sliding-menu" id="sliding-menu">
     <div class="slideSection">
-      {{#if getInSession "display_usersList"}}
-        {{> makeButton btn_class="navbarIconToggleActive usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Hide List of Users"}}
-      {{else}}
-        {{> makeButton btn_class="usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Show List of Users"}}
-      {{/if}}
-
       {{#if getInSession "display_whiteboard"}}
-        {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Hide Whiteboard"}}
+        {{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Hide Whiteboard"}}
       {{else}}
-        {{> makeButton btn_class="whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Show Whiteboard"}}
+        {{> makeButton btn_class="whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Show Whiteboard"}}
       {{/if}}
 
       {{#if getInSession "display_chatbar"}}
@@ -189,10 +157,16 @@
         {{> makeButton btn_class="chatBarIcon slideButton" i_class="glyphicon glyphicon-comment" rel="tooltip" data_placement="right" title="Show Message Pane"}}
       {{/if}}
 
-      {{#if amIInAudio}}
-        {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
+      {{#if getInSession "display_usersList"}}
+        {{> makeButton btn_class="navbarIconToggleActive usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Hide List of Users"}}
+      {{else}}
+        {{> makeButton btn_class="usersListIcon slideButton" i_class="glyphicon glyphicon-user" rel="tooltip" data_placement="right" title="Show List of Users"}}
+      {{/if}}
+
+      {{#if isCurrentUserSharingAudio}}
+        {{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="right" title="Leave Audio Call"}}
       {{else}}
-        {{> makeButton btn_class="audioFeedIcon slideButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
+        {{> makeButton btn_class="audioFeedIcon slideButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="right" title="Join Audio Call"}}
       {{/if}}
 
       {{#if isCurrentUserRaisingHand}}
diff --git a/bigbluebutton-html5/app/client/stylesheets/chat.less b/bigbluebutton-html5/app/client/stylesheets/chat.less
index 1407d1b95c8f693872186cb99d6e135d03f20794..1ee07825ecd5ca74076ed64d77072ac86eed4315 100755
--- a/bigbluebutton-html5/app/client/stylesheets/chat.less
+++ b/bigbluebutton-html5/app/client/stylesheets/chat.less
@@ -1,9 +1,9 @@
 @import "variables";
 
 .active {
-  border: .2vh solid !important;
+  border: .2vh solid extract(@azure, 2) !important;
   @media @mobile-portrait-with-keyboard, @mobile-portrait {
-    border-left: .1vh solid !important;
+    border-left: .1vh solid extract(@azure, 2) !important;
   }
 }
 
@@ -76,18 +76,6 @@
 .chatNameSelectorPrivate {
   .chatNameSelector;
   width:90%;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  @media @landscape {
-    height: 20px;
-  }
-  @media @desktop-portrait {
-    height: 25px;
-  }
-  @media @mobile-portrait, @mobile-portrait-with-keyboard {
-    font-size: 4vw;
-  }
 }
 
 .chatNameSelectorPublic {
@@ -96,6 +84,12 @@
   width:100%;
 }
 
+.chatOptionsText {
+  @media @mobile-portrait, @mobile-portrait-with-keyboard {
+    font-size: 5vw;
+  }
+}
+
 .close:hover {
   background-color: red;
 }
@@ -119,12 +113,6 @@
   padding: 5px;
 }
 
-
-.disabledChat {
-  background-color: grey;
-  width: 100% !important;
-}
-
 .dropdown {
   float: left;
   @media @desktop-portrait, @mobile-portrait, @mobile-portrait-with-keyboard {
@@ -140,15 +128,13 @@
   }
 }
 
-#fontSizeTable {
-  /* Static font sizes are used everywhere in this control. This is the maximum amount of space required */
-  height: 64px;
-  #displayButtons {
-    text-align:center;
-    width:84px;
+#fontSizeControl {
+  @media @mobile-portrait, @mobile-portrait-with-keyboard {
+    font-size:7vw;
   }
-  #displayLabel {
-    width: 154px;
+  .fontSizeLabel {
+    height:30px;
+    text-align:center;
   }
 }
 
@@ -156,6 +142,13 @@
   background: extract(@yellow, 2) !important;
 }
 
+#increaseFontSize, #decreaseFontSize {
+  @media @mobile-portrait, @mobile-portrait-with-keyboard {
+    height: 100px;
+    width: 100px;
+  }
+}
+
 #MoreChatsDrop {
   float: right;
 }
@@ -292,7 +285,7 @@
 
   &:hover {
     background-color: #ddd;
-    border: 1px solid;
+    border: 1px solid extract(@azure, 2);
     border-bottom: none;
   }
 }
diff --git a/bigbluebutton-html5/app/client/stylesheets/style.less b/bigbluebutton-html5/app/client/stylesheets/style.less
index 7920a4ac22c7d7b7198ded9a6864c5b6a5549410..9a86b20aa9b5cf01b6e16796d98ac8dca2997667 100755
--- a/bigbluebutton-html5/app/client/stylesheets/style.less
+++ b/bigbluebutton-html5/app/client/stylesheets/style.less
@@ -41,10 +41,6 @@ body {
   overflow-x: hidden;
 }
 
-.heading {
-  margin-left:5px 
-}
-
 .mainContainer {
   height: 95%;
 }
@@ -54,7 +50,6 @@ body {
   color: black;
   padding-top: 13px;
   text-align: center;
-  background-color: #EEEEEE;
   @media @landscape {
     position:fixed;
     bottom:0;
@@ -70,13 +65,13 @@ body {
     font-size: 2vw;
   }
 
-  /*the footer should be visible only at the very bottom of a portrait page*/
+  // the footer should be visible only at the very bottom of a portrait page
   @media @desktop-portrait, @mobile-portrait {
     order: 4;
     -webkit-order: 4;
   }
   @media @mobile-portrait-with-keyboard {
-    display: none; /*hide when typing*/
+    display: none; //hide when typing
   }
 }
 
@@ -88,6 +83,8 @@ body {
   }
   .btn {
     .linear-gradient(rgb(72,76,85), rgb(65,68,77));
+    border-left: 1px solid extract(@darkGrey, 2);
+    border-right: 1px solid extract(@darkGrey, 4);
     &.navbarIconToggleActive {
       background: extract(@darkGrey, 3);
       border-bottom: 4px solid extract(@azure, 1);
@@ -217,7 +214,7 @@ body {
     display: block;
     float: left;
     &:hover {
-      background: extract(@darkGrey, 4);
+      background: extract(@darkGrey, 3);
     }
   }
   @media @landscape {
@@ -226,7 +223,7 @@ body {
 }
 
 .navbarSettingsButtons .btn:hover {
-  background: extract(@darkGrey, 4);
+  background: extract(@darkGrey, 3);
 }
 
 .panel-footer {
@@ -323,6 +320,77 @@ body {
   }
 }
 
+/* Custom alert box */
+
+/* Logout menu's properties on mobile devices in landscape orientation */
+.landscape-mobile-logout-dialog {
+  @media @landscape {
+    .ui-widget-header {
+      font-size: 100% !important;
+    }
+    width: 55% !important; /* overriding "width: auto;" */
+    font-size: 3vh !important; /* overriding "font-size: 11px;" */
+    .ui-dialog-content {
+      height: 30% !important; /* overriding "height: auto;" */
+    }
+    .ui-dialog-buttonset {
+      width: 100%;
+      font-size: 4vh;
+      button {
+        width: 40%;
+        margin-left: 5% !important;
+        margin-right: 5% !important;
+      }
+    }
+    height: 32% !important;
+  }
+}
+
+/* Logout menu's properties on desktop */
+.desktop-logout-dialog {
+  @media @desktop-portrait, @landscape {
+    .ui-dialog-content {
+      height: 36px !important; /* overriding "height: auto;" */
+    }
+  }
+}
+
+.no-close .ui-dialog-titlebar-close {
+  display: none; /* no close button */
+}
+
+.logout-dialog.ui-dialog {
+  .ui-widget-header {
+    color: extract(@white, 1);
+    font-weight: bold;
+    background: extract(@darkGrey, 3);
+    @media @desktop-portrait, @landscape {
+      font-size: 12px;
+    }
+  }
+  .ui-dialog-content {
+    font-weight: bold;
+    text-align: center;
+    @media @desktop-portrait, @landscape {
+      min-height: 0px !important; /* overriding "min-height: 47px;"*/
+    }
+  }
+  @media @mobile-portrait-with-keyboard, @mobile-portrait {
+    width: 100% !important;
+  }
+}
+
+.logout-dialog.ui-widget-content {
+  background: extract(@white, 3);
+  border: 5px solid extract(@darkGrey, 3);
+  @media @desktop-portrait, @landscape {
+    font-size: 11px;
+  }
+  @media @mobile-portrait-with-keyboard, @mobile-portrait {
+    font-size: 280%;
+  }
+}
+
 .ui-widget-overlay {
   z-index: 1031;
 }
@@ -378,7 +446,7 @@ body {
   }
 }
 
-.glyphicon, .ion-android-hand, .ion-easel {
+.glyphicon, .ion-android-hand {
   @media @mobile-portrait-with-keyboard, @mobile-portrait {
     font-size: 35px;
   }
@@ -395,7 +463,7 @@ body {
 
 .narrowedNavbarTitle {
   @media @desktop-portrait {
-    width: calc(~'100% - 410px') !important;
+    width: calc(~'100% - 358.4px') !important;
   }
 }
 
@@ -466,6 +534,8 @@ body {
     }
     .btn {
       .linear-gradient(rgb(72,76,85), rgb(65,68,77));
+      border-left: 1px solid extract(@darkGrey, 2);
+      border-right: 1px solid extract(@darkGrey, 4);
       &.navbarIconToggleActive {
         background: extract(@darkGrey, 3);
         border-bottom: 4px solid extract(@azure, 1);
@@ -511,11 +581,12 @@ body {
 
   background: grey;
   &.webrtc-support-notification {
-    width: 500px !important;
+    width: 300px !important;
     height: 50px !important;
   }
   &.joined-audio-notification {
-    width: 500px !important;
+    width: 200px !important;
+    height: 32px !important;
     #browser-icon-container {
       display: none;
     }
@@ -528,6 +599,7 @@ body {
   &.ui-widget-content p {
     color: black;
     font-size: 14px;
+    height: 35px;
     margin: 0;
     padding: 1px;
   }
@@ -557,103 +629,3 @@ body {
 .invisible {
   display: none;
 }
-
-/* Custom alert box */
-/* Logout menu's properties on mobile devices in landscape orientation */
-.landscape-mobile-logout-dialog {
-  @media @landscape {
-    .ui-widget-header {
-      font-size: 100% !important;
-    }
-    width: 55% !important; /* overriding "width: auto;" */
-    font-size: 3vh !important; /* overriding "font-size: 11px;" */
-    .ui-dialog-content {
-      height: 30% !important; /* overriding "height: auto;" */
-    }
-    .ui-dialog-buttonset {
-      width: 100%;
-      font-size: 4vh;
-      button {
-        width: 40%;
-        margin-left: 5% !important;
-        margin-right: 5% !important;
-      }
-    }
-    height: 32% !important;
-  }
-}
-
-/* Logout menu's properties on desktop */
-.desktop-logout-dialog {
-  @media @desktop-portrait, @landscape {
-    .ui-dialog-content {
-      height: 36px !important; /* overriding "height: auto;" */
-    }
-  }
-}
-
-.no-close .ui-dialog-titlebar-close {
-  display: none; /* no close button */
-}
-
-.logout-dialog.ui-dialog {
-  .ui-widget-header {
-    color: extract(@white, 1);
-    font-weight: bold;
-    background: extract(@darkGrey, 3);
-    @media @desktop-portrait, @landscape {
-      font-size: 12px;
-    }
-  }
-  .ui-dialog-content {
-    font-weight: bold;
-    text-align: center;
-    @media @desktop-portrait, @landscape {
-      min-height: 0px !important; /* overriding "min-height: 47px;"*/
-    }
-  }
-  @media @mobile-portrait-with-keyboard, @mobile-portrait {
-    width: 100% !important;
-  }
-}
-
-.logout-dialog.ui-widget-content {
-  background: extract(@white, 3);
-  border: 5px solid extract(@darkGrey, 3);
-  @media @desktop-portrait, @landscape {
-    font-size: 11px;
-  }
-  @media @mobile-portrait-with-keyboard, @mobile-portrait {
-    font-size: 280%;
-  }
-}
-
-.joinAudioDialog {
-  min-width: 500px;
-  width: 25% !important;
-}
-#joinAudioDialog {
-  background-color: rgb(239, 239, 239);
-  display: none;
-}
-.joinAudioDialogButton {
-  background: -webkit-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Safari 5.1 to 6.0 */
-  background: -o-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Opera 11.1 to 12.0 */
-  background: -moz-linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* For Firefox 3.6 to 15 */
-  background: linear-gradient(rgb(255,255,255), rgb(225,226,229)); /* Standard syntax (must be last) */
-  border-radius: 5px;
-  color: rgb(94,95,99);
-  font-weight: bold;
-  padding: 10px;
-}
-.joinAudioDialogHr {
-  border: 1px solid darkgrey;
-  margin: 10px; 
-  margin-bottom:5px; 
-}
-.joinAudioDialogIcon {
-  font-size: 100px;
-}
-.ui-dialog-titlebar {
-  text-align: center;
-}
diff --git a/bigbluebutton-html5/app/client/stylesheets/users.less b/bigbluebutton-html5/app/client/stylesheets/users.less
index 9095fb7eefad5532190063d31c0cf9459288b80d..874b7f5634efc20f4084ea1dd81c326453015c7f 100755
--- a/bigbluebutton-html5/app/client/stylesheets/users.less
+++ b/bigbluebutton-html5/app/client/stylesheets/users.less
@@ -2,9 +2,6 @@
 
 #content {
   margin-top: 10px;
-  &:first-child {
-    margin-top: 0px;
-  }
   overflow: hidden;
   width: 100%;
   @media @mobile-portrait, @mobile-portrait-with-keyboard {
diff --git a/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee b/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee
index eb766d65107e99f6f8ced792eab62fafe0829d41..625df4acf83a76f704c2b010ec2751121ab185e7 100755
--- a/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee
+++ b/bigbluebutton-html5/app/client/views/chat/chat_bar.coffee
@@ -65,24 +65,6 @@ Handlebars.registerHelper "grabChatTabs", ->
     setInSession 'chatTabs', initTabs
   getInSession('chatTabs')[0..3]
 
-# true if the lock settings limit public chat and the current user is locked
-Handlebars.registerHelper "publicChatDisabled", ->
-  userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked
-  publicChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePubChat
-  presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter
-  return userIsLocked and publicChatIsDisabled and !presenter
-
-# true if the lock settings limit private chat and the current user is locked
-Handlebars.registerHelper "privateChatDisabled", ->
-  userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked
-  privateChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePrivChat
-  presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter
-  return userIsLocked and privateChatIsDisabled and !presenter
-
-# return whether the user's chat pane is open in Private chat (vs Public chat or Options)
-Handlebars.registerHelper "inPrivateChat", ->
-  return !((getInSession 'inChatWith') in ['PUBLIC_CHAT', 'OPTIONS'])
-
 @sendMessage = ->
   message = linkify $('#newMessageInput').val() # get the message from the input box
   unless (message?.length > 0 and (/\S/.test(message))) # check the message has content and it is not whitespace
diff --git a/bigbluebutton-html5/app/client/views/chat/chat_bar.html b/bigbluebutton-html5/app/client/views/chat/chat_bar.html
index 691352fb23c7dde7e299bd6841cc587fa57fb0aa..c99e4d04272a7bd0ff4227c5a59fa1245dba2bc5 100755
--- a/bigbluebutton-html5/app/client/views/chat/chat_bar.html
+++ b/bigbluebutton-html5/app/client/views/chat/chat_bar.html
@@ -1,90 +1,76 @@
 <template name="chatbar">
-  <div id="{{id}}" {{visibility name}} class="component">
-    <h3 class="title gradientBar">
-    <span class="glyphicon glyphicon-comment heading"></span>
-    {{> extraConversations}}
-    </h3>
-    {{>tabButtons}} <!-- Display public/options tabs, and private chat tabs -->
-    {{#if getInSession "display_chatPane"}}
-      <div id="chatbody">
-        <ul class="chat" {{messageFontSize}}>
-          {{#each getCombinedMessagesForChat}}
-            {{#if message}}
-              <li>{{> message}}</li>
+    <div id="{{id}}" {{visibility name}} class="component">
+        <h3 class="title gradientBar">
+        <span class="glyphicon glyphicon-comment"></span>
+        {{title}}
+        {{> extraConversations}}
+        </h3>
+        {{>tabButtons}} <!-- Display public/options tabs, and private chat tabs -->
+        {{#if getInSession "display_chatPane"}}
+            <div id="chatbody">
+                <ul class="chat" {{messageFontSize}}>
+                    {{#each getCombinedMessagesForChat}}
+                        {{#if message}}
+                            <li>{{> message}}</li>
+                        {{/if}}
+                    {{/each}}
+                    {{#unless userExists}}<li>The user has left</li>{{/unless}}
+                </ul>
+            </div>
+            {{#if userExists}}
+                <div class="panel-footer">{{> chatInput}}</div> 
             {{/if}}
-          {{/each}}
-          {{#unless userExists}}<li>The user has left</li>{{/unless}}
-        </ul>
-      </div>
-      {{#if userExists}}
-        <div class="panel-footer">{{> chatInput}}</div> 
-      {{/if}}
-    {{else}}
-      {{> optionsBar}}
-    {{/if}}
-  </div>
+        {{else}}
+            {{> optionsBar}}
+        {{/if}}
+    </div>
 </template>
 
 <template name="chatInput">
-  <div id="chatInput" class="chat-input-wrapper">
-    {{#if inPrivateChat}}
-      {{#if privateChatDisabled}}
-        <textarea id="newMessageInput" class="disabledChat" placeholder="Private chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Private chat is temporarily locked" disabled></textarea>
-      {{else}}
-        <textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
-        <button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top">
-        Send
-        </button>
-      {{/if}}
-    {{else}}
-      {{#if publicChatDisabled}}
-        <textarea id="newMessageInput" class="disabledChat" placeholder="Public chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Public chat is temporarily locked" disabled></textarea>
-      {{else}}
-        <textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
-        <button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top">
-        Send
-        </button>
-      {{/if}}
-    {{/if}}
-  </div>
+	<div id="chatInput" class="chat-input-wrapper">
+		<textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
+		<button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top" title="Click to send your message">
+		Send
+		</button>
+	</div>
 </template>
 
 <template name="chatOptions">
-  <p>Chat Options:</p>
-  {{> optionsFontSize}}
+	<p>Chat Options:</p>
+	{{> optionsFontSize}}
 </template>
 
 <template name="extraConversations">
-  {{#if tooManyConversations}}
-    <div id="MoreChatsDrop" class="btn-group">
-      <button type="button" id="MoreChatsbutton" class="btn btn-default dropdown-toggle" data-toggle="dropdown">More Chats<span class="caret"></span></button>
-      <ul class="dropdown-menu extraConversationScrollableMenu" role="menu">
-        {{#each getExtraConversations}}
-          <li class="extraConversation" id="{{safeName name}}"><a href="#">{{safeName name}}</a></li>
-        {{/each}}
-      </ul>
-    </div>
-  {{/if}}
+    {{#if tooManyConversations}}
+        <div id="MoreChatsDrop" class="btn-group">
+            <button type="button" id="MoreChatsbutton" class="btn btn-default dropdown-toggle" data-toggle="dropdown">More Chats<span class="caret"></span></button>
+            <ul class="dropdown-menu extraConversationScrollableMenu" role="menu">
+                {{#each getExtraConversations}}
+                    <li class="extraConversation" id="{{safeName name}}"><a href="#">{{safeName name}}</a></li>
+                {{/each}}
+            </ul>
+        </div>
+    {{/if}}
 </template>
 
 <!-- Displays and styles an individual message in the chat -->
 <template name="message">
-  <span style="float:left;">
-    {{#if message.from_username}}
-      <span class="userNameEntry" rel="tooltip" data-placement="bottom" title="{{message.from_username}}">
-        {{message.from_username}}
-      </span>
-    {{/if}}
-  </span>
-  <span style="float:right;">
-    {{#if message.from_time}}
-      <span {{messageFontSize}}>{{toClockTime message.from_time}}</span>
-      <span {{messageFontSize}} class="glyphicon glyphicon-time"></span>
-    {{/if}}
-  </span>
-  <br/>
-  <div style="color:{{colourToHex message.from_color}}">{{{sanitizeAndFormat message.message}}}</div>
-  {{autoscroll}}
+    <span style="float:left;">
+        {{#if message.from_username}}
+            <span class="userNameEntry" rel="tooltip" data-placement="bottom" title="{{message.from_username}}">
+                {{message.from_username}}
+            </span>
+        {{/if}}
+    </span>
+    <span style="float:right;">
+        {{#if message.from_time}}
+            <span {{messageFontSize}}>{{toClockTime message.from_time}}</span>
+            <span {{messageFontSize}} class="glyphicon glyphicon-time"></span>
+        {{/if}}
+    </span>
+    <br/>
+    <div style="color:{{colourToHex message.from_color}}">{{{sanitizeAndFormat message.message}}}</div>
+    {{autoscroll}}
 </template>
 
 <!-- Displays the list of options available -->
@@ -110,16 +96,12 @@
 </template>
 
 <template name="optionsFontSize">
-  <span class="chatOptionsText" >Chat Message Font Size: </span><br/>
-  <table id="fontSizeTable">
-    <tr>
-      <td id="displayButtons">
-        <button id="decreaseFontSize" class="glyphicon glyphicon-minus"></button>
-        <button id="increaseFontSize" class="glyphicon glyphicon-plus"></button>
-      </td >
-      <td id="displayLabel"><label class="fontSizeLabel" {{messageFontSize}} >Size({{getInSession "messageFontSize"}})</label></td>
-    </tr>
-  </table>
+  <div id="fontSizeControl">
+    <span class="chatOptionsText" >Chat Message Font Size: </span><br>
+    <button id="decreaseFontSize" class="glyphicon glyphicon-minus" ></button>
+    <label class="fontSizeLabel" {{messageFontSize}} >Size({{getInSession "messageFontSize"}})</label>
+    <button id="increaseFontSize" class="glyphicon glyphicon-plus"></button>
+  </div>
 </template>
 
 <!-- Display buttons on the chat tab, public, options, and all the private chat tabs -->
diff --git a/bigbluebutton-html5/app/client/views/users/user_item.coffee b/bigbluebutton-html5/app/client/views/users/user_item.coffee
index d9e7779ea6e0e89b205b040416049134a5db753c..24f33884fef64af9754012f0a27b5f2e730931c6 100755
--- a/bigbluebutton-html5/app/client/views/users/user_item.coffee
+++ b/bigbluebutton-html5/app/client/views/users/user_item.coffee
@@ -9,16 +9,3 @@ Template.displayUserIcons.events
     # the userId of the person who is lowering the hand
     console.log "lower hand- client click handler"
     Meteor.call('userLowerHand', getInSession("meetingId"), @userId, getInSession("userId"), getInSession("authToken"))
-
-Template.displayUserIcons.helpers
-  userLockedIconApplicable: (userId) ->
-    # the lock settings affect the user (and requiire a lock icon) if
-    # the user is set to be locked and there is a relevant lock in place
-    locked = BBB.getUser(userId)?.user.locked
-    settings = Meteor.Meetings.findOne()?.roomLockSettings
-    lockInAction = settings.disablePrivChat or
-                    settings.disableCam or
-                    settings.disableMic or
-                    settings.lockedLayout or
-                    settings.disablePubChat
-    return locked and lockInAction
diff --git a/bigbluebutton-html5/app/client/views/users/user_item.html b/bigbluebutton-html5/app/client/views/users/user_item.html
index 18df7410fd029019250401ac9733c4cd225d1e63..14efb5fcd916e85ad2967a79c3ee10284caef325 100755
--- a/bigbluebutton-html5/app/client/views/users/user_item.html
+++ b/bigbluebutton-html5/app/client/views/users/user_item.html
@@ -1,39 +1,36 @@
+
+
 <template name="displayUserIcons">
   {{#if isUserSharingVideo userId}}
     <span class="userListSettingIcon glyphicon glyphicon-facetime-video" rel="tooltip" data-placement="bottom" title="{{user.name}} is sharing their webcam"></span>
   {{/if}}
 
-  {{#if isUserInAudio userId}}
-    <!-- if the user is listen only, only display the one icon -->
-    {{#if isUserListenOnlyAudio userId}}
-      <span class="userListSettingIcon glyphicon glyphicon-headphones" title="Listening only"></span>
-    {{else}}
-      {{#if isCurrentUser userId}}
-        {{#if isUserMuted userId}}
-          <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="Unmute yourself"></span>
+  {{#if isUserSharingAudio userId}}
+    {{#if isCurrentUser userId}}
+      {{#if isUserMuted userId}}
+        <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="Unmute yourself"></span>
+      {{else}}
+        {{#if isCurrentUserTalking}}
+          <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="is talking"></span>
         {{else}}
-          {{#if isCurrentUserTalking}}
-            <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="is talking"></span>
-          {{else}}
-            <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="is not talking"></span>
-          {{/if}}
+          <span class="muteIcon userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="is not talking"></span>
         {{/if}}
+      {{/if}}
+    {{else}}
+      {{#if isUserMuted userId}}
+        <span class="userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="{{user.name}} is muted"></span>
       {{else}}
-        {{#if isUserMuted userId}}
-          <span class="userListSettingIcon glyphicon glyphicon-volume-off" rel="tooltip" data-placement="bottom" title="{{user.name}} is muted"></span>
+        {{#if isUserTalking userId}}
+          <span class="userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="{{user.name}} is talking"></span>
         {{else}}
-          {{#if isUserTalking userId}}
-            <span class="userListSettingIcon glyphicon glyphicon-volume-up" rel="tooltip" data-placement="bottom" title="{{user.name}} is talking"></span>
-          {{else}}
-            <span class="userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="{{user.name}} is not talking"></span>
-          {{/if}}
+          <span class="userListSettingIcon glyphicon glyphicon-volume-down" rel="tooltip" data-placement="bottom" title="{{user.name}} is not talking"></span>
         {{/if}}
       {{/if}}
     {{/if}}
   {{/if}}
 
-  {{#if userLockedIconApplicable userId}}
-    <span class="userListSettingIcon glyphicon ion-locked" rel="tooltip" data-placement="bottom" title="The viewer is locked"></span>
+  {{#if isUserListenOnly userId}}
+    <span class="userListSettingIcon glyphicon glyphicon-headphones" title="Listening only"></span>
   {{/if}}
 
   {{#if user.presenter}}
diff --git a/bigbluebutton-html5/app/client/views/users/user_list.coffee b/bigbluebutton-html5/app/client/views/users/user_list.coffee
index c6484a6b63abe76010164e3a43bcaa86b6111c1a..96d0fbcb2c217db88bb21c2d005db624d661d49a 100755
--- a/bigbluebutton-html5/app/client/views/users/user_list.coffee
+++ b/bigbluebutton-html5/app/client/views/users/user_list.coffee
@@ -1,6 +1,3 @@
 Template.usersList.helpers
-  getInfoNumberOfUsers: ->
-    numberUsers = Meteor.Users.find().count()
-    if numberUsers > 8
-      return "Users: #{numberUsers}"
-    # do not display the label if there are just a few users
+  getMeetingSize: -> # Retreieve the number of users in the chat, or "error" string
+    return Meteor.Users.find().count()
diff --git a/bigbluebutton-html5/app/client/views/users/users_list.html b/bigbluebutton-html5/app/client/views/users/users_list.html
index b245379dcb5835005c52e4d7a99f976ed5108fc1..4c9ec13d958026fe1269a87fe9da648bb1acca1d 100755
--- a/bigbluebutton-html5/app/client/views/users/users_list.html
+++ b/bigbluebutton-html5/app/client/views/users/users_list.html
@@ -1,6 +1,6 @@
 <template name="usersList">
 	<div id="{{id}}" {{visibility name}} class="component">
-		<h3 class="title gradientBar"><span class="glyphicon glyphicon-user heading"></span> {{getInfoNumberOfUsers}} </h3>
+		<h3 class="title gradientBar"><span class="glyphicon glyphicon-user"></span> Participants: {{getMeetingSize}} User(s)</h3>
 
 		<div id="user-contents">
 			<div class="userlist ScrollableWindowY">
diff --git a/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html b/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html
index 7288c5f7214b444c4575ba912d11bb240edb57dd..56f6213dd77cfd5cb6c219dfa5d8769c5e98d94e 100755
--- a/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html
+++ b/bigbluebutton-html5/app/client/views/whiteboard/whiteboard.html
@@ -4,7 +4,7 @@
             {{#if isMobileChromeOrFirefox}}
                 {{> makeButton btn_class="fullscreenWhiteboardButton" i_class="glyphicon glyphicon-fullscreen"}}
             {{/if}}
-            <span class="ion-easel heading"></span>
+            <span class="glyphicon glyphicon-pencil"></span>
             {{title}}
         </h3>
         {{#each getCurrentSlide}}
diff --git a/bigbluebutton-html5/app/config.coffee b/bigbluebutton-html5/app/config.coffee
index cc606108e86c763e2354e955ca2bafe4a27bf3c3..84bfbf10281d87f57a2ab2859157e36cc8346293 100755
--- a/bigbluebutton-html5/app/config.coffee
+++ b/bigbluebutton-html5/app/config.coffee
@@ -14,8 +14,6 @@ config.defaultWelcomeMessageFooter = "This server is running a build of <a href=
 config.maxUsernameLength = 30
 config.maxChatLength = 140
 
-config.lockOnJoin = true
-
 ## Application configurations
 config.app = {}
 
@@ -23,11 +21,6 @@ config.app = {}
 config.app.mobileFont = 24
 config.app.desktopFont = 12
 
-# Will offer the user to join the audio when entering the meeting
-config.app.autoJoinAudio = false
-# The amount of time the client will wait before making another call to successfully hangup the WebRTC conference call
-config.app.WebRTCHangupRetryInterval = 2000
-
 # Configs for redis
 config.redis = {}
 config.redis.host = "127.0.0.1"
diff --git a/bigbluebutton-html5/app/lib/router.coffee b/bigbluebutton-html5/app/lib/router.coffee
old mode 100755
new mode 100644
diff --git a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf
old mode 100755
new mode 100644
index c4e4632486d863337c1c73478ddb3c20726c55a0..f8fcf261a6b2501cb5ede90e5f3d371452c64156
Binary files a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf and b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf differ
diff --git a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff
old mode 100755
new mode 100644
index 5f3a14e0a5ca6d20cc4fac708979e807b0d51bc3..9f808a3cdddbe92050fc02ac0e9251c17d40687d
Binary files a/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff and b/bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff differ
diff --git a/bigbluebutton-html5/app/server/collection_methods/meetings.coffee b/bigbluebutton-html5/app/server/collection_methods/meetings.coffee
index 00d2acc142efe5e23352737a0ff19d82871e0d02..348d08bd74bd4ae5076e04b3ee024737b3c97a8f 100755
--- a/bigbluebutton-html5/app/server/collection_methods/meetings.coffee
+++ b/bigbluebutton-html5/app/server/collection_methods/meetings.coffee
@@ -2,27 +2,17 @@
 # Private methods on server
 # --------------------------------------------------------------------------------------------
 @addMeetingToCollection = (meetingId, name, intendedForRecording, voiceConf, duration) ->
-  #check if the meeting is already in the collection
-  unless Meteor.Meetings.findOne({meetingId: meetingId})?
-    entry =
-      meetingId: meetingId
-      meetingName: name
-      intendedForRecording: intendedForRecording
-      currentlyBeingRecorded: false # defaut value
-      voiceConf: voiceConf
-      duration: duration
-      roomLockSettings:
-        # by default the lock settings will be disabled on meeting create
-        disablePrivChat: false
-        disableCam: false
-        disableMic: false
-        lockOnJoin: Meteor.config.lockOnJoin
-        lockedLayout: false
-        disablePubChat: false
-
-    id = Meteor.Meetings.insert(entry)
-    Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]
-    roomLockSettings:[#{JSON.stringify entry.roomLockSettings}]."
+	#check if the meeting is already in the collection
+	unless Meteor.Meetings.findOne({meetingId: meetingId})?
+		currentlyBeingRecorded = false # defaut value
+		id = Meteor.Meetings.insert(
+			meetingId: meetingId,
+			meetingName: name,
+			intendedForRecording: intendedForRecording,
+			currentlyBeingRecorded: currentlyBeingRecorded,
+			voiceConf: voiceConf,
+			duration: duration)
+		Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]."
 
 
 @clearMeetingsCollection = (meetingId) ->
@@ -32,7 +22,6 @@
 		Meteor.Meetings.remove({}, Meteor.log.info "cleared Meetings Collection (all meetings)!")
 
 
-#clean up upon a meeting's end
 @removeMeetingFromCollection = (meetingId) ->
 	if Meteor.Meetings.findOne({meetingId: meetingId})?
 		Meteor.log.info "end of meeting #{meetingId}. Clear the meeting data from all collections"
diff --git a/bigbluebutton-html5/app/server/collection_methods/users.coffee b/bigbluebutton-html5/app/server/collection_methods/users.coffee
index 8b431dddb34c926139e7465b4d3eda1426519999..3b3980a09d240a4a53101090b7bbd37df30970a5 100755
--- a/bigbluebutton-html5/app/server/collection_methods/users.coffee
+++ b/bigbluebutton-html5/app/server/collection_methods/users.coffee
@@ -6,49 +6,6 @@
 # immediately, since they do not require permission for things such as muting themsevles. 
 # --------------------------------------------------------------------------------------------
 Meteor.methods
-  # meetingId: the meetingId of the meeting the user is in
-  # toSetUserId: the userId of the user joining
-  # requesterUserId: the userId of the requester
-  # requesterToken: the authToken of the requester
-  listenOnlyRequestToggle: (meetingId, userId, authToken, isJoining) ->
-    voiceConf = Meteor.Meetings.findOne({meetingId:meetingId})?.voiceConf
-    username = Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.name
-    if isJoining
-      if isAllowedTo('joinListenOnly', meetingId, userId, authToken)
-        message =
-          payload:
-            userid: userId
-            meeting_id: meetingId
-            voice_conf: voiceConf
-            name: username
-          header:
-            timestamp: new Date().getTime()
-            name: "user_connected_to_global_audio"
-            version: "0.0.1"
-
-        Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}"
-
-        publish Meteor.config.redis.channels.toBBBApps.meeting, message
-
-    else
-      if isAllowedTo('leaveListenOnly', meetingId, userId, authToken)
-        message =
-          payload:
-            userid: userId
-            meeting_id: meetingId
-            voice_conf: voiceConf
-            name: username
-          header:
-            timestamp: new Date().getTime()
-            name: "user_disconnected_from_global_audio"
-            version: "0.0.1"
-
-        Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}"
-
-        publish Meteor.config.redis.channels.toBBBApps.meeting, message
-
-    return
-
   # meetingId: the meetingId of the meeting the user[s] is in
   # toMuteUserId: the userId of the user to be [un]muted
   # requesterUserId: the userId of the requester
@@ -160,6 +117,7 @@ Meteor.methods
   Meteor.log.info "marking user [#{userId}] as offline in meeting[#{meetingId}]"
   Meteor.Users.update({'meetingId': meetingId, 'userId': userId}, {$set:{'user.connection_status':'offline'}})
 
+
 # Corresponds to a valid action on the HTML clientside
 # After authorization, publish a user_leaving_request in redis
 # params: meetingid, userid as defined in BBB-App
@@ -192,8 +150,8 @@ Meteor.methods
       Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.voiceUser.locked':voiceUserObject.locked}}) # locked
     if voiceUserObject.muted?
       Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.voiceUser.muted':voiceUserObject.muted}}) # muted
-    if voiceUserObject.listen_only?
-      Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.listenOnly':voiceUserObject.listen_only}}) # listenOnly
+    if voiceUserObject.listenOnly?
+      Meteor.Users.update({meetingId: meetingId ,userId: voiceUserObject.web_userid}, {$set: {'user.listenOnly':voiceUserObject.listenOnly}}) # muted
   else
     Meteor.log.error "ERROR! did not find such voiceUser!"
 
@@ -204,7 +162,7 @@ Meteor.methods
   # the collection already contains an entry for this user because
   # we added a dummy user on register_user_message (to save authToken)
   if u?
-    Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}, locked=#{user.locked}"
+    Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}"
     Meteor.Users.update({userId:user.userid, meetingId: meetingId}, {$set:{
       user:
         userid: user.userid
@@ -308,36 +266,6 @@ Meteor.methods
     Meteor.log.info "added user dummy html5 user with: userid=[#{userId}], id=[#{id}]
       Users.size is now #{Meteor.Users.find({meetingId: meetingId}).count()}"
 
-
-# when new lock settings including disableMic are set,
-# all viewers that are in the audio bridge with a mic should be muted and locked
-@handleLockingMic = (meetingId, newSettings) ->
-  # send mute requests for the viewer users joined with mic
-  for u in Meteor.Users.find({
-                              meetingId:meetingId
-                              'user.role':'VIEWER'
-                              'user.listenOnly':false
-                              'user.locked':true
-                              'user.voiceUser.joined':true
-                              'user.voiceUser.muted':false})?.fetch()
-    Meteor.log.error u.user.name #
-    Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted
-
-# change the locked status of a user (lock settings)
-@setUserLockedStatus = (meetingId, userId, isLocked) ->
-  if Meteor.Users.findOne({userId:userId, meetingId: meetingId})?
-    Meteor.Users.update({userId:userId, meetingId: meetingId}, {$set:{'user.locked': isLocked}})
-
-    # if the user is sharing audio, he should be muted upon locking involving disableMic
-    u = Meteor.Users.findOne({meetingId:meetingId, userId:userId})
-    if u.user.role is 'VIEWER' and !u.user.listenOnly and u.user.voiceUser.joined and !u.user.voiceUser.muted and isLocked
-      Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted
-
-    Meteor.log.info "setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}"
-  else
-    Meteor.log.error "(unsuccessful-no such user) setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}"
-
-
 # called on server start and on meeting end
 @clearUsersCollection = (meetingId) ->
   if meetingId?
diff --git a/bigbluebutton-html5/app/server/redispubsub.coffee b/bigbluebutton-html5/app/server/redispubsub.coffee
index 3d81454bb15b1a3e5eaf9334d003c4cf7b3a3cf4..21ae697e0005a82df71d7424b0d47743d032d586 100755
--- a/bigbluebutton-html5/app/server/redispubsub.coffee
+++ b/bigbluebutton-html5/app/server/redispubsub.coffee
@@ -1,4 +1,8 @@
 Meteor.methods
+  #
+  # I dont know if this is okay to be server side. We need to call it from the router, but I don't know if any harm can be caused
+  # by the client calling this
+  #
 
   # Construct and send a message to bbb-web to validate the user
   validateAuthToken: (meetingId, userId, authToken) ->
@@ -56,45 +60,29 @@ class Meteor.RedisPubSub
     correlationId = message.payload?.reply_to or message.header?.reply_to
     meetingId = message.payload?.meeting_id
 
-    # just because it's common. we handle it anyway
-    notLoggedEventTypes = [
+    ignoredEventTypes = [
       "keep_alive_reply"
       "page_resized_message"
       "presentation_page_resized_message"
-      "presentation_cursor_updated_message"
-      "get_presentation_info_reply"
-      # "get_users_reply"
-      "get_chat_history_reply"
-      "get_all_meetings_reply"
-      "presentation_shared_message"
-      "presentation_conversion_done_message"
-      "presentation_conversion_progress_message"
-      "presentation_page_generated_message"
-      "presentation_page_changed_message"
+      "presentation_cursor_updated_message" # just because it's common. we handle it anyway
     ]
 
     if message?.header? and message?.payload?
-      unless message.header.name in notLoggedEventTypes
+      unless message.header.name in ignoredEventTypes
         Meteor.log.info "eventType=  #{message.header.name}  ",
           message: jsonMsg
 
       # handle voice events
       if message.header.name in ['user_left_voice_message', 'user_joined_voice_message', 'user_voice_talking_message', 'user_voice_muted_message']
-        if message.payload.user?
-          updateVoiceUser meetingId,
-            'web_userid': message.payload.user.voiceUser.web_userid
-            'listen_only': message.payload.listen_only
-            'talking': message.payload.user.voiceUser.talking
-            'joined': message.payload.user.voiceUser.joined
-            'locked': message.payload.user.voiceUser.locked
-            'muted': message.payload.user.voiceUser.muted
+        voiceUser = message.payload.user?.voiceUser
+        updateVoiceUser meetingId, voiceUser
         return
 
       # listen only
       if message.header.name is 'user_listening_only'
-        updateVoiceUser meetingId, {'web_userid': message.payload.userid, 'listen_only': message.payload.listen_only}
+        updateVoiceUser meetingId, {'web_userid': message.payload.userid, 'listenOnly': message.payload.listen_only}
         # most likely we don't need to ensure that the user's voiceUser's {talking, joined, muted, locked} are false by default #TODO?
-        return 
+        return
 
       if message.header.name is "get_all_meetings_reply"
         Meteor.log.info "Let's store some data for the running meetings so that when an HTML5 client joins everything is ready!"
@@ -287,37 +275,6 @@ class Meteor.RedisPubSub
         Meteor.Meetings.update({meetingId: meetingId, intendedForRecording: intendedForRecording}, {$set: {currentlyBeingRecorded: currentlyBeingRecorded}})
         return
 
-      # --------------------------------------------------
-      # lock settings ------------------------------------
-      if message.header.name is "eject_voice_user_message"
-        console.log "\n111111111"
-        return
-
-      if message.header.name is "new_permission_settings"
-        oldSettings = Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings
-        newSettings = message.payload
-
-        # if the disableMic setting was turned on
-        if !oldSettings?.disableMic and newSettings.disableMic
-          handleLockingMic(meetingId, newSettings)
-
-        # substitute with the new lock settings
-        Meteor.Meetings.update({meetingId: meetingId}, {$set: {
-          'roomLockSettings.disablePrivChat': message.payload.disablePrivChat
-          'roomLockSettings.disableCam': message.payload.disableCam
-          'roomLockSettings.disableMic': message.payload.disableMic
-          'roomLockSettings.lockOnJoin': message.payload.lockOnJoin
-          'roomLockSettings.lockedLayout': message.payload.lockedLayout
-          'roomLockSettings.disablePubChat': message.payload.disablePubChat
-        }})
-        return
-
-      if message.header.name is "user_locked_message" or message.header.name is "user_unlocked_message"
-        userId = message.payload.userid
-        isLocked = message.payload.locked
-        setUserLockedStatus(meetingId, userId, isLocked)
-        return
-
       if message.header.name in ["meeting_ended_message", "meeting_destroyed_event",
         "end_and_kick_all_message", "disconnect_all_users_message"]
         if Meteor.Meetings.findOne({meetingId: meetingId})?
@@ -335,9 +292,9 @@ class Meteor.RedisPubSub
 
 # message should be an object
 @publish = (channel, message) ->
-  # Meteor.log.info "Publishing",
-  #   channel: channel
-  #   message: message
+  Meteor.log.info "Publishing",
+    channel: channel
+    message: message
 
   if Meteor.redisPubSub?
     Meteor.redisPubSub.pubClient.publish channel, JSON.stringify(message), (err, res) ->
diff --git a/bigbluebutton-html5/app/server/user_permissions.coffee b/bigbluebutton-html5/app/server/user_permissions.coffee
old mode 100755
new mode 100644
index ce3962ad81fc7bff5e7f9453a1beab3b86b02d0d..43a422767c1a49fd4c4121aa1225fed71e379575
--- a/bigbluebutton-html5/app/server/user_permissions.coffee
+++ b/bigbluebutton-html5/app/server/user_permissions.coffee
@@ -1,16 +1,8 @@
 
 presenter = null
 
-# holds the values for whether the moderator user is allowed to perform an action (true)
-# or false if not allowed. Some actions have dynamic values depending on the current lock settings
+#for the time being moderators have the same permissions that viewers do
 moderator =
-  # audio listen only
-  joinListenOnly: true
-  leaveListenOnly: true
-
-  # join audio with mic cannot be controlled on the server side as it is
-  # a client side only functionality
-
   # raising/lowering hand
   raiseOwnHand : true
   lowerOwnHand : true
@@ -26,29 +18,18 @@ moderator =
   subscribeChat: true
 
   #chat
-  chatPublic: true
-  chatPrivate: true
-
-
-# holds the values for whether the viewer user is allowed to perform an action (true)
-# or false if not allowed. Some actions have dynamic values depending on the current lock settings
-viewer = (meetingId, userId) ->
+  chatPublic: true #should make this dynamically modifiable later on
+  chatPrivate: true #should make this dynamically modifiable later on
 
-  # listen only
-  joinListenOnly: true
-  leaveListenOnly: true
-
-  # join audio with mic cannot be controlled on the server side as it is
-  # a client side only functionality
 
+viewer =
   # raising/lowering hand
   raiseOwnHand : true
   lowerOwnHand : true
 
   # muting
   muteSelf : true
-  unmuteSelf : !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disableMic) or
-                !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked)
+  unmuteSelf : true
 
   logoutSelf : true
 
@@ -57,18 +38,11 @@ viewer = (meetingId, userId) ->
   subscribeChat: true
 
   #chat
-  chatPublic: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePubChat) or
-                !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or
-                Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter
-  chatPrivate: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePrivChat) or
-                !(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or
-                Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter
-
-
+  chatPublic: true #should make this dynamically modifiable later on
+  chatPrivate: true #should make this dynamically modifiable later on
 
-# carries out the decision making for actions affecting users. For the list of
-# actions and the default value - see 'viewer' and 'moderator' in the beginning of the file
 @isAllowedTo = (action, meetingId, userId, authToken) ->
+  # Disclaimer:the current version of the HTML5 client represents only VIEWER users
 
   validated = Meteor.Users.findOne({meetingId:meetingId, userId: userId})?.validated
   Meteor.log.info "in isAllowedTo: action-#{action}, userId=#{userId}, authToken=#{authToken} validated:#{validated}"
@@ -78,7 +52,7 @@ viewer = (meetingId, userId) ->
   if user? and authToken is user.authToken # check if the user is who he claims to be
     if user.validated and user.clientType is "HTML5"
       if user.user?.role is 'VIEWER' or user.user?.role is 'MODERATOR' or user.user?.role is undefined
-        return viewer(meetingId, userId)[action] or false
+        return viewer[action] or false
       else
         Meteor.log.warn "UNSUCCESSFULL ATTEMPT FROM userid=#{userId} to perform:#{action}"
         return false
diff --git a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
index 791e6f6c79d9be3771236d9a72bc78fc45230921..021c97785e77f5fd14aaf929c59e07521c0f06b6 100644
--- a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
+++ b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
@@ -1,183 +1,183 @@
-/**
-* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-*
-* Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
-*
-* This program is free software; you can redistribute it and/or modify it under the
-* terms of the GNU Lesser General Public License as published by the Free Software
-* Foundation; either version 3.0 of the License, or (at your option) any later
-* version.
-*
-* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License along
-* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-*
-*/
-package org.bigbluebutton.web.services
-
-import java.util.concurrent.*;
-import java.lang.InterruptedException
-import org.bigbluebutton.presentation.DocumentConversionService
-import org.bigbluebutton.presentation.UploadedPresentation
-
-class PresentationService {
-
-    static transactional = false
-	DocumentConversionService documentConversionService
-	def presentationDir
-	def testConferenceMock
-	def testRoomMock
-	def testPresentationName
-	def testUploadedPresentation
-	def defaultUploadedPresentation
-	def presentationBaseUrl
-
-  def deletePresentation = {conf, room, filename ->
-    		def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename)
-    		deleteDirectory(directory)
-	}
-
-	def deleteDirectory = {directory ->
-		log.debug "delete = ${directory}"
-		/**
-		 * Go through each directory and check if it's not empty.
-		 * We need to delete files inside a directory before a
-		 * directory can be deleted.
-		**/
-		File[] files = directory.listFiles();
-		for (int i = 0; i < files.length; i++) {
-			if (files[i].isDirectory()) {
-				deleteDirectory(files[i])
-			} else {
-				files[i].delete()
-			}
-		}
-		// Now that the directory is empty. Delete it.
-		directory.delete()
-	}
-
-	def listPresentations = {conf, room ->
-		def presentationsList = []
-		def directory = roomDirectory(conf, room)
-		log.debug "directory ${directory.absolutePath}"
-		if( directory.exists() ){
-			directory.eachFile(){ file->
-				System.out.println(file.name)
-				if( file.isDirectory() )
-					presentationsList.add( file.name )
-			}
-		}
-		return presentationsList
-	}
-
-  def getPresentationDir = {
-    return presentationDir
-  }
-
-    def processUploadedPresentation = {uploadedPres ->
-        // Run conversion on another thread.
-        Timer t = new Timer(uploadedPres.getName(), false)
-
-        t.runAfter(1000) {
-            try {
-                documentConversionService.processDocument(uploadedPres)
-            } finally {
-            t.cancel()
-            }
-        }
-    }
-
-	def showSlide(String conf, String room, String presentationName, String id) {
-		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf")
-	}
-
-	def showPngImage(String conf, String room, String presentationName, String id) {
-		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "pngs" + File.separatorChar + "slide${id}.png")
-	}
-
-	def showPresentation = {conf, room, filename ->
-		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf")
-	}
-
-	def showThumbnail = {conf, room, presentationName, thumb ->
-		println "Show thumbnails request for $presentationName $thumb"
-		def thumbFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
-					"thumbnails" + File.separatorChar + "thumb-${thumb}.png"
-		log.debug "showing $thumbFile"
-
-		new File(thumbFile)
-	}
-
-	def showTextfile = {conf, room, presentationName, textfile ->
-		println "Show textfiles request for $presentationName $textfile"
-		def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
-					"textfiles" + File.separatorChar + "slide-${textfile}.txt"
-		log.debug "showing $txt"
-		
-		new File(txt)
-	}
-
-	def numberOfThumbnails = {conf, room, name ->
-		def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails")
-		thumbDir.listFiles().length
-	}
-
-	def numberOfPngs = {conf, room, name ->
-		def PngsDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "pngs")
-		PngsDir.listFiles().length
-	}
-
-	def numberOfTextfiles = {conf, room, name ->
-		log.debug roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles"
-		def textfilesDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles")
-		textfilesDir.listFiles().length
-	}
-
-  def roomDirectory = {conf, room ->
-      return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room)
-  }
-
-	def testConversionProcess() {
-		File presDir = new File(roomDirectory(testConferenceMock, testRoomMock).absolutePath + File.separatorChar + testPresentationName)
-		
-		if (presDir.exists()) {
-			File pres = new File(presDir.getAbsolutePath() + File.separatorChar + testUploadedPresentation)
-			if (pres.exists()) {
-				UploadedPresentation uploadedPres = new UploadedPresentation(testConferenceMock, testRoomMock, testPresentationName);
-				uploadedPres.setUploadedFile(pres);
-				// Run conversion on another thread.
-				new Timer().runAfter(1000) 
-				{
-					documentConversionService.processDocument(uploadedPres)
-				}
-			} else {
-				log.error "${pres.absolutePath} does NOT exist"
-			}			
-		} else {
-			log.error "${presDir.absolutePath} does NOT exist."
-		}
-		
-	}
-
-	def getFile = {conf, room, presentationName ->
-		println "download request for $presentationName"
-		def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
-"download")
-		//list the files of the download directory ; it must have only 1 file to download
-		def list = fileDirectory.listFiles()
-		//new File(pdfFile)
-		list[0]
-	}
-}	
-
-/*** Helper classes **/
-import java.io.FilenameFilter;
-import java.io.File;
-class PngFilter implements FilenameFilter {
-    public boolean accept(File dir, String name) {
-        return (name.endsWith(".png"));
-    }
-}
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2014 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.web.services
+
+import java.util.concurrent.*;
+import java.lang.InterruptedException
+import org.bigbluebutton.presentation.DocumentConversionService
+import org.bigbluebutton.presentation.UploadedPresentation
+
+class PresentationService {
+
+    static transactional = false
+	DocumentConversionService documentConversionService
+	def presentationDir
+	def testConferenceMock
+	def testRoomMock
+	def testPresentationName
+	def testUploadedPresentation
+	def defaultUploadedPresentation
+	def presentationBaseUrl
+
+  def deletePresentation = {conf, room, filename ->
+    		def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename)
+    		deleteDirectory(directory)
+	}
+
+	def deleteDirectory = {directory ->
+		log.debug "delete = ${directory}"
+		/**
+		 * Go through each directory and check if it's not empty.
+		 * We need to delete files inside a directory before a
+		 * directory can be deleted.
+		**/
+		File[] files = directory.listFiles();
+		for (int i = 0; i < files.length; i++) {
+			if (files[i].isDirectory()) {
+				deleteDirectory(files[i])
+			} else {
+				files[i].delete()
+			}
+		}
+		// Now that the directory is empty. Delete it.
+		directory.delete()
+	}
+
+	def listPresentations = {conf, room ->
+		def presentationsList = []
+		def directory = roomDirectory(conf, room)
+		log.debug "directory ${directory.absolutePath}"
+		if( directory.exists() ){
+			directory.eachFile(){ file->
+				System.out.println(file.name)
+				if( file.isDirectory() )
+					presentationsList.add( file.name )
+			}
+		}
+		return presentationsList
+	}
+
+  def getPresentationDir = {
+    return presentationDir
+  }
+
+    def processUploadedPresentation = {uploadedPres ->
+        // Run conversion on another thread.
+        Timer t = new Timer(uploadedPres.getName(), false)
+
+        t.runAfter(1000) {
+            try {
+                documentConversionService.processDocument(uploadedPres)
+            } finally {
+            t.cancel()
+            }
+        }
+    }
+
+	def showSlide(String conf, String room, String presentationName, String id) {
+		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "slide-${id}.swf")
+	}
+
+	def showPngImage(String conf, String room, String presentationName, String id) {
+		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar + "pngs" + File.separatorChar + "slide${id}.png")
+	}
+
+	def showPresentation = {conf, room, filename ->
+		new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename + File.separatorChar + "slides.swf")
+	}
+
+	def showThumbnail = {conf, room, presentationName, thumb ->
+		println "Show thumbnails request for $presentationName $thumb"
+		def thumbFile = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
+					"thumbnails" + File.separatorChar + "thumb-${thumb}.png"
+		log.debug "showing $thumbFile"
+
+		new File(thumbFile)
+	}
+
+	def showTextfile = {conf, room, presentationName, textfile ->
+		println "Show textfiles request for $presentationName $textfile"
+		def txt = roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
+					"textfiles" + File.separatorChar + "slide-${textfile}.txt"
+		log.debug "showing $txt"
+		
+		new File(txt)
+	}
+
+	def numberOfThumbnails = {conf, room, name ->
+		def thumbDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "thumbnails")
+		thumbDir.listFiles().length
+	}
+
+	def numberOfPngs = {conf, room, name ->
+		def PngsDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "pngs")
+		PngsDir.listFiles().length
+	}
+
+	def numberOfTextfiles = {conf, room, name ->
+		log.debug roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles"
+		def textfilesDir = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + name + File.separatorChar + "textfiles")
+		textfilesDir.listFiles().length
+	}
+
+  def roomDirectory = {conf, room ->
+      return new File(presentationDir + File.separatorChar + conf + File.separatorChar + room)
+  }
+
+	def testConversionProcess() {
+		File presDir = new File(roomDirectory(testConferenceMock, testRoomMock).absolutePath + File.separatorChar + testPresentationName)
+		
+		if (presDir.exists()) {
+			File pres = new File(presDir.getAbsolutePath() + File.separatorChar + testUploadedPresentation)
+			if (pres.exists()) {
+				UploadedPresentation uploadedPres = new UploadedPresentation(testConferenceMock, testRoomMock, testPresentationName);
+				uploadedPres.setUploadedFile(pres);
+				// Run conversion on another thread.
+				new Timer().runAfter(1000) 
+				{
+					documentConversionService.processDocument(uploadedPres)
+				}
+			} else {
+				log.error "${pres.absolutePath} does NOT exist"
+			}			
+		} else {
+			log.error "${presDir.absolutePath} does NOT exist."
+		}
+		
+	}
+
+	def getFile = {conf, room, presentationName ->
+		println "download request for $presentationName"
+		def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
+"download")
+		//list the files of the download directory ; it must have only 1 file to download
+		def list = fileDirectory.listFiles()
+		//new File(pdfFile)
+		list[0]
+	}
+}
+
+/*** Helper classes **/
+import java.io.FilenameFilter;
+import java.io.File;
+class PngFilter implements FilenameFilter {
+    public boolean accept(File dir, String name) {
+        return (name.endsWith(".png"));
+    }
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
index df6037d137dd437c88cc97fda70385830f58bd38..596d20747b66b7ddbcfbcbaa2c34cab1174a1e22 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
@@ -181,7 +181,7 @@ public class MeetingMessageHandler implements MessageHandler {
 								listener.handle(new UserRoleChanged(meetingId, userid, role));
 							}
 						}
-					}
+					}				
 				}
 		  } 
 	}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
index 33cc69c1dd6a459cdd5fefc71e995c3034b32946..1cc45708289ce8f64a096a0fed6d617f4e9d46db 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
@@ -53,6 +53,7 @@ public class MessagingConstants {
 	public static final String USER_SHARE_WEBCAM_EVENT       = "user_shared_webcam_message";
 	public static final String USER_UNSHARE_WEBCAM_EVENT     = "user_unshared_webcam_message";
 	public static final String USER_ROLE_CHANGE_EVENT        = "user_role_changed_message";
+	
 			
 	public static final String SEND_POLLS_EVENT = "SendPollsEvent";
 	public static final String KEEP_ALIVE_REPLY = "keep_alive_reply";