diff --git a/bbb-screenshare/jws/native-libs/README.md b/bbb-screenshare/NOTES.md
similarity index 97%
rename from bbb-screenshare/jws/native-libs/README.md
rename to bbb-screenshare/NOTES.md
index 9dd69047bdb738e2d40c6e337729b94188182c4f..83311f723e41cde738739e88bf92016353784223 100755
--- a/bbb-screenshare/jws/native-libs/README.md
+++ b/bbb-screenshare/NOTES.md
@@ -1,181 +1,184 @@
-
-** NOTE: **
- Taken from https://github.com/bytedeco/javacpp-presets/wiki/Build-Environments
-
-Introduction
-------------
-This page contains a description of the environments that are used to build the JavaCPP Presets for [Android (ARM and x86)](#android-arm-and-x86), [Linux (x86 and x86_64)](#linux-x86-and-x86_64), [Linux (ARM)](#linux-arm), [Mac OS X (x86_64)](#mac-os-x-x86_64), and [Windows (x86 and x86_64)](#windows-x86-and-x86_64). We also explain our choices given the requirements and provide some recommendations. Furthermore, JavaCPP is by no means limited to these platforms, so if you happen to know how to set up an environment for other platforms, by all means, please do add that information to this page to share with others. Thank you!
-
-
-Prerequisites for all platforms
--------------------------------
-The build process for the modules of `javacpp-presets` usually depends on the same version of the `javacpp` module. To insure that you have the latest matching version of both, please execute the following before starting the build in the `javacpp-presets` directory:
-```bash
-$ git clone https://github.com/bytedeco/javacpp.git --branch <tag>
-$ git clone https://github.com/bytedeco/javacpp-presets.git --branch <tag>
-$ cd javacpp
-$ mvn clean install
-```
-For the latest tag please check
-https://github.com/bytedeco/javacpp-presets/tags
-
-Android (ARM and x86)
----------------------
-To produce native libraries for Android, we basically only need to install the JDK and the NDK, which is available for Linux, Mac OS X, and Windows. However, the build scripts of some libraries only run correctly under Linux, so we recommend using a recent distribution of Linux (such as Fedora or Ubuntu) as build environment for Android.
-
-### Preparations
-1. Download the latest version of the [NDK](https://developer.android.com/ndk/downloads/), which is r10e at the time of this writing and contains important fixes for OpenMP, among other things
-2. Install the NDK under `~/Android/android-ndk`, where the build scripts will look for it by default
-3. Finally, make sure to have installed at least OpenJDK and Maven as per the instructions of your distribution
-
-After which the following commands can be used to start the build inside the `javacpp-presets` directory:
-```bash
-$ ANDROID_NDK=/path/to/android-ndk/ bash cppbuild.sh -platform android-xxx install
-$ mvn clean install -Djavacpp.platform=android-xxx -Djavacpp.platform.root=/path/to/android-ndk/ -Djavacpp.platform.compiler=/path/to/target-g++
-```
-where `android-xxx` is either `android-arm` or `android-x86`, and where `target-g++` is either `arm-linux-androideabi-g++` or `i686-linux-android-g++`.
-
-
-Linux (x86 and x86_64)
-----------------------
-To produce native libraries that can run on the largest possible number of Linux installations out there, it is recommended to build under CentOS 7. This is because it relies on an old enough version of glibc, which nevertheless works for all the libraries found in the JavaCPP Presets, and since newer versions of glibc are backward compatible, all recent distributions of Linux should support the binaries generated. We do not actually need to install CentOS 7 though. Pretty much any recent distribution of Linux comes with a package for [Docker](https://www.docker.com/). It is also possible to map existing directories, for example `/usr/local/lib/bazel` and `/usr/local/cuda` as shown in the steps below, to reuse an existing [Bazel](http://bazel.io/docs/install.html) or [CUDA](https://developer.nvidia.com/cuda-downloads) installation as well as any other set of files for the purpose of the build.
-
-### Preparations
-1. Install Docker under, for example, Fedora and Ubuntu, respectively:
-
-    ```bash
-    $ sudo yum install docker
-    $ sudo apt-get install docker.io
-    ```
-
-2. When using SELinux, it might also be necessary to disable temporarily the firewall, for example:
-
-    ```
-    $ sudo systemctl stop firewalld
-    $ sudo systemctl start docker
-    ```
-
-3. Start the container for CentOS 7 (the command might be `docker.io` instead of `docker`):
-
-    ```bash
-    $ sudo docker run --privileged -it -v /usr/local/lib/bazel:/usr/local/lib/bazel -v /usr/local/cuda:/usr/local/cuda centos:7 /bin/bash
-    ```
-
-4. Finally, inside the container, we need to install a bunch of things:
-
-    ```bash
-    $ ln -s /usr/local/lib/bazel/bin/bazel /usr/local/bin/bazel
-    $ yum install epel-release
-    $ yum install clang gcc-c++ gcc-gfortran java-devel maven python numpy swig git file which wget unzip tar bzip2 gzip xz patch make cmake3 perl nasm yasm alsa-lib-devel freeglut-devel gtk2-devel libusb-devel libusb1-devel zlib-devel
-    $ yum install `rpm -qa | sed s/.x86_64$/.i686/`
-    ```
-
-After which the following commands can be used to start the build inside the `javacpp-presets` directory:
-```bash
-$ bash cppbuild.sh -platform linux-xxx install
-$ mvn clean install -Djavacpp.platform=linux-xxx
-```
-where `linux-xxx` is either `linux-x86` or `linux-x86_64`.
-
-
-Linux (ARM)
------------
-There are a growing number of arm platforms running Linux, though testing of this build has mainly focussed on the Pi family of products. Compiling natively on these platforms can be quite time consuming, and as well to automate the build process, the build setup here relies on cross-compiling for the target arm platform. This has been tested using Ubuntu x64 15.10, but it should be reasonably similar approach for other host OS's. 
-
-You'll need to have setup a build environment with the usual packages (pkgconfig, build-essentials, yasm, nasm, maven3, etc). The major addition you'll need is a set of cross compilers: arm-linux-gnueabihf-gcc, arm-linux-gnueabihf-g++ and arm-linux-gnueabihf-cpp. It's best to get these via your OS's package manager, as there are other dependencies for these. 
-
-Originally a 5.x compiler was used, but this seems to caused problems in creating a dependency on newer glibc functionality which might not be present on your target arm device. The 4.8 or 4.9 version of the compiler seems to work fine, but, in targetting support for the Pi1 and well as Pi2-Pi3 (i.e. arm6 as well as arm7) it seems some compiler flag combinations might not be support by the standard gnueabihf compiler toolchain. 
-
-There are pi specific compilers available, so these have been used in the current setup. 
-
-1. Get the Pi tools: git clone https://github.com/raspberrypi/tools.git
-2. From this folder, move out a specific compiler version to a more generic location: sudo cp -r ./tools/arm-bcm2708/arm-bcm2708-linux-gnueabi /opt
-3. Setup alternatives of the generic compiler names in /usr/bin to point to this new compiler 
-
-    ```bash
-    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-gcc arm-linux-gnueabihf-gcc /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-gcc 46
-    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-g++ arm-linux-gnueabihf-g++ /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-g++ 46
-    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-cpp arm-linux-gnueabihf-cpp /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-cpp 46
-    ```
-
-   (This way if you want to explore using other newer compilers, just add them to alternatives and the same build setup should work fine)
-
-This should now have you setup ready to build for arm. It could be an idea to test at this stage with building a simple hello world executable (save your hello world test code as hello.cpp):
-
-    $ arm-linux-gnueabihf-g++ -O3 -g3 -Wall -fPIC -march=armv6 -mfpu=vfp -mfloat-abi=hard hello.cpp -c -o hello.o 
-    $ arm-linux-gnueabihf-g++ -o hello hello.o 
-    $ file hello
-
-And you should see in the returned info that hello is built for ARM
-
-With the build environment setup, now its on to building JavaCV. Not all components have been setup with the linux-armhf build configurations, so rather than building the entire project only a subset are built here, but enough to have core functionality (OpenCV, FFmpeg) working with some additional parts (artoolkitplus, flycapture, flandmark, libfreenect, libdc1394) built but not tested. For flycapture, you need to download the arm SDK (currently flycapture.2.9.3.13_armhf) and make these .so libs available, either in your path, or setting up a /usr/include/flycapture directory and moving them there. 
-
-Now all the dependencies are setup, the build can be started (assuming you've done a git clone of javacv, javacpp and javacpp-presets all to the same folder)
-
-    $ cd javacpp
-    $ mvn install
-    $ cd ..
-    $ cd javacpp-presets
-    $ ./cppbuild.sh -platform linux-armhf install
-    $ mvn install -Djavacpp.platform=linux-armhf -Djavacpp.platform.compiler=arm-linux-gnueabihf-g++
-    $ cd platform
-    $ mvn install -Djavacpp.platform=linux-armhf
-
-Hopefully that all runs OK, and then in ./javacpp-presets/platform/target/ you should find there are platform specific (opencv-linux-armhf.jar, ffmpeg-linux-armhf.jar, etc) files built.
-
-If you want to try alternative flags, you need to modify in javacpp, ./src/main/resources/org/bytedeco/javacpp/properties/linux-armhf.properties and then in javacpp-presets any project cppbuild.sh file where you want to update too (e.g. ./opencv/cppbuild.sh linux-armhf section). For newer Pis on arm7 it does look like there are potential performance gains in armv7 and neon flags, and using a newer compiler rather than the bcm2708 build used here may further improve things (some earlier builds specific for armv7 did look faster). Also if you are using onboard picam devices, make sure you load the module with "modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944" - this way if you test just using OpenCV or FFMPEG grabber you should get at least 30fps as a start point. The more computation you then do on each frame, the more this will drop.
-
-
-Mac OS X (x86_64)
------------------
-OS X Mavericks (10.9) is the first version of Mac OS X to support C++11 fully and properly, so to preserve your sanity, we do not recommend trying to build or use the JavaCPP Presets on any older versions of Mac OS X.
-
-### Preparations
-1. Install [Xcode](https://developer.apple.com/xcode/) and [Homebrew](http://brew.sh/)
-2. Ensure the command line tools for Xcode are installed
-
-    ```bash
-    $ xcode-select --install
-    ```
-3. Run the following commands to install the JDK, among other things Apple left out of Xcode:
-
-    ```bash
-    $ brew install caskroom/cask/brew-cask
-    $ brew cask install cuda java
-    $ brew install gcc5 swig bazel cmake libusb maven nasm yasm xz pkg-config
-    ```
-
-After which the following commands can be used to start the build inside the `javacpp-presets` directory:
-```bash
-$ bash cppbuild.sh install
-$ mvn clean install
-```
-
-
-Windows (x86 and x86_64)
-------------------------
-Visual Studio Community 2013 is the first free version to have been decently bundled with support for C++11, OpenMP, the Windows SDK, and everything else from Microsoft, so we recommend installing that version of Visual Studio, which consequently requires Windows 7. Still, to run the bash scripts and compile some things that the Microsoft C/C++ Compiler does not support, we need to install manually a few other things.
-
-### Preparations
-1. Install the [Java SE Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/), [Maven](https://maven.apache.org/download.cgi), [MSYS2](https://msys2.github.io/), [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx), and [CUDA](https://developer.nvidia.com/cuda-downloads)
-2. Under an "MSYS2 Shell", run:
-
-    ```bash
-    $ pacman -S base-devel tar patch make git unzip zip nasm yasm pkg-config mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-i686-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-i686-gcc-fortran mingw-w64-x86_64-libwinpthread-git mingw-w64-i686-libwinpthread-git
-    ```
-
-3. From the "Visual Studio Tools" found inside the Start menu, open:
-    - "VS2013 x86 Native Tools Command Prompt" and run `c:\msys64\mingw32_shell.bat` inside
-    - "VS2013 x64 Native Tools Command Prompt" and run `c:\msys64\mingw64_shell.bat` inside
-    - Making sure the `set MSYS2_PATH_TYPE=inherit` line is *not* commented out in either of those batch files.
-
-4. Run the "Prerequisites for all platforms" tasks inside the shell
-
-Afterwards the following commands can be used to start the build inside the `javacpp-presets` directory:
-```bash
-$ bash cppbuild.sh -platform windows-xxx install
-$ mvn clean install -Djavacpp.platform=windows-xxx
-```
-where `windows-xxx` is either `windows-x86` or `windows-x86_64`. Run the builds for `windows-x86` inside the "MINGW32" window, and the ones for `windows-x86_64` in the "MINGW64" one.
-
-
+
+These are instructions taken from JavaCV website to write the instructions above. We keep a copy here to make sure the instructions we have are compatible with out version of javacpp-presets. 
+
+
+** NOTE: **
+ Taken from https://github.com/bytedeco/javacpp-presets/wiki/Build-Environments
+
+Introduction
+------------
+This page contains a description of the environments that are used to build the JavaCPP Presets for [Android (ARM and x86)](#android-arm-and-x86), [Linux (x86 and x86_64)](#linux-x86-and-x86_64), [Linux (ARM)](#linux-arm), [Mac OS X (x86_64)](#mac-os-x-x86_64), and [Windows (x86 and x86_64)](#windows-x86-and-x86_64). We also explain our choices given the requirements and provide some recommendations. Furthermore, JavaCPP is by no means limited to these platforms, so if you happen to know how to set up an environment for other platforms, by all means, please do add that information to this page to share with others. Thank you!
+
+
+Prerequisites for all platforms
+-------------------------------
+The build process for the modules of `javacpp-presets` usually depends on the same version of the `javacpp` module. To insure that you have the latest matching version of both, please execute the following before starting the build in the `javacpp-presets` directory:
+```bash
+$ git clone https://github.com/bytedeco/javacpp.git --branch <tag>
+$ git clone https://github.com/bytedeco/javacpp-presets.git --branch <tag>
+$ cd javacpp
+$ mvn clean install
+```
+For the latest tag please check
+https://github.com/bytedeco/javacpp-presets/tags
+
+Android (ARM and x86)
+---------------------
+To produce native libraries for Android, we basically only need to install the JDK and the NDK, which is available for Linux, Mac OS X, and Windows. However, the build scripts of some libraries only run correctly under Linux, so we recommend using a recent distribution of Linux (such as Fedora or Ubuntu) as build environment for Android.
+
+### Preparations
+1. Download the latest version of the [NDK](https://developer.android.com/ndk/downloads/), which is r10e at the time of this writing and contains important fixes for OpenMP, among other things
+2. Install the NDK under `~/Android/android-ndk`, where the build scripts will look for it by default
+3. Finally, make sure to have installed at least OpenJDK and Maven as per the instructions of your distribution
+
+After which the following commands can be used to start the build inside the `javacpp-presets` directory:
+```bash
+$ ANDROID_NDK=/path/to/android-ndk/ bash cppbuild.sh -platform android-xxx install
+$ mvn clean install -Djavacpp.platform=android-xxx -Djavacpp.platform.root=/path/to/android-ndk/ -Djavacpp.platform.compiler=/path/to/target-g++
+```
+where `android-xxx` is either `android-arm` or `android-x86`, and where `target-g++` is either `arm-linux-androideabi-g++` or `i686-linux-android-g++`.
+
+
+Linux (x86 and x86_64)
+----------------------
+To produce native libraries that can run on the largest possible number of Linux installations out there, it is recommended to build under CentOS 7. This is because it relies on an old enough version of glibc, which nevertheless works for all the libraries found in the JavaCPP Presets, and since newer versions of glibc are backward compatible, all recent distributions of Linux should support the binaries generated. We do not actually need to install CentOS 7 though. Pretty much any recent distribution of Linux comes with a package for [Docker](https://www.docker.com/). It is also possible to map existing directories, for example `/usr/local/lib/bazel` and `/usr/local/cuda` as shown in the steps below, to reuse an existing [Bazel](http://bazel.io/docs/install.html) or [CUDA](https://developer.nvidia.com/cuda-downloads) installation as well as any other set of files for the purpose of the build.
+
+### Preparations
+1. Install Docker under, for example, Fedora and Ubuntu, respectively:
+
+    ```bash
+    $ sudo yum install docker
+    $ sudo apt-get install docker.io
+    ```
+
+2. When using SELinux, it might also be necessary to disable temporarily the firewall, for example:
+
+    ```
+    $ sudo systemctl stop firewalld
+    $ sudo systemctl start docker
+    ```
+
+3. Start the container for CentOS 7 (the command might be `docker.io` instead of `docker`):
+
+    ```bash
+    $ sudo docker run --privileged -it -v /usr/local/lib/bazel:/usr/local/lib/bazel -v /usr/local/cuda:/usr/local/cuda centos:7 /bin/bash
+    ```
+
+4. Finally, inside the container, we need to install a bunch of things:
+
+    ```bash
+    $ ln -s /usr/local/lib/bazel/bin/bazel /usr/local/bin/bazel
+    $ yum install epel-release
+    $ yum install clang gcc-c++ gcc-gfortran java-devel maven python numpy swig git file which wget unzip tar bzip2 gzip xz patch make cmake3 perl nasm yasm alsa-lib-devel freeglut-devel gtk2-devel libusb-devel libusb1-devel zlib-devel
+    $ yum install `rpm -qa | sed s/.x86_64$/.i686/`
+    ```
+
+After which the following commands can be used to start the build inside the `javacpp-presets` directory:
+```bash
+$ bash cppbuild.sh -platform linux-xxx install
+$ mvn clean install -Djavacpp.platform=linux-xxx
+```
+where `linux-xxx` is either `linux-x86` or `linux-x86_64`.
+
+
+Linux (ARM)
+-----------
+There are a growing number of arm platforms running Linux, though testing of this build has mainly focussed on the Pi family of products. Compiling natively on these platforms can be quite time consuming, and as well to automate the build process, the build setup here relies on cross-compiling for the target arm platform. This has been tested using Ubuntu x64 15.10, but it should be reasonably similar approach for other host OS's. 
+
+You'll need to have setup a build environment with the usual packages (pkgconfig, build-essentials, yasm, nasm, maven3, etc). The major addition you'll need is a set of cross compilers: arm-linux-gnueabihf-gcc, arm-linux-gnueabihf-g++ and arm-linux-gnueabihf-cpp. It's best to get these via your OS's package manager, as there are other dependencies for these. 
+
+Originally a 5.x compiler was used, but this seems to caused problems in creating a dependency on newer glibc functionality which might not be present on your target arm device. The 4.8 or 4.9 version of the compiler seems to work fine, but, in targetting support for the Pi1 and well as Pi2-Pi3 (i.e. arm6 as well as arm7) it seems some compiler flag combinations might not be support by the standard gnueabihf compiler toolchain. 
+
+There are pi specific compilers available, so these have been used in the current setup. 
+
+1. Get the Pi tools: git clone https://github.com/raspberrypi/tools.git
+2. From this folder, move out a specific compiler version to a more generic location: sudo cp -r ./tools/arm-bcm2708/arm-bcm2708-linux-gnueabi /opt
+3. Setup alternatives of the generic compiler names in /usr/bin to point to this new compiler 
+
+    ```bash
+    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-gcc arm-linux-gnueabihf-gcc /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-gcc 46
+    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-g++ arm-linux-gnueabihf-g++ /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-g++ 46
+    $ update-alternatives --install /usr/bin/arm-linux-gnueabihf-cpp arm-linux-gnueabihf-cpp /opt/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-cpp 46
+    ```
+
+   (This way if you want to explore using other newer compilers, just add them to alternatives and the same build setup should work fine)
+
+This should now have you setup ready to build for arm. It could be an idea to test at this stage with building a simple hello world executable (save your hello world test code as hello.cpp):
+
+    $ arm-linux-gnueabihf-g++ -O3 -g3 -Wall -fPIC -march=armv6 -mfpu=vfp -mfloat-abi=hard hello.cpp -c -o hello.o 
+    $ arm-linux-gnueabihf-g++ -o hello hello.o 
+    $ file hello
+
+And you should see in the returned info that hello is built for ARM
+
+With the build environment setup, now its on to building JavaCV. Not all components have been setup with the linux-armhf build configurations, so rather than building the entire project only a subset are built here, but enough to have core functionality (OpenCV, FFmpeg) working with some additional parts (artoolkitplus, flycapture, flandmark, libfreenect, libdc1394) built but not tested. For flycapture, you need to download the arm SDK (currently flycapture.2.9.3.13_armhf) and make these .so libs available, either in your path, or setting up a /usr/include/flycapture directory and moving them there. 
+
+Now all the dependencies are setup, the build can be started (assuming you've done a git clone of javacv, javacpp and javacpp-presets all to the same folder)
+
+    $ cd javacpp
+    $ mvn install
+    $ cd ..
+    $ cd javacpp-presets
+    $ ./cppbuild.sh -platform linux-armhf install
+    $ mvn install -Djavacpp.platform=linux-armhf -Djavacpp.platform.compiler=arm-linux-gnueabihf-g++
+    $ cd platform
+    $ mvn install -Djavacpp.platform=linux-armhf
+
+Hopefully that all runs OK, and then in ./javacpp-presets/platform/target/ you should find there are platform specific (opencv-linux-armhf.jar, ffmpeg-linux-armhf.jar, etc) files built.
+
+If you want to try alternative flags, you need to modify in javacpp, ./src/main/resources/org/bytedeco/javacpp/properties/linux-armhf.properties and then in javacpp-presets any project cppbuild.sh file where you want to update too (e.g. ./opencv/cppbuild.sh linux-armhf section). For newer Pis on arm7 it does look like there are potential performance gains in armv7 and neon flags, and using a newer compiler rather than the bcm2708 build used here may further improve things (some earlier builds specific for armv7 did look faster). Also if you are using onboard picam devices, make sure you load the module with "modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944" - this way if you test just using OpenCV or FFMPEG grabber you should get at least 30fps as a start point. The more computation you then do on each frame, the more this will drop.
+
+
+Mac OS X (x86_64)
+-----------------
+OS X Mavericks (10.9) is the first version of Mac OS X to support C++11 fully and properly, so to preserve your sanity, we do not recommend trying to build or use the JavaCPP Presets on any older versions of Mac OS X.
+
+### Preparations
+1. Install [Xcode](https://developer.apple.com/xcode/) and [Homebrew](http://brew.sh/)
+2. Ensure the command line tools for Xcode are installed
+
+    ```bash
+    $ xcode-select --install
+    ```
+3. Run the following commands to install the JDK, among other things Apple left out of Xcode:
+
+    ```bash
+    $ brew install caskroom/cask/brew-cask
+    $ brew cask install cuda java
+    $ brew install gcc5 swig bazel cmake libusb maven nasm yasm xz pkg-config
+    ```
+
+After which the following commands can be used to start the build inside the `javacpp-presets` directory:
+```bash
+$ bash cppbuild.sh install
+$ mvn clean install
+```
+
+
+Windows (x86 and x86_64)
+------------------------
+Visual Studio Community 2013 is the first free version to have been decently bundled with support for C++11, OpenMP, the Windows SDK, and everything else from Microsoft, so we recommend installing that version of Visual Studio, which consequently requires Windows 7. Still, to run the bash scripts and compile some things that the Microsoft C/C++ Compiler does not support, we need to install manually a few other things.
+
+### Preparations
+1. Install the [Java SE Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/), [Maven](https://maven.apache.org/download.cgi), [MSYS2](https://msys2.github.io/), [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx), and [CUDA](https://developer.nvidia.com/cuda-downloads)
+2. Under an "MSYS2 Shell", run:
+
+    ```bash
+    $ pacman -S base-devel tar patch make git unzip zip nasm yasm pkg-config mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-i686-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-i686-gcc-fortran mingw-w64-x86_64-libwinpthread-git mingw-w64-i686-libwinpthread-git
+    ```
+
+3. From the "Visual Studio Tools" found inside the Start menu, open:
+    - "VS2013 x86 Native Tools Command Prompt" and run `c:\msys64\mingw32_shell.bat` inside
+    - "VS2013 x64 Native Tools Command Prompt" and run `c:\msys64\mingw64_shell.bat` inside
+    - Making sure the `set MSYS2_PATH_TYPE=inherit` line is *not* commented out in either of those batch files.
+
+4. Run the "Prerequisites for all platforms" tasks inside the shell
+
+Afterwards the following commands can be used to start the build inside the `javacpp-presets` directory:
+```bash
+$ bash cppbuild.sh -platform windows-xxx install
+$ mvn clean install -Djavacpp.platform=windows-xxx
+```
+where `windows-xxx` is either `windows-x86` or `windows-x86_64`. Run the builds for `windows-x86` inside the "MINGW32" window, and the ones for `windows-x86_64` in the "MINGW64" one.
+
+
diff --git a/bbb-screenshare/README.md b/bbb-screenshare/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..0e43815737827655dc3e54d6e221ea988745098e
--- /dev/null
+++ b/bbb-screenshare/README.md
@@ -0,0 +1,176 @@
+This document contains instructions on how to build your own native libraries, screenshare webstart app, and how to deploy screenshare application.
+
+
+Building your own native libraries
+----------------------------------
+
+Linux (x86 and x86_64)
+----------------------
+To produce native libraries that can run on the largest possible number of Linux installations out there, it is recommended to build under CentOS 7. This is because it relies on an old enough version of glibc, which nevertheless works for all the libraries found in the JavaCPP Presets, and since newer versions of glibc are backward compatible, all recent distributions of Linux should support the binaries generated. We do not actually need to install CentOS 7 though. Pretty much any recent distribution of Linux comes with a package for [Docker](https://www.docker.com/). It is also possible to map existing directories, for example `/usr/local/lib/bazel` and `/usr/local/cuda` as shown in the steps below, to reuse an existing [Bazel](http://bazel.io/docs/install.html) or [CUDA](https://developer.nvidia.com/cuda-downloads) installation as well as any other set of files for the purpose of the build.
+
+### Preparations
+1. Install Docker under, for example, Fedora and Ubuntu, respectively:
+
+    ```bash
+    $ sudo yum install docker
+    $ sudo apt-get install docker.io
+    ```
+
+2. When using SELinux, it might also be necessary to disable temporarily the firewall, for example:
+
+    ```
+    $ sudo systemctl stop firewalld
+    $ sudo systemctl start docker
+    ```
+
+3. Start the container for CentOS 7 (the command might be `docker.io` instead of `docker`):
+
+    ```bash
+    $ sudo docker run --privileged -it -v /usr/local/lib/bazel:/usr/local/lib/bazel -v /usr/local/cuda:/usr/local/cuda centos:7 /bin/bash
+    ```
+
+4. Finally, inside the container, we need to install a bunch of things:
+
+    ```bash
+    $ ln -s /usr/local/lib/bazel/bin/bazel /usr/local/bin/bazel
+    $ yum install epel-release
+    $ yum install clang gcc-c++ gcc-gfortran java-devel maven python numpy swig git file which wget unzip tar bzip2 gzip xz patch make cmake3 perl nasm yasm alsa-lib-devel freeglut-devel gtk2-devel libusb-devel libusb1-devel zlib-devel
+    $ yum install `rpm -qa | sed s/.x86_64$/.i686/`
+    ```
+
+5. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
+
+6. cd to `javacpp-presets/ffmpeg`
+
+7. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
+
+8. After which the following commands inside the `ffmpeg` dir:
+
+```bash
+ bash cppbuild.sh -platform linux-xxx install
+
+ mvn clean install -Djavacpp.platform=linux-xxx
+```
+
+where `linux-xxx` is either `linux-x86` or `linux-x86_64`.
+
+If things go well, copy the resulting jar into `native-libs/ffmpeg-linux-xxx` and sign the jar.
+
+
+Mac OS X (x86_64)
+-----------------
+OS X Mavericks (10.9) is the first version of Mac OS X to support C++11 fully and properly, so to preserve your sanity, we do not recommend trying to build or use the JavaCPP Presets on any older versions of Mac OS X.
+
+### Preparations
+1. Install [Xcode](https://developer.apple.com/xcode/) and [Homebrew](http://brew.sh/)
+2. Ensure the command line tools for Xcode are installed
+
+    ```bash
+    $ xcode-select --install
+    ```
+3. Run the following commands to install the JDK, among other things Apple left out of Xcode:
+
+    ```bash
+    $ brew install caskroom/cask/brew-cask
+    $ brew cask install cuda java
+    $ brew install gcc5 swig bazel cmake libusb maven nasm yasm xz pkg-config
+    ```
+
+4. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
+
+5. cd to `javacpp-presets/ffmpeg`
+
+6. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
+
+7. After which the following commands inside the `ffmpeg` dir:
+
+```bash
+$ bash cppbuild.sh install
+$ mvn clean install
+```
+
+
+If things go well, copy the resulting jar into `native-libs/ffmpeg-macosx-x86_64` and sign the jar.
+
+
+Windows (x86 and x86_64)
+------------------------
+Visual Studio Community 2013 is the first free version to have been decently bundled with support for C++11, OpenMP, the Windows SDK, and everything else from Microsoft, so we recommend installing that version of Visual Studio, which consequently requires Windows 7. Still, to run the bash scripts and compile some things that the Microsoft C/C++ Compiler does not support, we need to install manually a few other things.
+
+### Preparations
+1. Install the [Java SE Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/), [Maven](https://maven.apache.org/download.cgi), [MSYS2](https://msys2.github.io/), [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx), and [CUDA](https://developer.nvidia.com/cuda-downloads)
+2. Under an "MSYS2 Shell", run:
+
+    ```bash
+    $ pacman -S base-devel tar patch make git unzip zip nasm yasm pkg-config mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-i686-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-i686-gcc-fortran mingw-w64-x86_64-libwinpthread-git mingw-w64-i686-libwinpthread-git
+    ```
+
+3. From the "Visual Studio Tools" found inside the Start menu, open:
+    - "VS2013 x86 Native Tools Command Prompt" and run `c:\msys64\mingw32_shell.bat` inside
+    - "VS2013 x64 Native Tools Command Prompt" and run `c:\msys64\mingw64_shell.bat` inside
+    - Making sure the `set MSYS2_PATH_TYPE=inherit` line is *not* commented out in either of those batch files.
+
+4. Run the "Prerequisites for all platforms" tasks inside the shell
+
+5. Checkout `https://github.com/bigbluebutton/javacpp-presets` and use branch `min-build-1.2-svc2`
+
+6. cd to `javacpp-presets/ffmpeg`
+
+7. If you want to build SVC2 libraries, you copy `cppbuild.sh.svc2` to `cppbuild.sh`
+
+8. After which the following commands inside the `ffmpeg` dir:
+
+```bash
+$ bash cppbuild.sh -platform windows-xxx install
+$ mvn clean install -Djavacpp.platform=windows-xxx
+```
+where `windows-xxx` is either `windows-x86` or `windows-x86_64`. Run the builds for `windows-x86` inside the "MINGW32" window, and the ones for `windows-x86_64` in the "MINGW64" one.
+
+If things go well, copy the resulting jar into `native-libs/ffmpeg-windows-xxx` and sign the jar.
+
+
+Signing the jar files
+---------------------
+
+To sign the native libraries, cd to the location of the jar. Copy tour cert into the dir and run `sign-jar.sh`. You will be prompted for
+your cert file and password of your cert.
+
+Example:
+
+```
+ cd ffmpeg-linux-x86/svc2
+
+ Copy your cert into this directory
+
+ ./sign-jar.sh
+
+ You will be prompted for your cert file and password.
+
+```
+
+The resulting signed jar file will be in `bbb-screenshare/apps/jws/lib`
+
+Aside from the native jar files, you will need to sign the `ffmpeg.jar` found in `jws/signed-jars`. Follow the README doc in that directory.
+
+
+Building screenshare webstart application
+-----------------------------------------
+
+1. Go to `jws/webstart` directory. 
+
+2. Copy your cert into the dir.
+
+3. Run `build.sh` and you will be prompted for your cert file and cert password in order to sign the jar file.
+
+
+Deploying and testing the screenshare application
+-------------------------------------------------
+
+1. Go to `app` directory.
+
+2. Edit `src/main/webapp/WEB-INF/screenshare.properties` to point to your server's IP address.
+
+3. Run `deploy.sh` to build the whole application and deploy to your local red5 server.
+
+
+
diff --git a/bbb-screenshare/app/jws/lib/ffmpeg-svc2.jar b/bbb-screenshare/app/jws/lib/ffmpeg-svc2.jar
deleted file mode 100644
index a2d74e5f2ae110ba99595876d4ebfaa208c1004f..0000000000000000000000000000000000000000
Binary files a/bbb-screenshare/app/jws/lib/ffmpeg-svc2.jar and /dev/null differ
diff --git a/bbb-screenshare/app/jws/lib/javacpp.jar b/bbb-screenshare/app/jws/lib/javacpp.jar
deleted file mode 100755
index 485a3a4c534fe5017cfa82c8d226b3ede1e681eb..0000000000000000000000000000000000000000
Binary files a/bbb-screenshare/app/jws/lib/javacpp.jar and /dev/null differ
diff --git a/bbb-screenshare/app/jws/lib/javacv.jar b/bbb-screenshare/app/jws/lib/javacv.jar
deleted file mode 100755
index 21265aca56ca352877d1a34aa27504d48119dbab..0000000000000000000000000000000000000000
Binary files a/bbb-screenshare/app/jws/lib/javacv.jar and /dev/null differ
diff --git a/bbb-screenshare/app/src/main/webapp/WEB-INF/screenshare.properties b/bbb-screenshare/app/src/main/webapp/WEB-INF/screenshare.properties
index 3a2c18f6ad2959c134b4ae20891811900a55a592..55bd99c50f97b91fe009d1446db69a6948d04348 100755
--- a/bbb-screenshare/app/src/main/webapp/WEB-INF/screenshare.properties
+++ b/bbb-screenshare/app/src/main/webapp/WEB-INF/screenshare.properties
@@ -1,30 +1,30 @@
-#
-# NOTE: default properties.
-#
-# NOTE!!!! NOTE!!!! NOTE!!!! NOTE!!!! NOTE!!!!
-# When making changes that you don't want checked-in, do
-#   git update-index --assume-unchanged <file>
-#
-# To have git track the changes again
-# 	git update-index --no-assume-unchanged <file>
-#
-
-recordingDirectory=/usr/share/red5/webapps/screenshare/streams
-
-redis.host=127.0.0.1
-redis.port=6379
-
-
-streamBaseUrl=rtmp://192.168.23.53/screenshare
-jnlpUrl=http://192.168.23.53/screenshare
-jnlpFile=http://192.168.23.53/screenshare/screenshare.jnlp
-useH264=false
-
-# NOTES:
-# 1. GOP (group of pictures) is calculated as frameRate * keyFrameInterval
-# 2. intra-refresh=1 doesn't work in Chrome. Late comers can't view the stream as 
-#    the user missed the key frame
-# 3. keyFrameInterval is in seconds
-# 4. Make sure you encode & into &amp; as it will break the JNLP XML
-#codecOptions=crf=36&amp;preset=veryfast&amp;tune=animation,zerolatency&amp;frameRate=12.0&amp;keyFrameInterval=6
-codecOptions=crf=38&amp;preset=veryfast&amp;tune=zerolatency&amp;frameRate=5.0&amp;keyFrameInterval=5
+#
+# NOTE: default properties.
+#
+# NOTE!!!! NOTE!!!! NOTE!!!! NOTE!!!! NOTE!!!!
+# When making changes that you don't want checked-in, do
+#   git update-index --assume-unchanged <file>
+#
+# To have git track the changes again
+# 	git update-index --no-assume-unchanged <file>
+#
+
+recordingDirectory=/usr/share/red5/webapps/screenshare/streams
+
+redis.host=127.0.0.1
+redis.port=6379
+
+
+streamBaseUrl=rtmp://192.168.23.22/screenshare
+jnlpUrl=http://192.168.23.22/screenshare
+jnlpFile=http://192.168.23.22/screenshare/screenshare.jnlp
+useH264=false
+
+# NOTES:
+# 1. GOP (group of pictures) is calculated as frameRate * keyFrameInterval
+# 2. intra-refresh=1 doesn't work in Chrome. Late comers can't view the stream as 
+#    the user missed the key frame
+# 3. keyFrameInterval is in seconds
+# 4. Make sure you encode & into &amp; as it will break the JNLP XML
+#codecOptions=crf=36&amp;preset=veryfast&amp;tune=animation,zerolatency&amp;frameRate=12.0&amp;keyFrameInterval=6
+codecOptions=crf=38&amp;preset=veryfast&amp;tune=zerolatency&amp;frameRate=5.0&amp;keyFrameInterval=5
diff --git a/bbb-screenshare/jws/README.md b/bbb-screenshare/jws/README.md
deleted file mode 100755
index 298cd0f33315127b396a1b0d79ed35383fcfa62e..0000000000000000000000000000000000000000
--- a/bbb-screenshare/jws/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# bigbluebutton-screenshare
diff --git a/bbb-screenshare/jws/native-libs/unsigned-jars/README.md b/bbb-screenshare/jws/native-libs/unsigned-jars/README.md
index 562a962044c8d3df8fc9bbd904b4924d1d4b8d0b..3d94ad1d0f56f29529ec58918dac62c63d2247dd 100755
--- a/bbb-screenshare/jws/native-libs/unsigned-jars/README.md
+++ b/bbb-screenshare/jws/native-libs/unsigned-jars/README.md
@@ -1,11 +1,15 @@
+=== Signing jars ===
 
-To sign the ffmpeg.jar and javacpp.jar, copy them to the ```workdir``` directory and
-run "```ant sign-ffmpeg-jar```" or "```ant sign-javacpp-jar```".
+In this version of screenshare, you only need to sign `ffmpeg.jar`.
 
-The resulting jar files will now be signed. To verify, run
+Copy your certificate in this directory and run `sign-ffmpeg.sh`. It will prompt for
+your cert file as well as password of your cert file.
+
+The resulting signed jar file will be found in `bbb-screenshare/apps/jws/lib`
+
+To verify that the jar has been signed, run
 
 ```
    jarsigner -verify ffmpeg.jar
-   jarsigner -verify javacpp.jar
 ```   
 
diff --git a/bbb-screenshare/jws/native-libs/unsigned-jars/ffmpeg-3.0.2-1.2-svc2.jar b/bbb-screenshare/jws/native-libs/unsigned-jars/ffmpeg-3.0.2-1.2-svc2.jar
deleted file mode 100755
index 9ef2ae226273b97e27197045c5253d1d62a74414..0000000000000000000000000000000000000000
Binary files a/bbb-screenshare/jws/native-libs/unsigned-jars/ffmpeg-3.0.2-1.2-svc2.jar and /dev/null differ
diff --git a/bbb-screenshare/jws/native-libs/unsigned-jars/sign-ffmpeg-svc2.sh b/bbb-screenshare/jws/native-libs/unsigned-jars/sign-ffmpeg-svc2.sh
deleted file mode 100755
index d5d8d74129a7167aa7969ac682eb6ffc52639bcd..0000000000000000000000000000000000000000
--- a/bbb-screenshare/jws/native-libs/unsigned-jars/sign-ffmpeg-svc2.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-FFMPEG=ffmpeg-3.0.2-1.2-svc2.jar
-if [ -d "workdir" ]; then
-  rm -rf workdir
-fi
-mkdir workdir
-cp $FFMPEG workdir
-cd workdir
-jar xf $FFMPEG
-rm $FFMPEG
-rm -rf META-INF
-jar cf ffmpeg.jar *
-cd ..
-ant sign-ffmpeg-jar
-cp workdir/ffmpeg.jar ../../../app/jws/lib/ffmpeg-svc2.jar
-rm -rf workdir
-
diff --git a/bbb-screenshare/jws/webstart/build.sh b/bbb-screenshare/jws/webstart/build.sh
index 34699d94eee59075fb36db407b5bd8ef784fe04d..7074eba05053fb7e50983b4a92274174da04f6fd 100755
--- a/bbb-screenshare/jws/webstart/build.sh
+++ b/bbb-screenshare/jws/webstart/build.sh
@@ -2,9 +2,7 @@ if [ -d "lib" ]; then
   rm -rf lib
 fi
 mkdir lib
-cp ../../app/jws/lib/*.jar lib
-rm lib/javacv.jar
-rm lib/javacpp.jar
+cp ../../app/jws/lib/ffmpeg.jar lib
 gradle clean
 gradle jar
 ant sign-jar
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 ce1c25bb2329733c64c0dad0034ac1260f29e624..5a7cb7262875765ddc91c2d8045d7639f73d662e 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
@@ -36,16 +36,20 @@ import org.red5.server.stream.ClientBroadcastStream;
 import org.slf4j.Logger;
 
 import com.google.gson.Gson;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 
 public class VideoApplication extends MultiThreadedApplicationAdapter {
 	private static Logger log = Red5LoggerFactory.getLogger(VideoApplication.class, "video");
 
 	private MessagePublisher publisher;
-	private boolean recordVideoStream = false;
 	private EventRecordingService recordingService;
 	private final Map<String, IStreamListener> streamListeners = new HashMap<String, IStreamListener>();
 	
 	private int packetTimeout = 10000;
+
+	private final Pattern RECORD_STREAM_ID_PATTERN = Pattern.compile("(.*)(-recorded)$");
 	
     @Override
 	public boolean appStart(IScope app) {
@@ -190,14 +194,21 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     	String meetingId = conn.getScope().getName();
     	String streamId = stream.getPublishedName();
 
-    	VideoStreamListener listener = new VideoStreamListener(conn.getScope(), stream, recordVideoStream, userId, packetTimeout);
-        listener.setEventRecordingService(recordingService);
-        stream.addStreamListener(listener); 
-        streamListeners.put(conn.getScope().getName() + "-" + stream.getPublishedName(), listener);
-        
-        if (recordVideoStream) {
-	    	recordStream(stream);
-        }
+
+			Matcher matcher = RECORD_STREAM_ID_PATTERN.matcher(stream.getPublishedName());
+			if (matcher.matches()) {
+				log.info("Start recording of stream=[" + stream.getPublishedName() + "] for meeting=[" + conn.getScope().getName() + "]");
+				Boolean recordVideoStream = true;
+
+				VideoStreamListener listener = new VideoStreamListener(conn.getScope(), stream, recordVideoStream, userId, packetTimeout);
+				listener.setEventRecordingService(recordingService);
+				stream.addStreamListener(listener);
+				streamListeners.put(conn.getScope().getName() + "-" + stream.getPublishedName(), listener);
+
+				recordStream(stream);
+			}
+
+
     }
 
     private Long genTimestamp() {
@@ -222,24 +233,26 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
   		String meetingId = conn.getScope().getName();
   		String streamId = stream.getPublishedName();
 
-        IStreamListener listener = streamListeners.remove(scopeName + "-" + stream.getPublishedName());
-        if (listener != null) {
-        	((VideoStreamListener) listener).streamStopped();
-        	stream.removeStreamListener(listener);
-        }
-        
-      if (recordVideoStream) {        
-        long publishDuration = (System.currentTimeMillis() - stream.getCreationTime()) / 1000;
-        log.info("Stop recording event for stream=[{}] meeting=[{}]", stream.getPublishedName(), scopeName);
-        Map<String, String> event = new HashMap<String, String>();
-        event.put("module", "WEBCAM");
-        event.put("timestamp", genTimestamp().toString());
-        event.put("meetingId", scopeName);
-        event.put("stream", stream.getPublishedName());
-        event.put("duration", new Long(publishDuration).toString());
-        event.put("eventName", "StopWebcamShareEvent");
-        recordingService.record(scopeName, event);    		
-      }
+			Matcher matcher = RECORD_STREAM_ID_PATTERN.matcher(stream.getPublishedName());
+			if (matcher.matches()) {
+				IStreamListener listener = streamListeners.remove(scopeName + "-" + stream.getPublishedName());
+				if (listener != null) {
+					((VideoStreamListener) listener).streamStopped();
+					stream.removeStreamListener(listener);
+				}
+
+				long publishDuration = (System.currentTimeMillis() - stream.getCreationTime()) / 1000;
+				log.info("Stop recording event for stream=[{}] meeting=[{}]", stream.getPublishedName(), scopeName);
+				Map<String, String> event = new HashMap<String, String>();
+				event.put("module", "WEBCAM");
+				event.put("timestamp", genTimestamp().toString());
+				event.put("meetingId", scopeName);
+				event.put("stream", stream.getPublishedName());
+				event.put("duration", new Long(publishDuration).toString());
+				event.put("eventName", "StopWebcamShareEvent");
+				recordingService.record(scopeName, event);
+
+			}
     }
     
     /**
@@ -261,10 +274,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     	}    	
     }
 
-	public void setRecordVideoStream(boolean recordVideoStream) {
-		this.recordVideoStream = recordVideoStream;
-	}
-	
+
 	public void setPacketTimeout(int timeout) {
 		this.packetTimeout = timeout;
 	}
diff --git a/bbb-video/src/main/webapp/WEB-INF/red5-web.xml b/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
index d54025f7932706365e310eb57999f918870158ff..1ea5e9f5b363741d2198517b5ef9681e74ff3bd7 100755
--- a/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
+++ b/bbb-video/src/main/webapp/WEB-INF/red5-web.xml
@@ -47,7 +47,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 	<bean id="web.handler" class="org.bigbluebutton.app.video.VideoApplication">
 	   <property name="packetTimeout" value="10000"/>
-		<property name="recordVideoStream" value="true"/>
 		<property name="eventRecordingService" ref="redisRecorder"/>
 		<property name="messagePublisher" ref="redisPublisher"/>
 	</bean>
diff --git a/bigbluebutton-client/branding/default/style/css/BBBDefault.css b/bigbluebutton-client/branding/default/style/css/BBBDefault.css
index fdda4d8cc12ea576a6ff4ffb467ec19ce346b717..c01fee75e8f5e8c1863eeb28e9592ca4f8ec665d 100755
--- a/bigbluebutton-client/branding/default/style/css/BBBDefault.css
+++ b/bigbluebutton-client/branding/default/style/css/BBBDefault.css
@@ -1043,6 +1043,11 @@ PollChoicesModal {
 	fontFamily: Arial;
 }
 
+.chatMessageListStyle {
+	rollOverColor: #ffffff;
+	selectionColor: #f3f3f3;
+}
+
 EmojiGrid {
 	backgroundColor: #ffffff;
 	horizontalAlign: center;
diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties
index fa6e9638ca21aaa64c925c16444ce98c19a91ba9..f226af0f384db6c1590e15c35d552067afc18abf 100755
--- a/bigbluebutton-client/locale/en_US/bbbResources.properties
+++ b/bigbluebutton-client/locale/en_US/bbbResources.properties
@@ -2,7 +2,7 @@ bbb.mainshell.locale.version = 0.9.0
 bbb.mainshell.statusProgress.connecting = Connecting to the server
 bbb.mainshell.statusProgress.loading = Loading {0} modules
 bbb.mainshell.statusProgress.cannotConnectServer = Sorry, we cannot connect to the server.
-bbb.mainshell.copyrightLabel2 = (c) 2016 <a href='event:http://www.bigbluebutton.org/' target='_blank'><u>BigBlueButton Inc.</u></a> (build {0})
+bbb.mainshell.copyrightLabel2 = (c) 2017 <a href='event:http://www.bigbluebutton.org/' target='_blank'><u>BigBlueButton Inc.</u></a> (build {0})
 bbb.mainshell.logBtn.toolTip = Open Log Window
 bbb.mainshell.meetingNotFound = Meeting Not Found
 bbb.mainshell.invalidAuthToken = Invalid Authentication Token
@@ -249,12 +249,13 @@ bbb.chat.usersList.accessibilityName = Select user to open private chat. Use the
 bbb.chat.chatOptions = Chat Options
 bbb.chat.fontSize = Chat Message Font Size
 bbb.chat.cmbFontSize.toolTip = Select Chat Message Font Size
-bbb.chat.messageList = Message Box
+bbb.chat.messageList = Chat Messages
 bbb.chat.minimizeBtn.accessibilityName = Minimize the Chat Window
 bbb.chat.maximizeRestoreBtn.accessibilityName = Maximize the Chat Window
 bbb.chat.closeBtn.accessibilityName = Close the Chat Window
 bbb.chat.chatTabs.accessibleNotice = New messages in this tab.
 bbb.chat.chatMessage.systemMessage = System
+bbb.chat.chatMessage.stringRespresentation = From {0} {1} at {2}
 bbb.chat.chatMessage.tooLong = The message is {0} character(s) too long
 bbb.publishVideo.changeCameraBtn.labelText = Change Webcam
 bbb.publishVideo.changeCameraBtn.toolTip = Open the change webcam dialog box
@@ -287,10 +288,11 @@ bbb.video.streamClose.toolTip = Close stream for: {0}
 bbb.screensharePublish.title = Screen Sharing: Presenter's Preview
 bbb.screensharePublish.pause.tooltip = Pause screen share
 bbb.screensharePublish.pause.label = Pause
-bbb.screensharePublish.restart.tooltip = Restart screen share
-bbb.screensharePublish.restart.label = Restart
+bbb.screensharePublish.restart.tooltip = Resume screen share
+bbb.screensharePublish.restart.label = Resume
 bbb.screensharePublish.maximizeRestoreBtn.toolTip = You cannot maximize this window.
 bbb.screensharePublish.closeBtn.toolTip = Stop Sharing and Close
+bbb.screensharePublish.closeBtn.accessibilityName = Stop Sharing and Close Screen Sharing Publish Window
 bbb.screensharePublish.minimizeBtn.toolTip = Minimize
 bbb.screensharePublish.minimizeBtn.accessibilityName = Minimize the Screen Sharing Publish Window
 bbb.screensharePublish.maximizeRestoreBtn.accessibilityName = Maximize the Screen Sharing Publish Window
@@ -332,6 +334,8 @@ bbb.screensharePublish.startFailed.label = Did not detect start of screen sharin
 bbb.screensharePublish.restartFailed.label = Did not detect restart of screen sharing.
 bbb.screensharePublish.jwsCrashed.label = The screen sharing application closed unexpectedly. 
 bbb.screensharePublish.commonErrorMessage.label = Select 'Cancel' and try again.
+bbb.screensharePublish.tunnelingErrorMessage.one = Screen Sharing is unable to run.
+bbb.screensharePublish.tunnelingErrorMessage.two = Try refreshing the client (click the refresh button on the browser). If after refresh you still see the words '[ Tunneling ]' in the lower right-hand corner of the client, try connecting from a different network location.
 bbb.screensharePublish.cancelButton.label = Cancel
 bbb.screensharePublish.startButton.label = Start
 bbb.screensharePublish.stopButton.label = Stop
@@ -346,12 +350,12 @@ bbb.toolbar.phone.toolTip.stop = Stop Sharing Your Microphone
 bbb.toolbar.phone.toolTip.mute = Stop listening the conference
 bbb.toolbar.phone.toolTip.unmute = Start listening the conference
 bbb.toolbar.phone.toolTip.nomic = No microphone detected
-bbb.toolbar.deskshare.toolTip.start = Share Your Screen
+bbb.toolbar.deskshare.toolTip.start = Open Screen Share Publish Window
 bbb.toolbar.deskshare.toolTip.stop = Stop Sharing Your Screen
 bbb.toolbar.video.toolTip.start = Share Your Webcam
 bbb.toolbar.video.toolTip.stop = Stop Sharing Your Webcam
 bbb.layout.addButton.toolTip = Add the custom layout to the list
-bbb.layout.broadcastButton.toolTip = Apply Current Layout to All Viewers
+bbb.layout.broadcastButton.toolTip = Apply current layout to all users except moderators
 bbb.layout.combo.toolTip = Change Your Layout
 bbb.layout.loadButton.toolTip = Load layouts from a file
 bbb.layout.saveButton.toolTip = Save layouts to a file
@@ -437,6 +441,7 @@ ltbcustom.bbb.highlighter.toolbar.text.accessibilityName = Switch whiteboard cur
 ltbcustom.bbb.highlighter.texttoolbar.textColorPicker = Text color
 ltbcustom.bbb.highlighter.texttoolbar.textSizeMenu = Font size
 bbb.caption.window.title = Closed Caption
+bbb.caption.quickLink.label = Closed Caption Window
 bbb.caption.window.titleBar = Closed Caption Window Title Bar
 bbb.caption.window.minimizeBtn.accessibilityName = Minimize the Closed Caption Window
 bbb.caption.window.maximizeRestoreBtn.accessibilityName = Maximize the Closed Caption Window
@@ -444,6 +449,8 @@ bbb.caption.transcript.noowner = None
 bbb.caption.transcript.youowner = You
 bbb.caption.transcript.pastewarning.title = Caption Paste Warning
 bbb.caption.transcript.pastewarning.text = Cannot paste text longer than {0} characters. You pasted {1} characters.
+bbb.caption.transcript.inputArea.toolTip = Caption Input Area
+bbb.caption.transcript.outputArea.toolTip = Caption Output Area
 bbb.caption.option.label = Options
 bbb.caption.option.language = Language:
 bbb.caption.option.language.tooltip = Select Caption Language
@@ -482,6 +489,7 @@ bbb.shortcuthelp.dropdown.general = Global shortcuts
 bbb.shortcuthelp.dropdown.presentation = Presentation shortcuts
 bbb.shortcuthelp.dropdown.chat = Chat shortcuts
 bbb.shortcuthelp.dropdown.users = Users shortcuts
+bbb.shortcuthelp.dropdown.caption = Closed Caption shortcuts
 bbb.shortcuthelp.headers.shortcut = Shortcut
 bbb.shortcuthelp.headers.function = Function
 
@@ -509,6 +517,8 @@ bbb.shortcutkey.focus.presentation = 51
 bbb.shortcutkey.focus.presentation.function = Move focus to the Presentation window
 bbb.shortcutkey.focus.chat = 52
 bbb.shortcutkey.focus.chat.function = Move focus to the Chat window
+bbb.shortcutkey.focus.caption = 53
+bbb.shortcutkey.focus.caption.function = Move focus to the Closed Caption window
 
 bbb.shortcutkey.share.desktop = 68
 bbb.shortcutkey.share.desktop.function = Open desktop sharing window
@@ -547,6 +557,14 @@ bbb.shortcutkey.users.focusUsers = 85
 bbb.shortcutkey.users.focusUsers.function = Focus to users list
 bbb.shortcutkey.users.muteAllButPres = 65
 bbb.shortcutkey.users.muteAllButPres.function = Mute everyone but the Presenter
+bbb.shortcutkey.users.breakoutRooms = 75
+bbb.shortcutkey.users.breakoutRooms.function = Breakout rooms window
+bbb.shortcutkey.users.focusBreakoutRooms = 82
+bbb.shortcutkey.users.focusBreakoutRooms.function = Focus to breakout rooms list
+bbb.shortcutkey.users.listenToBreakoutRoom = 76
+bbb.shortcutkey.users.listenToBreakoutRoom.function = Listen to selected breakout room
+bbb.shortcutkey.users.joinBreakoutRoom = 74
+bbb.shortcutkey.users.joinBreakoutRoom.function = Join selected breakout room
 
 bbb.shortcutkey.chat.focusTabs = 89
 bbb.shortcutkey.chat.focusTabs.function = Focus to chat tabs
@@ -576,6 +594,9 @@ bbb.shortcutkey.chat.chatbox.goread.function = Navigate to the most recent messa
 bbb.shortcutkey.chat.chatbox.debug = 71
 bbb.shortcutkey.chat.chatbox.debug.function = Temporary debug hotkey
 
+bbb.shortcutkey.caption.takeOwnership = 79
+bbb.shortcutkey.caption.takeOwnership.function = Take ownsership of selected language
+
 bbb.polling.startButton.tooltip = Start a poll
 bbb.polling.startButton.label = Start Poll
 bbb.polling.publishButton.label = Publish
@@ -615,14 +636,14 @@ bbb.shortcutkey.specialKeys.plus = Plus
 bbb.shortcutkey.specialKeys.minus = Minus
 
 bbb.toolbar.videodock.toolTip.closeAllVideos = Close all videos
-bbb.users.settings.lockAll=Lock All Users
-bbb.users.settings.lockAllExcept=Lock Users Except Presenter
-bbb.users.settings.lockSettings=Lock Viewers ...
-bbb.users.settings.breakoutRooms=Breakout Rooms ...
-bbb.users.settings.sendBreakoutRoomsInvitations=Send Breakout Rooms Invitations ...
-bbb.users.settings.unlockAll=Unlock All Viewers
-bbb.users.settings.roomIsLocked=Locked by default
-bbb.users.settings.roomIsMuted=Muted by default
+bbb.users.settings.lockAll = Lock All Users
+bbb.users.settings.lockAllExcept = Lock Users Except Presenter
+bbb.users.settings.lockSettings = Lock Viewers ...
+bbb.users.settings.breakoutRooms = Breakout Rooms ...
+bbb.users.settings.sendBreakoutRoomsInvitations = Send Breakout Rooms Invitations ...
+bbb.users.settings.unlockAll = Unlock All Viewers
+bbb.users.settings.roomIsLocked = Locked by default
+bbb.users.settings.roomIsMuted = Muted by default
 
 bbb.lockSettings.save = Apply
 bbb.lockSettings.save.tooltip = Apply lock settings
diff --git a/bigbluebutton-client/resources/prod/BigBlueButton.html b/bigbluebutton-client/resources/prod/BigBlueButton.html
index 401163c2241fbae06af098d6af5332e489797fcd..41dfc3f40d40e07ba61a95e26bf7031f1d92b31d 100755
--- a/bigbluebutton-client/resources/prod/BigBlueButton.html
+++ b/bigbluebutton-client/resources/prod/BigBlueButton.html
@@ -191,7 +191,7 @@
     <button id="enterFlash" type="button" class="visually-hidden" onclick="startFlashFocus();">Set focus to client</button>
     <div id="content">
       <div id="altFlash"  style="width:50%; margin-left: auto; margin-right: auto; ">
-        <h2>You need Flash installed and enabled in order to use the Flash client.</h2>
+        <h3>You need Adobe Flash installed and enabled in order to use this client.</h3>
         <br/>
         <div style="width:50%; margin-left: auto; margin-right: auto; ">
           <a href="http://www.adobe.com/go/getflashplayer">
diff --git a/bigbluebutton-client/resources/prod/lib/3rd-party.js b/bigbluebutton-client/resources/prod/lib/3rd-party.js
index b9ac5e738f5dadd21c82b86d7336b35a761ccaf5..b60b84af629106fc4523ade62497ea179833fce1 100755
--- a/bigbluebutton-client/resources/prod/lib/3rd-party.js
+++ b/bigbluebutton-client/resources/prod/lib/3rd-party.js
@@ -29,20 +29,24 @@ var registerListeners = function() {
 			console.log("AmISharingCamQueryResponse [isPublishing=" + bbbEvent2.isPublishing + ",camIndex=" + bbbEvent2.camIndex + "]");
 		});
 		BBB.amISharingWebcam();
+
 		BBB.amISharingWebcam(function(bbbEvent3) {
-			console.log("amISharingWebcam [isPublishing=" + bbbEvent3.isPublishing 
-						+ ",camIndex=" + bbbEvent3.camIndex 
-						+ ",camWidth=" + bbbEvent3.camWidth
-						+ ",camHeight=" + bbbEvent3.camHeight
-						+ ",camKeyFrameInterval=" + bbbEvent3.camKeyFrameInterval
-						+ ",camModeFps=" + bbbEvent3.camModeFps
-						+ ",camQualityBandwidth=" + bbbEvent3.camQualityBandwidth
-						+ ",camQualityPicture=" + bbbEvent3.camQualityPicture						
-						+ "]");
-			if (bbbEvent3.isPublishing) {	
-				CAM_PREVIEW.stopPreviewCamera(bbbEvent3.avatarURL);
-				CAM_PREVIEW.previewCamera(bbbEvent3.camIndex, bbbEvent3.camWidth, bbbEvent3.camHeight, bbbEvent3.camKeyFrameInterval,
-										  bbbEvent3.camModeFps, bbbEvent3.camQualityBandwidth, bbbEvent3.camQualityPicture, bbbEvent3.avatarURL);
+			var cameras = bbbEvent3.cameras;
+			for(var aCamera in cameras){
+				console.log("amISharingWebcam [isPublishing=" + aCamera.isPublishing
+					+ ",camIndex=" + aCamera.camIndex
+					+ ",camWidth=" + aCamera.camWidth
+					+ ",camHeight=" + aCamera.camHeight
+					+ ",camKeyFrameInterval=" + aCamera.camKeyFrameInterval
+					+ ",camModeFps=" + aCamera.camModeFps
+					+ ",camQualityBandwidth=" + aCamera.camQualityBandwidth
+					+ ",camQualityPicture=" + aCamera.camQualityPicture
+					+ "]");
+				if (aCamera.isPublishing) {
+					CAM_PREVIEW.stopPreviewCamera(aCamera.avatarURL);
+					CAM_PREVIEW.previewCamera(aCamera.camIndex, aCamera.camWidth, aCamera.camHeight, aCamera.camKeyFrameInterval,
+						aCamera.camModeFps, aCamera.camQualityBandwidth, aCamera.camQualityPicture, aCamera.avatarURL);
+				}
 			}
 		});
 	} else {
diff --git a/bigbluebutton-client/resources/prod/lib/bbb_blinker.js b/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
index 1eb2bc24632649fca521c878144bfd91a287b40e..223b12e20c1254d7e53f9672c77b78fb99f4c4d5 100755
--- a/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
+++ b/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
@@ -64,6 +64,28 @@ function determineGlobalModifier()
 	return modifier;
 }
 
+function determineGlobalAlternateModifier()
+{
+	var browser = determineBrowser()[0];
+	var modifier;
+	if (browser == "Firefox"){
+		modifier = "control+";
+	}
+	else if (browser == "Chrome"){
+		modifier = "control+";
+	}
+	else if (browser == "Microsoft Internet Explorer"){
+		modifier = "control+shift+";
+	}
+	//else if (browser == "Safari"){
+	//	modifier = "control+alt";
+	//}
+	else{
+		modifier = "control+shift";
+	}
+	return modifier;
+}
+
 function determineBrowser()
 {
 	// Browser name extraction code provided by http://www.javascripter.net/faq/browsern.htm
diff --git a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
old mode 100755
new mode 100644
index 99881b885f9814d3c45fa796015e886467dbbccc..b82548b8300b2352aa8ddf86183d9760569f1d40
--- a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
+++ b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
@@ -33,19 +33,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   
   <mx:Script>
     <![CDATA[
-		import com.asfusion.mate.events.Dispatcher;		
-		import flash.events.Event;		
+		import com.asfusion.mate.events.Dispatcher;
+		
+		import flash.events.Event;
+		
 		import mx.managers.HistoryManager;
 		import mx.managers.IDragManager;
 		import mx.managers.ToolTipManager;
-		import mx.utils.URLUtil;	
+		import mx.utils.URLUtil;
+		
 		import org.as3commons.logging.api.ILogger;
 		import org.as3commons.logging.api.getClassLogger;
 		import org.bigbluebutton.core.BBB;
+		import org.bigbluebutton.core.KeyboardUtil;
 		import org.bigbluebutton.main.api.ExternalApiCallbacks;
 		import org.bigbluebutton.main.events.ShortcutEvent;
 		import org.bigbluebutton.main.model.ShortcutOptions;
-		import org.bigbluebutton.util.QueryStringParameters;
 		import org.bigbluebutton.util.i18n.ResourceUtil;
 		
 		private static const LOGGER:ILogger = getClassLogger(BigBlueButtonMainContainer);      
@@ -163,9 +166,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.raiseHand') as String)] = ShortcutEvent.RAISE_HAND;
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.users.muteme') as String)] = ShortcutEvent.MUTE_ME_EVENT;
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.users.muteAllButPres') as String)] = ShortcutEvent.MUTE_ALL_BUT_PRES;
-        }
-        if (ShortcutOptions.videoDockActive){
-          keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.focus.video') as String)] = ShortcutEvent.FOCUS_VIDEO_WINDOW;
+		  keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.users.breakoutRooms') as String)] = ShortcutEvent.OPEN_BREAKOUT_ROOMS;
         }
         if (ShortcutOptions.presentationActive){
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.focus.presentation') as String)] = ShortcutEvent.FOCUS_PRESENTATION_WINDOW;
@@ -181,8 +182,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.polling.buttonClick') as String)] = ShortcutEvent.POLL_BUTTON_CLICK;
         }
         if (ShortcutOptions.webcamActive){
-          keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.webcam') as String)] = ShortcutEvent.SHARE_WEBCAM;
+			keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.focus.video') as String)] = ShortcutEvent.FOCUS_VIDEO_WINDOW;
+			keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.webcam') as String)] = ShortcutEvent.SHARE_WEBCAM;
         }
+		if (ShortcutOptions.closedCaptionActive){
+			keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.focus.caption') as String)] = ShortcutEvent.FOCUS_CAPTION_WINDOW;
+		}
         if (ShortcutOptions.deskshareActive){
           keyCombos[globalModifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.share.desktop') as String)] = ShortcutEvent.SHARE_DESKTOP;
         }
@@ -197,9 +202,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
       // Handle general-access hotkeys, regardless of what window the user is focused in
       private function handleKeyDown(e:KeyboardEvent) :void {
-        if (keyCombos == null) loadKeyCombos(globalModifier);
+	        if (keyCombos == null) loadKeyCombos(globalModifier);
         
-        var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") + (e.altKey   ? "alt+"     : "") + e.keyCode;
+        var keyPress:String = KeyboardUtil.buildPressedKeys(e);
         
         if (e.keyCode < 64 || e.keyCode > 90){
 			LOGGER.debug("Keypress debugging: KeyCode {0} is nonalphabetic (probably)", [e.keyCode]);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/AccessibleNumericStepper.as b/bigbluebutton-client/src/org/bigbluebutton/common/AccessibleNumericStepper.as
new file mode 100755
index 0000000000000000000000000000000000000000..da984795288565080de30f520e28ae00f2ce5ec8
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/common/AccessibleNumericStepper.as
@@ -0,0 +1,33 @@
+package org.bigbluebutton.common {
+	import mx.controls.NumericStepper;
+	import mx.controls.TextInput;
+	import mx.core.mx_internal;
+	
+	/* The purpose of this class is to propagate the toolTip value to the internal 
+	 * text field so screen readers can read out the description.
+	 */
+	
+	public class AccessibleNumericStepper extends NumericStepper {
+		public function AccessibleNumericStepper() {
+			super();
+		}
+		
+		override protected function createChildren():void {
+			var inputFieldCreated:Boolean = !mx_internal::inputField;
+			
+			super.createChildren();
+			
+			if (inputFieldCreated && toolTip && mx_internal::inputField is TextInput) {
+				(mx_internal::inputField as TextInput).toolTip = toolTip;
+			}
+		}
+		
+		override public function set toolTip(value:String):void {
+			super.toolTip = value;
+			
+			if (mx_internal::inputField && mx_internal::inputField is TextInput) {
+				(mx_internal::inputField as TextInput).toolTip = toolTip;
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/events/DragWindowEvent.as b/bigbluebutton-client/src/org/bigbluebutton/common/events/DragWindowEvent.as
deleted file mode 100755
index 32ddd0b0e93f89e456aeee0cc536afb900e232a8..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/common/events/DragWindowEvent.as
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
-* 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.common.events
-{
-	import flash.events.Event;
-	import flash.geom.Point;
-	import mx.core.UIComponent;
-	import flexlib.mdi.containers.*;
-	
-	public class DragWindowEvent extends Event
-	{
-		public static const DRAG_WINDOW_EVENT:String = "DRAG_WINDOW_EVENT";
-		public static const DRAG_START:String = "DRAG_START";
-		public static const DRAG_END:String = "DRAG_END";
-		public static const DRAG:String = "DRAG";
-		
-		public var mouseGlobal:Point;
-		public var window:MDIWindow;
-		public var mode:String;
-		
-		public function DragWindowEvent(mode:String, type:String = DRAG_WINDOW_EVENT)
-		{
-			super(type, true, false);
-			this.mode = mode;
-		}
-		
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/BBB.as b/bigbluebutton-client/src/org/bigbluebutton/core/BBB.as
index dd35060518e5aade2e2535ff536fe7c152d0fd13..632d50a9617936fc0523b27dc46f51b54e285eec 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/BBB.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/BBB.as
@@ -26,7 +26,6 @@ package org.bigbluebutton.core {
 	import org.bigbluebutton.core.managers.ConfigManager2;
 	import org.bigbluebutton.core.managers.ConnectionManager;
 	import org.bigbluebutton.core.managers.UserConfigManager;
-	import org.bigbluebutton.core.managers.UserManager;
 	import org.bigbluebutton.core.managers.VideoProfileManager;
 	import org.bigbluebutton.core.model.Session;
 	import org.bigbluebutton.core.model.VideoProfile;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/PublishingModel.as b/bigbluebutton-client/src/org/bigbluebutton/core/KeyboardUtil.as
old mode 100755
new mode 100644
similarity index 65%
rename from bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/PublishingModel.as
rename to bigbluebutton-client/src/org/bigbluebutton/core/KeyboardUtil.as
index 7c08aced36e1a9b07d43c5370ddf5b3acafc778a..97b1685c6a168a2dd6fd1fa4951c193368288d0e
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/model/PublishingModel.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/KeyboardUtil.as
@@ -1,13 +1,13 @@
 /**
  * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * Copyright (c) 2017 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.
@@ -16,18 +16,13 @@
  * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
  *
  */
-package org.bigbluebutton.modules.videoconf.model
-{
-  public class PublishingModel
-  {
-    public var streamName;
-    public var camIndex:int;
-    public var camWidth:int;
-    public var camHeight:int;
-    public var isPublishing:Boolean = false;
-    
-    public function PublishingModel()
-    {
+package org.bigbluebutton.core {
+
+    import flash.events.KeyboardEvent;
+
+    public final class KeyboardUtil {
+        public static function buildPressedKeys(e:KeyboardEvent):String {
+            return (e.ctrlKey ? "control+" : "") + (e.shiftKey ? "shift+" : "") + (e.altKey ? "alt+" : "") + e.keyCode;
+        }
     }
-  }
-}
\ No newline at end of file
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/PopUpUtil.as b/bigbluebutton-client/src/org/bigbluebutton/core/PopUpUtil.as
new file mode 100644
index 0000000000000000000000000000000000000000..d500bd937b60d2e196c7ac84e265230a9745d580
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/PopUpUtil.as
@@ -0,0 +1,92 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2017 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.core {
+    import flash.display.DisplayObject;
+    import flash.utils.Dictionary;
+    import flash.utils.getQualifiedClassName;
+
+    import mx.core.FlexGlobals;
+    import mx.core.IChildList;
+    import mx.core.IFlexDisplayObject;
+    import mx.core.IUIComponent;
+    import mx.managers.PopUpManager;
+    import mx.managers.SystemManager;
+
+    import org.as3commons.logging.api.ILogger;
+    import org.as3commons.logging.api.getClassLogger;
+
+    public final class PopUpUtil {
+
+        private static const LOGGER:ILogger = getClassLogger(PopUpUtil);
+
+        private static var popUpDict:Dictionary = new Dictionary(true);
+
+        public static function createNonModelPopUp(parent:DisplayObject, className:Class, center:Boolean = true):IFlexDisplayObject {
+            if (!checkPopUpExists(className)) {
+                return addPopUpToStage(parent, className, false, center);
+            }
+            return null;
+        }
+
+        public static function createModalPopUp(parent:DisplayObject, className:Class, center:Boolean = true):IFlexDisplayObject {
+            if (!checkPopUpExists(className)) {
+                return addPopUpToStage(parent, className, true, center);
+            }
+            return null;
+        }
+
+        public static function removePopUp(classOrInstance:*):void {
+            var fqcn:String = getQualifiedClassName(classOrInstance);
+            if (popUpDict[fqcn] != undefined) {
+                PopUpManager.removePopUp(popUpDict[fqcn])
+                delete popUpDict[fqcn];
+                LOGGER.debug("Removed PopUp with type [{0}]", [fqcn]);
+            }
+        }
+
+        private static function checkPopUpExists(className:Class):Boolean {
+            LOGGER.debug("Checking if [{0}] exists as a PopUp", [className]);
+            var systemManager:SystemManager = FlexGlobals.topLevelApplication.systemManager;
+
+            var childList:IChildList = systemManager.rawChildren;
+            for (var i:int = childList.numChildren - 1; i >= 0; i--) {
+                var childObject:IUIComponent = childList.getChildAt(i) as IUIComponent;
+                // PopUp already exists
+                if (childObject is className && childObject.isPopUp) {
+                    LOGGER.debug("PopUp with type [{0}] found", [className]);
+                    return true;
+                }
+            }
+            LOGGER.debug("No PopUp with type [{0}] not found", [className]);
+            return false;
+        }
+
+        private static function addPopUpToStage(parent:DisplayObject, className:Class, modal:Boolean = false, center:Boolean = true):IFlexDisplayObject {
+            var popUp:IFlexDisplayObject = PopUpManager.createPopUp(parent, className, modal);
+            if (center) {
+                PopUpManager.centerPopUp(popUp)
+            }
+            popUpDict[getQualifiedClassName(className)] = popUp;
+
+            LOGGER.debug("Created PopUp with type [{0}]", [className]);
+
+            return popUp;
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as b/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
index 8887e7ab68b50e8b39c1f8987e3e0f9aae4073b6..b3c8da63cc39f37052456a4a3c0429c995b2f546 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
@@ -71,18 +71,18 @@ package org.bigbluebutton.core
     return UserManager.getInstance().getConference().record;
   }
   
-    public static function amIPublishing():CameraSettingsVO {
-     return UserManager.getInstance().getConference().amIPublishing();
+    public static function amIPublishing():ArrayCollection {
+     return UserManager.getInstance().getConference().amIPublishing() as ArrayCollection;
     }
-    
-    public static function setIAmPublishing(publishing:Boolean):void {
-      UserManager.getInstance().getConference().setCamPublishing(publishing);
+
+    public static function addCameraSettings(camSettings:CameraSettingsVO):void {
+      UserManager.getInstance().getConference().addCameraSettings(camSettings);
     }
-    
-    public static function setCameraSettings(camSettings:CameraSettingsVO):void {
-      UserManager.getInstance().getConference().setCameraSettings(camSettings);
+
+    public static function removeCameraSettings(camIndex:int):void {
+      UserManager.getInstance().getConference().removeCameraSettings(camIndex);
     }
-    
+
     public static function hasWebcamStream(userID:String):Boolean {
       var u:BBBUser = getUser(userID);
       if (u != null) {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager.as b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager.as
deleted file mode 100755
index 67dc3be097870ef7b38dd19c2c53e71838681339..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager.as
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
-* 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.core.managers {
-	import org.bigbluebutton.core.vo.Config;
-	
-	public class ConfigManager {
-		public var configs:Config;
-		
-		public function setConfig(conf:Config):void {
-			this.configs = configs;
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager2.as b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager2.as
index eac7cd74501b2ac4984c3302067d63ef78d6ca60..67439b218548c4a3bbf97bdcef9ebe014310e6fb 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager2.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConfigManager2.as
@@ -21,7 +21,6 @@ package org.bigbluebutton.core.managers
 	import com.asfusion.mate.events.Dispatcher;
 	
 	import flash.events.Event;
-	import flash.events.EventDispatcher;
 	import flash.net.URLLoader;
 	import flash.net.URLRequest;
 	import flash.net.URLRequestMethod;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ReconnectionManager.as b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ReconnectionManager.as
old mode 100755
new mode 100644
index e96b3e54f8826b34111adff8d16bdfdd96294b06..054a49cc432c697c6b0b9ee9d479a70385a938ae
--- a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ReconnectionManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ReconnectionManager.as
@@ -18,25 +18,26 @@
 */
 package org.bigbluebutton.core.managers
 {
-  import com.asfusion.mate.events.Dispatcher; 
+  import com.asfusion.mate.events.Dispatcher;
+  
   import flash.display.DisplayObject;
   import flash.events.TimerEvent;
   import flash.utils.Dictionary;
-  import flash.utils.Timer; 
+  import flash.utils.Timer;
+  
   import mx.collections.ArrayCollection;
   import mx.core.FlexGlobals;
-  import mx.core.IFlexDisplayObject;
-  import mx.managers.PopUpManager;  
+  
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
+  import org.bigbluebutton.core.PopUpUtil;
   import org.bigbluebutton.core.UsersUtil;
-  import org.bigbluebutton.main.api.JSLog;
   import org.bigbluebutton.main.events.BBBEvent;
   import org.bigbluebutton.main.events.ClientStatusEvent;
   import org.bigbluebutton.main.events.LogoutEvent;
   import org.bigbluebutton.main.model.users.AutoReconnect;
   import org.bigbluebutton.main.views.ReconnectionPopup;
-  import org.bigbluebutton.util.i18n.ResourceUtil;
+  import org.bigbluebutton.util.i18n.ResourceUtil;
 
   public class ReconnectionManager
   {
@@ -52,7 +53,6 @@ package org.bigbluebutton.core.managers
     private var _reconnectTimer:Timer = new Timer(10000, 1);
     private var _reconnectTimeout:Timer = new Timer(15000, 1);
     private var _dispatcher:Dispatcher = new Dispatcher();
-    private var _popup:IFlexDisplayObject = null;
     private var _canceled:Boolean = false;
 
     public function ReconnectionManager() {
@@ -97,8 +97,7 @@ package org.bigbluebutton.core.managers
         _connections[type] = obj;
 
         if (!_reconnectTimer.running) {
-          _popup = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, ReconnectionPopup, true);
-          PopUpManager.centerPopUp(_popup);
+			PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, ReconnectionPopup, true);
 
           _reconnectTimer.reset();
           _reconnectTimer.start();
@@ -163,8 +162,8 @@ package org.bigbluebutton.core.managers
           msg, 'bbb.connection.reestablished'));
 
         _reconnectTimeout.reset();
-        removePopUp();
-      }
+		PopUpUtil.removePopUp(ReconnectionPopup);
+	  }
     }
 
     public function onCancelReconnection():void {
@@ -172,15 +171,8 @@ package org.bigbluebutton.core.managers
 
       for (var type:Object in _connections) delete _connections[type];
 
-      removePopUp();
-    }
-
-    private function removePopUp():void {
-      if (_popup != null) {
-        PopUpManager.removePopUp(_popup);
-        _popup = null;
-      }
-    }
+	  PopUpUtil.removePopUp(ReconnectionPopup);
+	}
 
     private function connectionReestablishedMessage():String {
       var msg:String = "";
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as
deleted file mode 100755
index d005b462285c4cb1d8b7f492b3fe9ee2e5eebdfb..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
-* 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.core.vo {
-	public class Config {
-		private var _version:String;
-		private var _localeVersion:String;
-		private var _portTestHost:String;
-		private var _portTestApplication:String;
-		private var _helpURL:String;
-		private var _application:String;
-		private var _host:String;
-		private var _numModules:int;
-		private var _languageEnabled:Boolean;
-		private var _shortcutKeysShowButton:Boolean;
-		private var _skinning:String = "";
-		private var _showDebug:Boolean = false;
-		
-		public function Config(builder:ConfigBuilder) {
-			_version = builder.version;
-			_localeVersion = builder.localeVersion;
-			_portTestHost = builder.portTestHost;
-			_portTestApplication = builder.portTestApplication;
-			_helpURL = builder.helpURL;
-			_application = builder.application;
-			_host = builder.host;
-			_numModules = builder.numModules;
-			_languageEnabled = builder.languageEnabled;
-			_shortcutKeysShowButton = builder.shortcutKeysShowButton;
-			_skinning = builder.skinning;
-			_showDebug = builder.showDebug;
-		}
-		
-		public function get version():String {
-			return _version;
-		}
-		
-		public function get localeVersion():String {
-			return _localeVersion;
-		}
-		
-		public function get portTestHost():String {
-			return _portTestHost;
-		}
-		
-		public function get portTestApplication():String {
-			return _portTestApplication;
-		}
-		
-		public function get helpURL():String {
-			return _helpURL;
-		}
-		
-		public function get application():String {
-			return _application;
-		}
-		
-		public function get host():String {
-			return _host;
-		}
-		
-		public function get numModules():int {
-			return _numModules;
-		}
-		
-		public function get languageEnabled():Boolean {
-			return _languageEnabled;
-		}
-		
-		public function get shortcutKeysShowButton():Boolean {
-			return _shortcutKeysShowButton;
-		}
-		
-		public function get skinning():String {
-			return _skinning;
-		}
-		
-		public function get showDebug():Boolean {
-			return _showDebug;
-		} 
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as
deleted file mode 100755
index 6e8f0ed2ed121efb0a3c7552090e7155ddb50d0a..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
-* 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.core.vo {
-	public class ConfigBuilder {
-		internal var version:String;
-		internal var localeVersion:String;
-		internal var portTestHost:String;
-		internal var portTestApplication:String;
-		internal var helpURL:String;
-		internal var application:String;
-		internal var host:String;
-		internal var numModules:int;
-		internal var languageEnabled:Boolean;
-		internal var shortcutKeysShowButton:Boolean;
-		internal var skinning:String = "";
-		internal var showDebug:Boolean = false;
-		
-		public function ConfigBuilder(version:String, localVersion:String){
-			this.version = version;
-			this.localeVersion = localVersion;
-		}
-		
-		public function withPortTestHost(portTestHost:String):ConfigBuilder {
-			this.portTestHost = portTestHost;
-			return this;
-		}
-		
-		public function withPortTestApplication(portTestApplication:String):ConfigBuilder {
-			this.portTestApplication = portTestApplication;
-			return this;
-		}
-
-		public function withHelpUrl(helpUrl:String):ConfigBuilder {
-			this.helpURL = helpUrl;
-			return this;
-		}
-		
-		public function withApplication(application:String):ConfigBuilder {
-			this.application = application;
-			return this;
-		}
-		
-		public function withHost(host:String):ConfigBuilder {
-			this.host = host;
-			return this;
-		}
-		
-		public function withNumModule(numModules:int):ConfigBuilder {
-			this.numModules = numModules;
-			return this;
-		}
-		
-		public function withLanguageEnabled(languageEnabled:Boolean):ConfigBuilder {
-			this.languageEnabled = languageEnabled;
-			return this;
-		}
-		
-		public function withShortcutKeysShowButton(shortcutKeysShowButton:Boolean):ConfigBuilder {
-			this.shortcutKeysShowButton = shortcutKeysShowButton;
-			return this;
-		}
-		
-		public function withSkinning(skinning:String):ConfigBuilder {
-			this.skinning = skinning;
-			return this;
-		}
-		
-		public function withShowDebug(showDebug:Boolean):ConfigBuilder {
-			this.showDebug = showDebug;
-			return this;
-		}
-		
-   		public function build():Config {
-			return new Config(this);
-		}		
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettings.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettings.as
deleted file mode 100644
index ebfe51fe3626cfd9f8a6fea8e3de9e33af33b87d..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettings.as
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * 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.core.vo
-{
-	public class LockSettings
-	{
-		private var allowModeratorLocking:Boolean;
-		private var disableCam:Boolean;
-		private var disableMic:Boolean;
-		private var disablePrivateChat:Boolean;
-		private var disablePublicChat:Boolean;
-
-		public function LockSettings(pAllowModeratorLocking:Boolean, pDisableCam:Boolean, pDisableMic:Boolean, pDisablePrivateChat:Boolean, pDisablePublicChat:Boolean)
-		{
-			this.allowModeratorLocking = pAllowModeratorLocking;
-			this.disableCam = pDisableCam;
-			this.disableMic = pDisableMic;
-			this.disablePrivateChat = pDisablePrivateChat;
-			this.disablePublicChat = pDisablePublicChat;
-		}
-		
-		public function toMap():Object {
-			var map:Object = {
-				allowModeratorLocking: this.allowModeratorLocking,
-				disableCam: this.disableCam,
-				disableMic: this.disableMic,
-				disablePrivateChat: this.disablePrivateChat,
-				disablePublicChat: this.disablePublicChat
-			};
-			
-			return map;
-		}
-		
-		public function getAllowModeratorLocking():Boolean {
-			return allowModeratorLocking;
-		}
-		
-		public function getDisableCam():Boolean {
-			return disableCam;
-		}
-		
-		public function getDisableMic():Boolean {
-			return disableMic;
-		}
-		
-		public function getDisablePrivateChat():Boolean {
-			return disablePrivateChat;
-		}
-		
-		public function getDisablePublicChat():Boolean {
-			return disablePublicChat;
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettingsVO.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettingsVO.as
index 308874e6070d3342a6d333bb375076ef83bc88ad..8f89969a2ff8651395c507f38f08ad7d3bec585f 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettingsVO.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/vo/LockSettingsVO.as
@@ -18,9 +18,6 @@
  */
 package org.bigbluebutton.core.vo
 {
-	import org.bigbluebutton.core.UsersUtil;
-	import org.bigbluebutton.main.model.users.BBBUser;
-
 	public class LockSettingsVO
 	{
 		private var lockOnJoinConfigurable:Boolean;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCallbacks.as b/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCallbacks.as
index f8f1e8d5c0d559ba90740adc74db03fd58ba432f..d3862708b54c7272d620599a9499c01c7243989d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCallbacks.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCallbacks.as
@@ -19,7 +19,8 @@
 package org.bigbluebutton.main.api
 {
   import com.asfusion.mate.events.Dispatcher;
-  
+  import mx.collections.ArrayCollection;
+
   import flash.external.ExternalInterface;
   import org.bigbluebutton.core.BBB;
   import org.as3commons.logging.api.ILogger;
@@ -48,7 +49,7 @@ package org.bigbluebutton.main.api
   import org.bigbluebutton.modules.videoconf.events.ClosePublishWindowEvent;
   import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
   import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
-  import org.bigbluebutton.util.SessionTokenUtil;
+  import org.bigbluebutton.util.SessionTokenUtil;
 
   public class ExternalApiCallbacks {
 	private static const LOGGER:ILogger = getClassLogger(ExternalApiCallbacks);
@@ -188,17 +189,26 @@ package org.bigbluebutton.main.api
     
     private function handleAmISharingCameraRequestSync():Object {
       var obj:Object = new Object();
-      var camSettings:CameraSettingsVO = UsersUtil.amIPublishing();
-      obj.isPublishing = camSettings.isPublishing;
-      obj.camIndex = camSettings.camIndex;
-      obj.camWidth = camSettings.videoProfile.width;
-      obj.camHeight = camSettings.videoProfile.height;
-      obj.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
-      obj.camModeFps = camSettings.videoProfile.modeFps;
-      obj.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
-      obj.camQualityPicture = camSettings.videoProfile.qualityPicture;
-      obj.avatarURL = UsersUtil.getAvatarURL();
-      
+      var camArray: ArrayCollection = new ArrayCollection();
+
+      var camSettingsArray:ArrayCollection = UsersUtil.amIPublishing();
+      for (var i:int = 0; i < camSettingsArray.length; i++) {
+        var camSettings:CameraSettingsVO = camSettingsArray.getItemAt(i) as CameraSettingsVO;
+        var cam:Object = new Object();
+
+        cam.isPublishing = camSettings.isPublishing;
+        cam.camIndex = camSettings.camIndex;
+        cam.camWidth = camSettings.videoProfile.width;
+        cam.camHeight = camSettings.videoProfile.height;
+        cam.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
+        cam.camModeFps = camSettings.videoProfile.modeFps;
+        cam.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
+        cam.camQualityPicture = camSettings.videoProfile.qualityPicture;
+        cam.avatarURL = UsersUtil.getAvatarURL();
+        camArray.addItem(cam);
+      }
+
+      obj.cameras = camArray;
       return obj;
     }
     
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCalls.as b/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCalls.as
index a6bd4d1d864c078f8e55e0fdf9699f2c1370b575..2387f26724b15248ea4f8470a637404c94cfd2ae 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCalls.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/api/ExternalApiCalls.as
@@ -19,6 +19,7 @@
 package org.bigbluebutton.main.api
 {
   import flash.external.ExternalInterface;
+  import mx.collections.ArrayCollection;
   
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
@@ -158,21 +159,28 @@ package org.bigbluebutton.main.api
     }
     
     public function handleAmISharingCamQueryEvent(event:AmISharingWebcamQueryEvent):void {
-      var camSettings:CameraSettingsVO = UsersUtil.amIPublishing();
-      
+      var camSettingsArray:ArrayCollection = UsersUtil.amIPublishing();
       var payload:Object = new Object();
+      var camArray: ArrayCollection = new ArrayCollection();
+      for (var i:int = 0; i < camSettingsArray.length; i++) {
+        var camSettings:CameraSettingsVO = camSettingsArray.getItemAt(i) as CameraSettingsVO;
+
+        var cam:Object = new Object();
+        cam.isPublishing = camSettings.isPublishing;
+        cam.camIndex = camSettings.camIndex;
+        cam.camWidth = camSettings.videoProfile.width;
+        cam.camHeight = camSettings.videoProfile.height;
+        cam.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
+        cam.camModeFps = camSettings.videoProfile.modeFps;
+        cam.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
+        cam.camQualityPicture = camSettings.videoProfile.qualityPicture;
+        cam.avatarURL = UsersUtil.getAvatarURL();
+        camArray.addItem(cam);
+      }
       payload.eventName = EventConstants.AM_I_SHARING_CAM_RESP;
-      payload.isPublishing = camSettings.isPublishing;
-      payload.camIndex = camSettings.camIndex;
-      payload.camWidth = camSettings.videoProfile.width;
-      payload.camHeight = camSettings.videoProfile.height;
-      payload.camKeyFrameInterval = camSettings.videoProfile.keyFrameInterval;
-      payload.camModeFps = camSettings.videoProfile.modeFps;
-      payload.camQualityBandwidth = camSettings.videoProfile.qualityBandwidth;
-      payload.camQualityPicture = camSettings.videoProfile.qualityPicture;
-      payload.avatarURL = UsersUtil.getAvatarURL();
-      
-      broadcastEvent(payload);        
+      payload.cameras = camArray;
+
+      broadcastEvent(payload);
     }
     
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/ShortcutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/ShortcutEvent.as
old mode 100755
new mode 100644
index 14183a7324b500d312a66c184405a8269f9a033f..4c9b713ef816197833841fa503723c11925e8643
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/ShortcutEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/ShortcutEvent.as
@@ -17,6 +17,7 @@
  *
  */
 package org.bigbluebutton.main.events {
+
 	import flash.events.Event;
 
 	public class ShortcutEvent extends Event {
@@ -34,12 +35,6 @@ package org.bigbluebutton.main.events {
 		public static const FOCUS_CHAT_INPUT:String = 'FOCUS_CHAT_INPUT';
 		public static const UNDO_WHITEBOARD:String = 'UNDO_WHITEBOARD';
 		public static const FOCUS_SLIDE:String = 'FOCUS_SLIDE_VIEW';
-		public static const ADVANCE_MESSAGE:String = 'ADVANCE_MESSAGE';
-		public static const GOBACK_MESSAGE:String = 'GOBACK_MESSAGE';
-		public static const REPEAT_MESSAGE:String = 'REPEAT_MESSAGE';
-		public static const GOLATEST_MESSAGE:String = 'GOLATEST_MESSAGE';
-		public static const GOFIRST_MESSAGE:String = 'GOFIRST_MESSAGE';
-		public static const GOREAD_MESSAGE:String = 'GOREAD_MESSAGE';
 		public static const OPEN_SHORTCUT_WIN:String = 'OPEN_SHORTCUT_WIN';
 		
 		public static const FOCUS_USERS_WINDOW:String = 'FOCUS_USERS_WINDOW';
@@ -52,6 +47,8 @@ package org.bigbluebutton.main.events {
 		public static const SHARE_WEBCAM:String = 'SHARE_WEBCAM';
 		public static const PAUSE_REMOTE_STREAM:String = 'PAUSE_REMOTE_STREAM';
 		
+		public static const FOCUS_CAPTION_WINDOW:String = 'FOCUS_CAPTION_WINDOW';
+		
 		public static const REMOTE_FOCUS_DESKTOP:String = 'REMOTE_FOCUS_DESKTOP';
 		public static const REMOTE_FOCUS_WEBCAM:String = 'REMOTE_FOCUS_WEBCAM';
 		// Remote focus microphone not necessary; audio options already hog focus
@@ -76,6 +73,7 @@ package org.bigbluebutton.main.events {
 		//public static const FOCUS_LOOP_END:String = 'FOCUS_LOOP_END';
 		public static const FOCUS_SHORTCUT_BUTTON:String = 'FOCUS_SHORTCUT_BUTTON';
 		public static const MUTE_ALL_BUT_PRES:String = 'MUTE_ALL_BUT_PRES';
+		public static const OPEN_BREAKOUT_ROOMS:String = 'OPEN_BREAKOUT_ROOMS';
 		public static const FOCUS_LOGOUT_BUTTON:String = 'FOCUS_LOGOUT_BUTTON';
 		
 		public static const CLOSE_POLL_STATS:String = 'CLOSE_POLL_STATS';
@@ -99,10 +97,7 @@ package org.bigbluebutton.main.events {
 		public static const REMOTE_CAST_VOTE:String = 'REMOTE_CAST_VOTE';
 		public static const SC_REFRESH_POLL:String = 'SC_REFRESH_POLL';
 		public static const SC_REPOST_POLL:String = 'SC_REPOST_POLL';
-		public static const SC_STOP_POLL:String = 'SC_STOP_POLL';
-		
-		// Temporary string to help fix chat message navigation for screen readers
-		public static const CHAT_DEBUG:String = 'CHAT_DEBUG';
+		public static const SC_STOP_POLL:String = 'SC_STOP_POLL';
 		
 		public var otherUserID:String;
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
old mode 100755
new mode 100644
index 2f4399ed84b5a80e3b667627cbca19b54673d70e..61c6cc041008a38b74a40bbd20d7479446947655
--- a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
@@ -29,7 +29,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		The FlexEvent.PREINITIALIZE event is a good place for creating and initializing managers.
 		-->
 		<ObjectBuilder generator="{ModulesProxy}" cache="global" />
-		<ObjectBuilder generator="{ConfigManager}" cache="global" />
 		<ObjectBuilder generator="{ReconnectionManager}" cache="global" />
 		<!--
 		Disabling temporarily the stream monitor
@@ -100,13 +99,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<![CDATA[
 		import mx.events.FlexEvent;
 		
-		import org.bigbluebutton.core.managers.ConfigManager;
 		import org.bigbluebutton.core.managers.ReconnectionManager;
 		import org.bigbluebutton.core.services.SkinningService;
 		import org.bigbluebutton.main.events.BBBEvent;
 		import org.bigbluebutton.main.events.ConfigLoadedEvent;
 		import org.bigbluebutton.main.events.LoadConfigCommand;
-		import org.bigbluebutton.main.events.ConfigEvent;
 		import org.bigbluebutton.main.events.LogoutEvent;
 		import org.bigbluebutton.main.events.ModuleLoadEvent;
 		import org.bigbluebutton.main.events.PortTestEvent;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as
deleted file mode 100755
index b8ac7b46593de0a365e11a9e7e674b3fa4fcf997..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
-* 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
-{
-	import com.asfusion.mate.events.Dispatcher;
-	
-	import flash.events.Event;
-	import flash.net.URLLoader;
-	import flash.net.URLRequest;
-	import flash.net.URLRequestMethod;
-	import flash.net.URLVariables;
-	import flash.utils.Dictionary;
-	
-	import mx.core.FlexGlobals;
-	import mx.utils.URLUtil;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	import org.bigbluebutton.main.model.modules.ModuleDescriptor;
-	import org.bigbluebutton.util.QueryStringParameters;
-
-	public class ConfigParameters {
-		private static const LOGGER:ILogger = getClassLogger(ConfigParameters);
-		
-		public static const CONFIG_XML:String = "bigbluebutton/api/configXML";
-		
-		private var _urlLoader:URLLoader;
-		
-		private var rawXML:XML;
-		
-		public var version:String;
-		public var localeVersion:String;
-		public var suppressLocaleWarning:Boolean = false;
-		public var portTestHost:String;
-		public var portTestApplication:String;
-		public var portTestTimeout:Number;
-		public var helpURL:String;
-		public var application:String;
-		public var host:String;
-		public var numModules:int;
-		public var languageEnabled:Boolean;
-		public var shortcutKeysShowButton:Boolean;
-		public var skinning:String = "";
-		public var showDebug:Boolean = false;
-		
-		private var loadedListener:Function;
-		private var dispatcher:Dispatcher = new Dispatcher();
-		
-		private var _modules:Dictionary;
-		
-		public function ConfigParameters(loadedListener:Function, file:String = CONFIG_XML) {			
-			this.numModules = 0;
-			this.loadedListener = loadedListener;
-		}
-		
-		public function loadConfig():void {
-			
-			var p:QueryStringParameters = new QueryStringParameters();
-			p.collectParameters();
-			var sessionToken:String = p.getParameter("sessionToken");
-			
-			var reqVars:URLVariables = new URLVariables();
-			reqVars.sessionToken = sessionToken;
-			
-			_urlLoader = new URLLoader();
-			_urlLoader.addEventListener(Event.COMPLETE, handleComplete);
-			var date:Date = new Date();
-			var localeReqURL:String = buildRequestURL() + "?a=" + date.time;
-			
-			LOGGER.debug(localeReqURL + " session=[" + sessionToken + "]"); 
-			
-			var request:URLRequest = new URLRequest(localeReqURL);
-			request.method = URLRequestMethod.GET;
-			request.data = reqVars;
-			
-			_urlLoader.load(request);				
-		}
-		
-    private function buildRequestURL():String {
-      var swfURL:String = FlexGlobals.topLevelApplication.url;
-      var protocol:String = URLUtil.getProtocol(swfURL);
-      var serverName:String = URLUtil.getServerNameWithPort(swfURL);        
-      return protocol + "://" + serverName + "/" + CONFIG_XML;
-    }
-    
-		private function handleComplete(e:Event):void{
-			LOGGER.debug("handleComplete [{0}]", [new XML(e.target.data)]);
-			parse(new XML(e.target.data));	
-			buildModuleDescriptors();
-			this.loadedListener();
-		}
-		
-		private function parse(xml:XML):void{
-			rawXML = xml;
-			
-			portTestHost = xml.porttest.@host;
-			portTestApplication = xml.porttest.@application;
-			
-			portTestTimeout = parseInt(xml.porttest.@timeout);
-			if(isNaN(portTestTimeout) || portTestTimeout < 500) portTestTimeout = 10000;
-			
-			application = xml.application.@uri;
-			host = xml.application.@host;
-			helpURL = xml.help.@url;
-			version = xml.version;
-			localeVersion = xml.localeversion;	
-			if (xml.localeversion.@suppressWarning == "true") suppressLocaleWarning = true;
-			if (xml.language.@userSelectionEnabled == "true") languageEnabled = true;
-			else languageEnabled = false;
-			
-			if (xml.shortcutKeys.@showButton == "true") shortcutKeysShowButton = true;
-			else shortcutKeysShowButton = false;
-			
-			if (xml.skinning.@enabled == "true") skinning = xml.skinning.@url;
-
-			if (xml.debug.@showDebugWindow == "true") showDebug = true;
-		}
-		
-		public function getModulesXML():XMLList{
-			return rawXML.modules.module;
-		}
-		
-		private function buildModuleDescriptors():Dictionary{
-			_modules = new Dictionary();
-			var list:XMLList = getModulesXML();
-			var item:XML;
-			for each(item in list){
-				var mod:ModuleDescriptor = new ModuleDescriptor(item);
-				_modules[item.@name] = mod;
-				numModules++;
-			}
-			return _modules;
-		}
-		
-		public function getModules():Dictionary{
-			return _modules;
-		}
-		
-		public function getModule(name:String):ModuleDescriptor {
-			for (var key:Object in _modules) {				
-				var m:ModuleDescriptor = _modules[key] as ModuleDescriptor;
-				if (m.getName() == name) {
-					return m;
-				}
-			}		
-			return null;	
-		}
-		
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTestProxy.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTestProxy.as
old mode 100755
new mode 100644
index fd1bc13c9783117ce909a0e47e7e6c26ce1bd7ab..99fec41b9396d2af2c7fad824ce059a95f50bb02
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTestProxy.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/PortTestProxy.as
@@ -1,58 +1,55 @@
 /**
-* 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/>.
-*
-*/
+ * 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 {
-	import flash.events.NetStatusEvent;
-	import flash.net.NetConnection;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	import org.bigbluebutton.main.model.modules.ModulesDispatcher;
+    import org.as3commons.logging.api.ILogger;
+    import org.as3commons.logging.api.getClassLogger;
+    import org.bigbluebutton.main.model.modules.ModulesDispatcher;
 
-	public class PortTestProxy {
-		private static const LOGGER:ILogger = getClassLogger(PortTestProxy);      
-    
-		private var tunnel:Boolean;
-		private var port:String;
-		private var hostname:String;
-		private var application:String;
-		private var modulesDispatcher:ModulesDispatcher;
-		private var portTest:PortTest;
-    
-		public function PortTestProxy(modulesDispatcher: ModulesDispatcher) {
-			this.modulesDispatcher = modulesDispatcher;
-		}
-		
-		public function connect(tunnel:Boolean, hostname:String = "", port:String = "", application:String = "", testTimeout:Number = 10000):void {
-      this.tunnel = tunnel;
-			portTest = new PortTest(tunnel, hostname, port, application, testTimeout);
-			portTest.addConnectionSuccessListener(connectionListener);
+    public class PortTestProxy {
 
-			portTest.connect();
-		}
-		
-		private function connectionListener(status:String, tunnel:Boolean, hostname:String, port:String, application:String):void {
-      
-			if (status == "SUCCESS") {				
-				modulesDispatcher.sendPortTestSuccessEvent(port, hostname, tunnel, application);			
-			} else {
-				modulesDispatcher.sendPortTestFailedEvent(port, hostname, tunnel, application);
-			}				 		
-		}
-	}
+		private static const LOGGER:ILogger = getClassLogger(PortTestProxy);
+
+        private var tunnel:Boolean;
+        private var port:String;
+        private var hostname:String;
+        private var application:String;
+        private var modulesDispatcher:ModulesDispatcher;
+        private var portTest:PortTest;
+
+        public function PortTestProxy(modulesDispatcher:ModulesDispatcher) {
+            this.modulesDispatcher = modulesDispatcher;
+        }
+
+        public function connect(tunnel:Boolean, hostname:String = "", port:String = "", application:String = "", testTimeout:Number = 10000):void {
+            this.tunnel = tunnel;
+            portTest = new PortTest(tunnel, hostname, port, application, testTimeout);
+            portTest.addConnectionSuccessListener(connectionListener);
+
+            portTest.connect();
+        }
+
+        private function connectionListener(status:String, tunnel:Boolean, hostname:String, port:String, application:String):void {
+            if (status == "SUCCESS") {
+                modulesDispatcher.sendPortTestSuccessEvent(port, hostname, tunnel, application);
+            } else {
+                modulesDispatcher.sendPortTestFailedEvent(port, hostname, tunnel, application);
+            }
+        }
+    }
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
old mode 100755
new mode 100644
index 44f6375235388a7bb513f22c051c8cc562ed10a3..136e0ab398cb6f45e7e4cb302ae3523a0ac87c42
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ShortcutOptions.as
@@ -1,14 +1,15 @@
 package org.bigbluebutton.main.model
 {
 	import org.bigbluebutton.core.BBB;
+
 	public class ShortcutOptions
 	{
 		private static var users:Boolean = true;
-		private static var videoDock:Boolean = true;
 		private static var presentation:Boolean = true;
 		private static var chat:Boolean = true;
 		private static var polling:Boolean = true;
 		private static var webcam:Boolean = true;
+		private static var closedCaption:Boolean = true;
 		private static var deskshare:Boolean = true;
 		private static var audio:Boolean = true;
 		private static var generalResource:Array;
@@ -21,11 +22,6 @@ package org.bigbluebutton.main.model
 				users = false;
 			}
 			
-			vxml = BBB.getConfigForModule("VideodockModule");
-			if (vxml == null) {
-				videoDock = false;
-			}
-			
 			vxml = BBB.getConfigForModule("PresentModule");
 			if (vxml == null) {
 				presentation = false;
@@ -56,16 +52,21 @@ package org.bigbluebutton.main.model
 				audio = false;
 			}
 			
+			vxml = BBB.getConfigForModule("CaptionModule");
+			if (vxml == null) {
+				closedCaption = false;
+			}
+			
 			generalResource = new Array();
 			generateGlobalKeys();
 		}
 		
 		public static function get usersActive():Boolean{return users;}
-		public static function get videoDockActive():Boolean{return videoDock;}
 		public static function get presentationActive():Boolean{return presentation;}
 		public static function get chatActive():Boolean{return chat;}
 		public static function get pollingActive():Boolean{return polling;}
-		public static function get webcamActive():Boolean{return webcam;}		
+		public static function get webcamActive():Boolean{return webcam;}	
+		public static function get closedCaptionActive():Boolean{return closedCaption;}
 		public static function get deskshareActive():Boolean{return deskshare;}
 		public static function get audioActive():Boolean{return audio;}
 		public static function get genResource():Array{return generalResource;}
@@ -78,9 +79,10 @@ package org.bigbluebutton.main.model
 			generalResource.push('bbb.shortcutkey.flash.exit');
 			
 			if (users){generalResource.push('bbb.shortcutkey.focus.users');}
-			if (videoDock){generalResource.push('bbb.shortcutkey.focus.video');}
+			if (webcam){generalResource.push('bbb.shortcutkey.focus.video');}
 			if (presentation){generalResource.push('bbb.shortcutkey.focus.presentation');}
 			if (chat){generalResource.push('bbb.shortcutkey.focus.chat');}
+			if (closedCaption){generalResource.push('bbb.shortcutkey.focus.caption');}
 			
 			if (deskshare){generalResource.push('bbb.shortcutkey.share.desktop');}
 			if (webcam){generalResource.push('bbb.shortcutkey.share.webcam');}
@@ -88,13 +90,14 @@ package org.bigbluebutton.main.model
 			generalResource.push('bbb.shortcutkey.logout');
 			
 			if (users){generalResource.push('bbb.shortcutkey.raiseHand');}
+			if (users){generalResource.push('bbb.shortcutkey.users.breakoutRooms');}
 			if (audio){generalResource.push('bbb.shortcutkey.users.muteme');}
 			if (audio){generalResource.push('bbb.shortcutkey.users.muteAllButPres');}
 			if (chat){generalResource.push('bbb.shortcutkey.chat.chatinput');}
 		}
 		
 		public static function debugString():String{
-			return "USERS: " + users + " VIDEODOCK: " + videoDock + " PRESENTATION: " + presentation + " CHAT: " + chat + " POLLING: " + polling + " WEBCAM: " + webcam + " DESKSHARE: " + deskshare + " AUDIO: " + audio;
+			return "USERS: " + users + " PRESENTATION: " + presentation + " CHAT: " + chat + " CLOSED CAPTION: " + closedCaption + " POLLING: " + polling + " WEBCAM: " + webcam + " DESKSHARE: " + deskshare + " AUDIO: " + audio;
 		}
 	}
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
old mode 100755
new mode 100644
index 4eeeb8a8fd0900bd66da3b4476b5f07137000104..a6192f097965a411fb9e5a2b00ee4109ec4d156a
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
@@ -18,21 +18,14 @@
  */
 package org.bigbluebutton.main.model.modules
 {
-  import com.asfusion.mate.events.Dispatcher;  
-  import flash.events.TimerEvent; 
+  import com.asfusion.mate.events.Dispatcher;
+  
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
-  import org.as3commons.logging.util.jsonXify;
-  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.ConfigLoadedEvent;
   import org.bigbluebutton.main.events.ModuleLoadEvent;
   import org.bigbluebutton.main.events.PortTestEvent;
   import org.bigbluebutton.main.events.UserServicesEvent;
-  import org.bigbluebutton.main.model.ConfigParameters;
   
   public class ModulesDispatcher
   {
@@ -41,12 +34,10 @@ package org.bigbluebutton.main.model.modules
     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{
@@ -74,49 +65,20 @@ package org.bigbluebutton.main.model.modules
       dispatcher.dispatchEvent(e);
     }
     
-    public function sendPortTestEvent():void {     
-      //getMeetingAndUserInfo();
+    public function sendPortTestEvent():void{
 	  doPortTesting();
     }
     
-    private function getMeetingAndUserInfo():void {
-      enterApiService = new EnterApiService();
-      enterApiService.addResultListener(resultListener);
-      enterApiService.load(enterApiUrl);
-    }
-      
-    private function resultListener(success:Boolean, result:Object):void {
-      if (success) {
-        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 {
+    private function doPortTesting():void{
       var e:PortTestEvent = new PortTestEvent(PortTestEvent.TEST_RTMP);
       dispatcher.dispatchEvent(e);       
     }
     
-    private function timerHandler(e:TimerEvent):void{
-      var evt:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_UPDATE);
-      dispatcher.dispatchEvent(evt);
-    }
-    
     public function sendTunnelingFailedEvent(server: String, app: String):void{     
       dispatcher.dispatchEvent(new PortTestEvent(PortTestEvent.TUNNELING_FAILED));
     }
     
     public function sendPortTestSuccessEvent(port:String, host:String, tunnel:Boolean, app:String):void{
-      
       var portEvent:PortTestEvent = new PortTestEvent(PortTestEvent.PORT_TEST_SUCCESS);
       portEvent.port = port;
       portEvent.hostname = host;
@@ -140,26 +102,6 @@ package org.bigbluebutton.main.model.modules
       var event:ModuleLoadEvent = new ModuleLoadEvent(ModuleLoadEvent.MODULE_LOADING_STARTED);
       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)
-        .build()
-      event.config = config;
-      dispatcher.dispatchEvent(event);
-    }
+
   }
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesProxy.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesProxy.as
old mode 100755
new mode 100644
index 58fcc15ea5ae70f6c01232f76191f04e858f9218..e1864d5a198f48fe641064e9bf4dcbb98ba393f1
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesProxy.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesProxy.as
@@ -20,9 +20,9 @@ package org.bigbluebutton.main.model.modules
 {
 	import org.as3commons.logging.api.ILogger;
 	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.core.UsersUtil;
 	import org.bigbluebutton.main.model.ConferenceParameters;
 	import org.bigbluebutton.main.model.PortTestProxy;
-    import org.bigbluebutton.core.UsersUtil;
 	
 	public class ModulesProxy {
 		private static const LOGGER:ILogger = getClassLogger(ModulesProxy);      
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
index e81a281a23aefe77fd8459b8bb42c1dfd1a19a57..6b0706299dd6dc96ef75f317e0b9dad430d8648d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
@@ -64,7 +64,7 @@ package org.bigbluebutton.main.model.users {
 		
 		private var lockSettings:LockSettingsVO;
 		
-		private var _myCamSettings:CameraSettingsVO = new CameraSettingsVO();
+		private var _myCamSettings:ArrayCollection = null;
 		
 		[Bindable]
 		private var me:BBBUser = null;
@@ -90,6 +90,7 @@ package org.bigbluebutton.main.model.users {
 			users.sort = sort;
 			users.refresh();
 			breakoutRooms = new ArrayCollection();
+			_myCamSettings = new ArrayCollection();
 		}
 		
 		// Custom sort function for the users ArrayCollection. Need to put dial-in users at the very bottom.
@@ -152,19 +153,28 @@ package org.bigbluebutton.main.model.users {
 			users.addItem(newuser);
 			users.refresh();
 		}
-		
-		public function setCamPublishing(publishing:Boolean):void {
-			_myCamSettings.isPublishing = publishing;
+
+		public function addCameraSettings(camSettings: CameraSettingsVO): void {
+			if(!_myCamSettings.contains(camSettings)) {
+				_myCamSettings.addItem(camSettings);
+			}
 		}
-		
-		public function setCameraSettings(camSettings:CameraSettingsVO):void {
-			_myCamSettings = camSettings;
+
+		public function removeCameraSettings(camIndex:int): void {
+			if (camIndex != -1) {
+				for(var i:int = 0; i < _myCamSettings.length; i++) {
+					if (_myCamSettings.getItemAt(i) != null && _myCamSettings.getItemAt(i).camIndex == camIndex) {
+						_myCamSettings.removeItemAt(i);
+						return;
+					}
+				}
+			}
 		}
-		
-		public function amIPublishing():CameraSettingsVO {
+
+		public function amIPublishing():ArrayCollection {
 			return _myCamSettings;
 		}
-		
+
 		public function setDefaultLayout(defaultLayout:String):void {
 			this.defaultLayout = defaultLayout;
 		}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Status.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Status.as
old mode 100755
new mode 100644
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/BroadcastStartedEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/BroadcastStartedEvent.as
index b3a40e2dfe31007888800e77f1f44cce4de3896b..14b06222eaca240a02214755ac583821a7ccf0ce 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/BroadcastStartedEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/BroadcastStartedEvent.as
@@ -29,7 +29,7 @@
 		public var stream:String;
 		public var userid:String;
 		public var isPresenter:Boolean;
-    public var camSettings:CameraSettingsVO;
+		public var camSettings:CameraSettingsVO;
     
 		public function BroadcastStartedEvent(type:String = BROADCAST_STARTED_EVENT) {
 			super(type, true, false);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/AudioSelectionWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/AudioSelectionWindow.mxml
index 0e11ba544fb430437e2123da811b9110fad316ce..91274f99c4a610049ff3d15179ba91adf245a985 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/AudioSelectionWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/AudioSelectionWindow.mxml
@@ -34,10 +34,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import mx.managers.PopUpManager;
-			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.api.JSAPI;
@@ -99,7 +98,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					dispatcher.dispatchEvent(command);
 				}
 				
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function onListenClick():void {
@@ -109,7 +108,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				command.mic = false;
 				dispatcher.dispatchEvent(command);
 				
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function onCancelClicked():void {
@@ -117,7 +116,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				var dispatcher:Dispatcher = new Dispatcher();
 				dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.CLOSED_AUDIO_SELECTION));
 				
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleBecomePresenter(e:MadePresenterEvent):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/ConfigEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/views/BBBDataGrid.as
old mode 100755
new mode 100644
similarity index 58%
rename from bigbluebutton-client/src/org/bigbluebutton/main/events/ConfigEvent.as
rename to bigbluebutton-client/src/org/bigbluebutton/main/views/BBBDataGrid.as
index ee9927aee490e30beb519c5d2e3c4a30199a113f..2ef7a35507f8c8add6a3ba8fdb28968620d0e12e
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/ConfigEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/BBBDataGrid.as
@@ -1,13 +1,13 @@
 /**
  * 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.
@@ -16,21 +16,19 @@
  * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
  *
  */
-package org.bigbluebutton.main.events
-{
-	import flash.events.Event;
-	
-	import org.bigbluebutton.core.vo.Config;
+package org.bigbluebutton.main.views {
+    import mx.controls.DataGrid;
 
-	public class ConfigEvent extends Event
-	{
-		public static const CONFIG_EVENT:String = "config event";
-		
-		public var config:Config;
-		
-		public function ConfigEvent(type:String)
-		{
-			super(type, true, false);
-		}
-	}
-}
\ No newline at end of file
+    public class BBBDataGrid extends DataGrid {
+        // This function needs to be overridden to avoid finding any
+        // first comumn value that starts the typed letter.
+        // It will make hotkeys work correctly gtriki (12 feb, 2017)
+        override protected function findKey(eventCode:int):Boolean {
+            if (eventCode >= 33 && eventCode <= 126) {
+                return false;
+            } else {
+				return super.findKey(eventCode);
+            }
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
old mode 100755
new mode 100644
index 790fec496ec004a329d68b31dfc35a4ef78381d7..2100cac414b28b30dc29732896783313d3be9c4b
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
@@ -21,7 +21,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" 
                 xmlns:view="org.bigbluebutton.main.views.*"
 				xmlns:common="org.bigbluebutton.common.*"
-                layout="absolute" 
+                layout="absolute"
                 verticalScrollPolicy="off" horizontalScrollPolicy="off"
                 width="630" height="450" creationComplete="onCreationComplete()" styleName="cameraDisplaySettingsWindowStyle" 
                 showCloseButton="false" close="onCancelClicked()" keyDown="handleKeyDown(event)">
@@ -34,11 +34,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		import mx.collections.ArrayCollection;
 		import mx.collections.ArrayList;
 		import mx.events.CloseEvent;
-		import mx.managers.PopUpManager;
 		
 		import org.bigbluebutton.common.Images;
 		import org.bigbluebutton.common.Media;
 		import org.bigbluebutton.core.BBB;
+		import org.bigbluebutton.core.PopUpUtil;
 		import org.bigbluebutton.core.model.VideoProfile;
 		import org.bigbluebutton.main.events.BBBEvent;
 		import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -70,10 +70,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	    {
 	       return;
 	    }
-      
+
 		private function onCreationComplete():void {
             tabIndex = 51;
-            
+		}
+
+		public function updateCameraList() : void {
 			if(defaultCamera != null) {
 				var indexDefault:int = 0;
 				for (var i:int = 0; i < Media.availableCameras; i++){
@@ -97,14 +99,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			for each (var value:VideoProfile in BBB.videoProfiles) {
 				var item:Object = {index:idx, label:value.name, profile:value};
 				_videoProfiles.addItem(item);
-
+				
 				if (value.id == defaultProfile.id) {
 					cmbVideoProfile.selectedIndex = idx;
 				}
-
+				
 				idx++;
 			}
-
+			
 			if (_videoProfiles.length > 1) {
 				showResControls(true);
 			}
@@ -197,11 +199,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		private function onCancelClicked():void {
 			close("cancel");
 		}
-		
-		private function showCameraSettings():void {
-			Security.showSettings(SecurityPanel.CAMERA);
-		}
-		
+
 		private function close(payload:String):void {
 			disableCamera();
 			
@@ -211,7 +209,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			var event:BBBEvent = new BBBEvent(BBBEvent.CAM_SETTINGS_CLOSED);
 			event.payload['clicked'] = payload;
 			dispatchEvent(event);
-			PopUpManager.removePopUp(this);
+			PopUpUtil.removePopUp(this);
 		}
       
     ]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeMicPermissionImage.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeMicPermissionImage.mxml
old mode 100755
new mode 100644
index 51e6d1d7ce1b20aa559373ec6f720404d7f20c1a..2c15ebb80766ffb9e71dc876cb6de7a40c9b627a
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeMicPermissionImage.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeMicPermissionImage.mxml
@@ -39,22 +39,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	
 	<mx:Script>
 		<![CDATA[
-			import mx.managers.PopUpManager;
-			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.modules.phone.events.WebRTCEchoTestEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCMediaEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 			
 			private function handleWebRTCMediaSuccessEvent(e:WebRTCMediaEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleWebRTCMediaFailEvent(e:WebRTCMediaEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleWebRTCEchoTestFailedEvent(e:WebRTCEchoTestEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 		
 		]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeWebcamPermissionImage.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeWebcamPermissionImage.mxml
old mode 100755
new mode 100644
index c37f21dc7a26c17f83cc7149ed20abac810373e9..f06d72a60afff81c00d5680a3bc956f3e8baa24e
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeWebcamPermissionImage.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/ChromeWebcamPermissionImage.mxml
@@ -38,18 +38,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	
 	<mx:Script>
 		<![CDATA[
-			import mx.managers.PopUpManager;
-			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.main.events.BBBEvent;
 			import org.bigbluebutton.main.model.users.events.BroadcastStartedEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 			
 			private function handleBroadcastStartedEvent(e:BroadcastStartedEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleCameraSettingsClosedEvent(e:BBBEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 		]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/ClientStatusWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/ClientStatusWindow.mxml
old mode 100755
new mode 100644
index 39e7bbb725fdd08efa4664b924a1dd7c3bbb11b3..e2cce80b7d4dbde09e648b5dc4f07d781f33b346
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/ClientStatusWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/ClientStatusWindow.mxml
@@ -28,8 +28,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				creationComplete="onCreationComplete();">
 	<mx:Script>
 		<![CDATA[
-			import mx.managers.PopUpManager;
-			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 			
 			private function onCreationComplete():void {
@@ -41,7 +40,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			private function handleCloseButtonClick():void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/ConnectionLostWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/ConnectionLostWindow.mxml
old mode 100755
new mode 100644
index 62eea23e5c4e054cadd7482156b3d88251397d71..d272e2e97794bb6934cede8257ddb908d9f500da
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/ConnectionLostWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/ConnectionLostWindow.mxml
@@ -26,14 +26,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import flash.net.navigateToURL;
 			
-			import mx.managers.PopUpManager;
-			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
 			
 			private function connectionReestablished(e:UsersConnectionEvent):void{
 				var url:URLRequest = new URLRequest(ExternalInterface.call("window.location.href.toString"));
 				navigateToURL(url, '_self');
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 		]]>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
old mode 100755
new mode 100644
index a528a89b454529ad1de35dff1976e9a21efbf54d..47f88d9576a3c6cd02ec115712f50bfdb7e2f398
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
@@ -39,24 +39,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   
 	<mx:Script>
 		<![CDATA[
-			import mx.managers.PopUpManager;
-			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.modules.phone.events.WebRTCEchoTestEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCMediaEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 
 			private function handleWebRTCMediaSuccessEvent(e:WebRTCMediaEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleWebRTCMediaFailEvent(e:WebRTCMediaEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 			
 			private function handleWebRTCEchoTestFailedEvent(e:WebRTCEchoTestEvent):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
-		
 		]]>
 	</mx:Script>
   
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/FlashMicSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/FlashMicSettings.mxml
old mode 100755
new mode 100644
index ac461d35064fc6202b3ab69a15578619e2057eab..5d3c7c2d8ceef542aa41317e595b417c528800e1
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/FlashMicSettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/FlashMicSettings.mxml
@@ -39,17 +39,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import com.asfusion.mate.events.Dispatcher;
 			
 			import flash.ui.Keyboard;
-			import org.bigbluebutton.core.UsersUtil;
+			
 			import mx.controls.sliderClasses.Slider;
 			import mx.events.CloseEvent;
 			import mx.events.SliderEvent;
-			import mx.managers.PopUpManager;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.common.Images;
 			import org.bigbluebutton.common.Media;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.PopUpUtil;
+			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent;
 			import org.bigbluebutton.modules.phone.events.FlashEchoTestFailedEvent;
 			import org.bigbluebutton.modules.phone.events.FlashEchoTestHasAudioEvent;
@@ -241,7 +242,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       }
       
       private function handleFlashJoinedVoiceConferenceEvent(event:FlashJoinedVoiceConferenceEvent):void {
-        PopUpManager.removePopUp(this);
+        PopUpUtil.removePopUp(this);
       }
       
       private function echoTestButtonClickHandler():void {
@@ -263,7 +264,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         stopEchoTest();
         var dispatcher:Dispatcher = new Dispatcher();
         dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.CLOSED_AUDIO_SELECTION));
-        PopUpManager.removePopUp(this);
+        PopUpUtil.removePopUp(this);
       }
       
       private function stopEchoTest():void {
@@ -307,7 +308,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         dispatchEvent(new FlashEchoTestHasAudioEvent());
         var dispatcher:Dispatcher = new Dispatcher();
         dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.CLOSED_AUDIO_SELECTION));
-        PopUpManager.removePopUp(this);
+        PopUpUtil.removePopUp(this);
       }
       
       private function noButtonClicked():void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
old mode 100755
new mode 100644
index cbec69caf6e717b5f963f3075de1f5765da4689a..a02ed94f2b106a0b8413fc40f37cf7583aa493ec
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LockSettings.mxml
@@ -22,7 +22,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				xmlns:mate="http://mate.asfusion.com/" 
 				xmlns:common="org.bigbluebutton.common.*"
 				width="300" height="400" 
-				creationComplete="creationCompleteHandler(event)" 
 				styleName="lockSettingsWindowStyle"
 				showCloseButton="false" 
 				close="onCancelClicked()" 
@@ -30,20 +29,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	
 	<mx:Script>
 		<![CDATA[
-			import com.asfusion.mate.events.Dispatcher;
-			
 			import mx.events.CloseEvent;
-			import mx.events.FlexEvent;
-			import mx.managers.PopUpManager;
 			
 			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
-			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.core.vo.LockSettingsVO;
-			import org.bigbluebutton.main.model.ConferenceParameters;
-			import org.bigbluebutton.main.model.users.Conference;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
-			
+
 			private var images:Images = new Images();
 			
 			[Bindable] private var cancelIcon:Class = images.cancel;
@@ -65,24 +58,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					this.dispatchEvent(new CloseEvent(CloseEvent.CLOSE));
 				}
 			}
-			
-			
+
 			private function onSaveClicked():void {
 				var event:LockControlEvent = new LockControlEvent(LockControlEvent.SAVE_LOCK_SETTINGS);
 				var lockSettings:LockSettingsVO = new LockSettingsVO(chkDisableWebcam.selected, chkDisableMicrophone.selected, chkDisablePrivateChat.selected, chkDisablePublicChat.selected, chkDisableLayout.selected, chkLockOnJoin.selected, lockOnJoinConfigurable);
 				event.payload = lockSettings.toMap();
 				dispatchEvent(event);
 				
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}	
 			
 			private function onCancelClicked():void {
-				PopUpManager.removePopUp(this);
-			}
-			
-			protected function creationCompleteHandler(event:FlexEvent):void
-			{
-			
+				PopUpUtil.removePopUp(this);
 			}
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
old mode 100755
new mode 100644
index 5254556d829630f57992ce1963ca8d2c61a4995e..14e5beefd337a268380f405fbb79684223669efc
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoggedOutWindow.mxml
@@ -28,19 +28,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import flash.net.navigateToURL;
-			
-			import mx.managers.PopUpManager;
+			import flash.net.URLLoader;
+			import flash.net.URLRequest;
+			import flash.net.URLRequestMethod;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.events.ExitApplicationEvent;
 			import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
-
+			
 			private static const LOGGER:ILogger = getClassLogger(LoggedOutWindow);
 
 			[Bindable]
@@ -70,7 +71,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 
 			private function handleComplete(e:Event):void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 				exitApplication();
 			}
 
@@ -79,13 +80,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				logData.tags = ["logout"];
 				logData.message = "Log out redirection returned with error.";
 				LOGGER.error(JSON.stringify(logData));
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 				exitApplication();
 			}
 
 			private function onUserLoggedOutWindowClose(e:Event):void {
 				LOGGER.debug("Closing UserLoggedOutWindow");
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 
 			public function setReason(reason:String):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
old mode 100755
new mode 100644
index fba02f7be2d4375fa5c9c5bd2225ef5ce9a21b6f..77220f09621ea6df91324e8ce9289ba9026dad22
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
@@ -86,7 +86,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import mx.core.IFlexDisplayObject;
 			import mx.core.UIComponent;
 			import mx.events.FlexEvent;
-			import mx.managers.PopUpManager;
 			
 			import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
 			
@@ -99,6 +98,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.common.events.OpenWindowEvent;
 			import org.bigbluebutton.common.events.ToolbarButtonEvent;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
 			import org.bigbluebutton.core.managers.UserManager;
@@ -133,7 +133,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var stoppedModules:ArrayCollection;			
 			private var logWindow:LogWindow;
 			private var scWindow:ShortcutHelpWindow;
-			private var logoutWindow:LoggedOutWindow;
 			private var connectionLostWindow:ConnectionLostWindow;
 			
 			// LIVE or PLAYBACK
@@ -165,7 +164,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var isTunneling:Boolean = false;
 			
 			private var confirmingLogout:Boolean = false;
-			private var chromeBrowser:ChromeWebcamPermissionImage = null;
 			
 			public function getLogWindow() : LogWindow
 			{
@@ -408,141 +406,152 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					if (version != localeVersion) wrongLocaleVersion();
 				}	   			
 	   		}
+            private function handleFlashMicSettingsEvent(event:FlashMicSettingsEvent):void {
+                /**
+                 * There is a bug in Flex SDK 4.14 where the screen stays blurry if a
+                 * pop-up is opened from another pop-up. I delayed the second open to
+                 * avoid this case. - Chad
+                 */
+                this.callLater(function():void {
+                    var micSettings:FlashMicSettings = PopUpUtil.createModalPopUp(mdiCanvas, FlashMicSettings, false) as FlashMicSettings;
+                    if (micSettings) {
+                        micSettings.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
+                            var point1:Point = new Point();
+                            // Calculate position of TitleWindow in Application's coordinates. 
+                            point1.x = width / 2;
+                            point1.y = height / 2;
+                            micSettings.x = point1.x - (micSettings.width / 2);
+                            micSettings.y = point1.y - (micSettings.height / 2);
+                        });
+                    }
+                });
+            }
 
-			private function handleFlashMicSettingsEvent(event:FlashMicSettingsEvent):void {
-				/**
-				 * There is a bug in Flex SDK 4.14 where the screen stays blurry if a 
-				 * pop-up is opened from another pop-up. I delayed the second open to 
-				 * avoid this case. - Chad
-				 */
-				this.callLater( function():void {
-					var micSettings:FlashMicSettings = PopUpManager.createPopUp(mdiCanvas, FlashMicSettings, true) as FlashMicSettings;
-					micSettings.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-						var point1:Point = new Point();
-						// Calculate position of TitleWindow in Application's coordinates. 
-						point1.x = width/2;
-						point1.y = height/2;
-						micSettings.x = point1.x - (micSettings.width/2);
-						micSettings.y = point1.y - (micSettings.height/2);
-					});
-				});
-			}
-			
-      private function openVideoPreviewWindow(event:BBBEvent):void {
-        var camSettings:CameraDisplaySettings = CameraDisplaySettings(PopUpManager.createPopUp(mdiCanvas, CameraDisplaySettings, true));		
-        camSettings.defaultCamera = event.payload.defaultCamera;
-        camSettings.camerasArray = event.payload.camerasArray;
-        camSettings.publishInClient = event.payload.publishInClient;
-        camSettings.chromePermissionDenied = event.payload.chromePermissionDenied;
-        
-        var point1:Point = new Point();
-        // Calculate position of TitleWindow in Application's coordinates. 
-        point1.x = width/2;
-        point1.y = height/2;                
-        camSettings.x = point1.x - (camSettings.width/2);
-        camSettings.y = point1.y - (camSettings.height/2);	
-      }
-      
-	   	private function wrongLocaleVersion():void {
-				var localeWindow:OldLocaleWarnWindow = OldLocaleWarnWindow(PopUpManager.createPopUp(mdiCanvas, OldLocaleWarnWindow, false));
-
-				var point1:Point = new Point();
-	        	// Calculate position of TitleWindow in Application's coordinates. 
-				point1.x = width/2;
-				point1.y = height/2;              
-				localeWindow.x = point1.x - (localeWindow.width/2);
-				localeWindow.y = point1.y - (localeWindow.height/2);	
-      }
-
-      private function handleShowAudioSelectionWindowEvent(event:AudioSelectionWindowEvent):void {
-  	    var audioSelection:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, AudioSelectionWindow, true);
-		PopUpManager.centerPopUp(audioSelection);
-	  }
-          
-      private function handleWebRTCMediaRequestEvent(event:WebRTCMediaEvent):void {
-        var browser:String = ExternalInterface.call("determineBrowser")[0];
-        if (browser == "Firefox") {
-          var ffBrowser:FirefoxMicPermissionImage = PopUpManager.createPopUp(mdiCanvas, FirefoxMicPermissionImage, true) as FirefoxMicPermissionImage;
-          ffBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-            ffBrowser.x = 100;
-            ffBrowser.y = 150;
-          }); 
-        } else if (browser == "Chrome") {
-          var chromeBrowser:ChromeMicPermissionImage = PopUpManager.createPopUp(mdiCanvas, ChromeMicPermissionImage, true) as ChromeMicPermissionImage;
-          chromeBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-            chromeBrowser.x = 20;
-            chromeBrowser.y = 130;
-          });          
-        }
-      }
-      
-      private function handleWebRTCEchoTestConnectingEvent(event:WebRTCEchoTestEvent):void {
-        var webRTCEchoTest:WebRTCEchoTest = PopUpManager.createPopUp(mdiCanvas, WebRTCEchoTest, true) as WebRTCEchoTest;
-          webRTCEchoTest.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-          var point1:Point = new Point();
-          // Calculate position of TitleWindow in Application's coordinates. 
-          point1.x = width/2;
-          point1.y = height/2;
-          webRTCEchoTest.x = point1.x - (webRTCEchoTest.width/2);
-          webRTCEchoTest.y = point1.y - (webRTCEchoTest.height/2);
-        });        
-      }
-
-      private function handleShareCameraRequestEvent(event:ShareCameraRequestEvent):void {
-          if (ExternalInterface.call("determineBrowser")[0] == "Chrome" && chromeBrowser == null ) {
-          chromeBrowser = PopUpManager.createPopUp(mdiCanvas, ChromeWebcamPermissionImage , true) as ChromeWebcamPermissionImage;
-          chromeBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-          var point1:Point = new Point();
-          // Calculate position of TitleWindow in Application's coordinates.
-          point1.x = width/2;
-          point1.y = height/2;
-          if (Capabilities.os.indexOf("Mac") >= 0) {
-            chromeBrowser.x = (mdiCanvas.width - chromeBrowser.width);
-		  }
-          else {
-		    chromeBrowser.x = 20;
-		  }
-	      chromeBrowser.y = 20;
-         });
-       }
-     }
-      
-      private function handleMeetingNotFoundEvent(e:MeetingNotFoundEvent):void {
-        showlogoutWindow(ResourceUtil.getInstance().getString('bbb.mainshell.meetingNotFound'));
-      }
-
-			private function showlogoutWindow(reason:String):void {
-				if (layoutOptions!= null && layoutOptions.showLogoutWindow) {
-					if (UserManager.getInstance().getConference().iAskedToLogout) {
-						handleExitApplicationEvent();
-						return;
-					}
-					if (logoutWindow != null) return;
-					logoutWindow = LoggedOutWindow(PopUpManager.createPopUp( mdiCanvas, LoggedOutWindow, true));
-					
-					var point1:Point = new Point();
-					// Calculate position of TitleWindow in Application's coordinates. 
-					point1.x = width/2;
-					point1.y = height/2;                 
-					logoutWindow.x = point1.x - (logoutWindow.width/2);
-					logoutWindow.y = point1.y - (logoutWindow.height/2);
-					
-					logoutWindow.setReason(reason);
-					mdiCanvas.removeAllPopUps();
-					removeToolBars();
-				} else {
-					mdiCanvas.removeAllPopUps();
-					removeToolBars();
-					var pageHost:String = FlexGlobals.topLevelApplication.url.split("/")[0];
-					var pageURL:String = FlexGlobals.topLevelApplication.url.split("/")[2];
-					LOGGER.debug("SingOut to [{0}//{1}/bigbluebutton/api/signOut]", [pageHost, pageURL]);
-					var request:URLRequest = new URLRequest(pageHost + "//" + pageURL + "/bigbluebutton/api/signOut");
-					var urlLoader:URLLoader = new URLLoader();
-					urlLoader.addEventListener(Event.COMPLETE, handleLogoutComplete);	
-					urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLogoutError);
-					urlLoader.load(request);
-				}	        
-			}
+            private function openVideoPreviewWindow(event:BBBEvent):void {
+                var camSettings:CameraDisplaySettings = PopUpUtil.createModalPopUp(mdiCanvas, CameraDisplaySettings, true) as CameraDisplaySettings;
+                if (camSettings) {
+                    camSettings.defaultCamera = event.payload.defaultCamera;
+                    camSettings.camerasArray = event.payload.camerasArray;
+                    camSettings.publishInClient = event.payload.publishInClient;
+                    camSettings.chromePermissionDenied = event.payload.chromePermissionDenied;
+					camSettings.updateCameraList();
+
+                    var point1:Point = new Point();
+                    // Calculate position of TitleWindow in Application's coordinates. 
+                    point1.x = width / 2;
+                    point1.y = height / 2;
+                    camSettings.x = point1.x - (camSettings.width / 2);
+                    camSettings.y = point1.y - (camSettings.height / 2);
+                }
+            }
+
+            private function wrongLocaleVersion():void {
+                var localeWindow:OldLocaleWarnWindow = PopUpUtil.createNonModelPopUp(mdiCanvas, OldLocaleWarnWindow, false) as OldLocaleWarnWindow;
+                if (localeWindow) {
+                    var point1:Point = new Point();
+                    // Calculate position of TitleWindow in Application's coordinates. 
+                    point1.x = width / 2;
+                    point1.y = height / 2;
+                    localeWindow.x = point1.x - (localeWindow.width / 2);
+                    localeWindow.y = point1.y - (localeWindow.height / 2);
+                }
+            }
+
+            private function handleShowAudioSelectionWindowEvent(event:AudioSelectionWindowEvent):void {
+                PopUpUtil.createModalPopUp(mdiCanvas, AudioSelectionWindow, true);
+            }
+
+            private function handleWebRTCMediaRequestEvent(event:WebRTCMediaEvent):void {
+                var browser:String = ExternalInterface.call("determineBrowser")[0];
+                if (browser == "Firefox") {
+                    var ffBrowser:FirefoxMicPermissionImage = PopUpUtil.createModalPopUp(mdiCanvas, FirefoxMicPermissionImage, false) as FirefoxMicPermissionImage;
+                    if (ffBrowser) {
+                        ffBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
+                            ffBrowser.x = 100;
+                            ffBrowser.y = 150;
+                        });
+                    }
+                } else if (browser == "Chrome") {
+                    var chromeBrowser:ChromeMicPermissionImage = PopUpUtil.createModalPopUp(mdiCanvas, ChromeMicPermissionImage, false) as ChromeMicPermissionImage;
+                    if (chromeBrowser) {
+                        chromeBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
+                            chromeBrowser.x = 20;
+                            chromeBrowser.y = 130;
+                        });
+                    }
+                }
+            }
+
+            private function handleWebRTCEchoTestConnectingEvent(event:WebRTCEchoTestEvent):void {
+                var webRTCEchoTest:WebRTCEchoTest = PopUpUtil.createModalPopUp(mdiCanvas, WebRTCEchoTest, false) as WebRTCEchoTest;
+                if (webRTCEchoTest) {
+                    webRTCEchoTest.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
+                        var point1:Point = new Point();
+                        // Calculate position of TitleWindow in Application's coordinates. 
+                        point1.x = width / 2;
+                        point1.y = height / 2;
+                        webRTCEchoTest.x = point1.x - (webRTCEchoTest.width / 2);
+                        webRTCEchoTest.y = point1.y - (webRTCEchoTest.height / 2);
+                    });
+                }
+            }
+
+            private function handleShareCameraRequestEvent(event:ShareCameraRequestEvent):void {
+                if (ExternalInterface.call("determineBrowser")[0] == "Chrome") {
+                    var chromeWebcmPermissionImg : ChromeWebcamPermissionImage = PopUpUtil.createModalPopUp(mdiCanvas, ChromeWebcamPermissionImage, false) as ChromeWebcamPermissionImage;
+                    if (chromeWebcmPermissionImg) {
+                        chromeWebcmPermissionImg.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
+                            var point1:Point = new Point();
+                            // Calculate position of TitleWindow in Application's coordinates.
+                            point1.x = width / 2;
+                            point1.y = height / 2;
+                            if (Capabilities.os.indexOf("Mac") >= 0) {
+                                chromeWebcmPermissionImg.x = (mdiCanvas.width - chromeWebcmPermissionImg.width);
+                            } else {
+                                chromeWebcmPermissionImg.x = 20;
+                            }
+                            chromeWebcmPermissionImg.y = 20;
+                        });
+                    }
+                }
+            }
+
+            private function handleMeetingNotFoundEvent(e:MeetingNotFoundEvent):void {
+                showlogoutWindow(ResourceUtil.getInstance().getString('bbb.mainshell.meetingNotFound'));
+            }
+
+            private function showlogoutWindow(reason:String):void {
+                if (layoutOptions != null && layoutOptions.showLogoutWindow) {
+                    if (UserManager.getInstance().getConference().iAskedToLogout) {
+                        handleExitApplicationEvent();
+                        return;
+                    }
+                    var logoutWindow:LoggedOutWindow = PopUpUtil.createModalPopUp(mdiCanvas, LoggedOutWindow, false) as LoggedOutWindow;
+                    if (logoutWindow) {
+                        var point1:Point = new Point();
+                        // Calculate position of TitleWindow in Application's coordinates. 
+                        point1.x = width / 2;
+                        point1.y = height / 2;
+                        logoutWindow.x = point1.x - (logoutWindow.width / 2);
+                        logoutWindow.y = point1.y - (logoutWindow.height / 2);
+
+                        logoutWindow.setReason(reason);
+                        mdiCanvas.removeAllPopUps();
+                        removeToolBars();
+                    }
+                } else {
+                    mdiCanvas.removeAllPopUps();
+                    removeToolBars();
+                    var pageHost:String = FlexGlobals.topLevelApplication.url.split("/")[0];
+                    var pageURL:String = FlexGlobals.topLevelApplication.url.split("/")[2];
+                    LOGGER.debug("SingOut to [{0}//{1}/bigbluebutton/api/signOut]", [pageHost, pageURL]);
+                    var request:URLRequest = new URLRequest(pageHost + "//" + pageURL + "/bigbluebutton/api/signOut");
+                    var urlLoader:URLLoader = new URLLoader();
+                    urlLoader.addEventListener(Event.COMPLETE, handleLogoutComplete);
+                    urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLogoutError);
+                    urlLoader.load(request);
+                }
+            }
 
             /**
              * Removes toolbars from the display list.
@@ -635,33 +644,36 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function closeNetworkStatsWindow(e:Event = null):void {
 				networkStatsWindow.disappear();
 			}
-			
-			private function openLockSettingsWindow(event:LockControlEvent):void {
-				var conference:Conference = UserManager.getInstance().getConference();
-				var lsv:LockSettingsVO = conference.getLockSettings();
-        
-				var popUp:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, LockSettings, true);
-				var ls:LockSettings = LockSettings(popUp);
-				ls.disableCam = lsv.getDisableCam();
-				ls.disableMic = lsv.getDisableMic();
-				ls.disablePrivChat = lsv.getDisablePrivateChat();
-				ls.disablePubChat = lsv.getDisablePublicChat();
-				ls.lockedLayout = lsv.getLockedLayout();
-				ls.lockOnJoin = lsv.getLockOnJoin();
-				ls.lockOnJoinConfigurable = lsv.getLockOnJoinConfigurable();
-        
-				var point1:Point = new Point();
-				point1.x = width/2;
-				point1.y = height/2;
-				ls.x = point1.x - (ls.width/2);
-				ls.y = point1.y - (ls.height/2);	
-			}
-			
-			private function openBreakoutRoomsWindow(e:BreakoutRoomEvent):void  {
-				var popUp:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, BreakoutRoomSettings, true);
-				PopUpManager.centerPopUp(popUp);
-				BreakoutRoomSettings(popUp).initCreateBreakoutRooms(e.joinMode, e.record);
-			}
+
+            private function openLockSettingsWindow(event:LockControlEvent):void {
+                var conference:Conference = UserManager.getInstance().getConference();
+                var lsv:LockSettingsVO = conference.getLockSettings();
+
+                var popUp:IFlexDisplayObject = PopUpUtil.createModalPopUp(mdiCanvas, LockSettings, false);
+                if (popUp) {
+                    var ls:LockSettings = LockSettings(popUp);
+                    ls.disableCam = lsv.getDisableCam();
+                    ls.disableMic = lsv.getDisableMic();
+                    ls.disablePrivChat = lsv.getDisablePrivateChat();
+                    ls.disablePubChat = lsv.getDisablePublicChat();
+                    ls.lockedLayout = lsv.getLockedLayout();
+                    ls.lockOnJoin = lsv.getLockOnJoin();
+                    ls.lockOnJoinConfigurable = lsv.getLockOnJoinConfigurable();
+
+                    var point1:Point = new Point();
+                    point1.x = width / 2;
+                    point1.y = height / 2;
+                    ls.x = point1.x - (ls.width / 2);
+                    ls.y = point1.y - (ls.height / 2);
+                }
+            }
+
+            private function openBreakoutRoomsWindow(e:BreakoutRoomEvent):void {
+                var popUp:IFlexDisplayObject = PopUpUtil.createModalPopUp(mdiCanvas, BreakoutRoomSettings, true);
+                if (popUp != null) {
+                    BreakoutRoomSettings(popUp).initCreateBreakoutRooms(e.joinMode, e.record);
+                }
+            }
 			
 			private function onFooterLinkClicked(e:TextEvent):void{
 				if (ExternalInterface.available) {
@@ -672,7 +684,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	</mx:Script>
 	
 	<common:TabIndexer id="tabIndexer" startIndex="100000"
-					   tabIndices="{[langSelector, logBtn]}"/>
+					   tabIndices="{[warningBtn, langSelector, logBtn]}"/>
 
 	<views:MainToolbar id="toolbar" 
 					   dock="true" 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
index 955661182a74752a80ee6d20015c3c17106c8a89..d78828d0c6c7f22cc3017b3b1ee43ad3511e277f 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
@@ -81,6 +81,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			/**
 			 * Removes all display list containers created using PopUpManager
+			 * @fixme: move to PopUpUtil and improve
 			 */
 			public function removeAllPopUps():void{
 				for (var i:int = systemManager.numChildren-1; i>0; i-=1){
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
old mode 100755
new mode 100644
index 79b90afdbadbfade20c7d0e8ef64ea33693fd21a..c42ee071fbac812ea52ea855b64014e0926a0605
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
@@ -24,21 +24,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	xmlns:mate="http://mate.asfusion.com/" xmlns:common="org.bigbluebutton.common.*"
 	xmlns:views="org.bigbluebutton.main.views.*"
 	enabled="true" visible="{showToolbar}"
-	initialize="init()" creationComplete="onCreationComplete()">   
+	initialize="init()">   
 	
 	<mate:Listener type="{ToolbarButtonEvent.ADD}" method="handleAddToolbarButtonEvent" />	
 	<mate:Listener type="{ToolbarButtonEvent.REMOVE}" method="handleRemoveToolbarButtonEvent"/>
 	<mate:Listener type="{BBBEvent.END_MEETING_EVENT}" method="handleEndMeetingEvent"/>
 	<mate:Listener type="{ConnectionFailedEvent.USER_LOGGED_OUT}" method="hideToolbar" />
 	<mate:Listener type="{ConnectionFailedEvent.CONNECTION_CLOSED}" method="hideToolbar" />
-	<mate:Listener type="{ConfigEvent.CONFIG_EVENT}" method="gotConfigParameters" />
+	<mate:Listener type="{ConfigLoadedEvent.CONFIG_LOADED_EVENT}" method="initOptions"  />
 	<mate:Listener type="{SettingsEvent.SETTINGS_MODULE_LOADED}" method="showSettingsButton" />
 	<mate:Listener type="{ShortcutEvent.REMOTE_OPEN_SHORTCUT_WIN}" method="remoteShortcutClick" />
 	<mate:Listener type="{ShortcutEvent.LOGOUT}" method="remoteLogout" />
 	<mate:Listener type="{ShortcutEvent.FOCUS_SHORTCUT_BUTTON}" method="focusShortcutButton" />
 	<mate:Listener type="{ShortcutEvent.FOCUS_LOGOUT_BUTTON}" method="focusLogoutButton" />
 	<mate:Listener type="{ConferenceCreatedEvent.CONFERENCE_CREATED_EVENT}" method="retrieveMeetingName" />
-  <mate:Listener type="{BBBEvent.CHANGE_RECORDING_STATUS}" method="onRecordingStatusChanged" />
+	<mate:Listener type="{BBBEvent.CHANGE_RECORDING_STATUS}" method="onRecordingStatusChanged" />
   
 	<mx:Script>
 		<![CDATA[
@@ -56,7 +56,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.events.BBBEvent;
-			import org.bigbluebutton.main.events.ConfigEvent;
+			import org.bigbluebutton.main.events.ConfigLoadedEvent;
 			import org.bigbluebutton.main.events.LogoutEvent;
 			import org.bigbluebutton.main.events.SettingsEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
@@ -76,6 +76,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var showToolbar:Boolean = false;
 			[Bindable] public var toolbarOptions:LayoutOptions = new LayoutOptions();		
 			[Bindable] private var numButtons:int;
+			
+			private var logoutAlert:Alert; 
       
 			/*
 			 * Because of the de-centralized way buttons are added to the toolbar, there is a large gap between the tab indexes of the main buttons
@@ -97,9 +99,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 			}
       
-      private function onCreationComplete():void {
-      }
-      
       private function checkAccessiblity(e:TimerEvent):void {
         // remove the quick links if there's no screen reader active
         if (!Accessibility.active) {
@@ -122,6 +121,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           case "chat":
             dispatcher.dispatchEvent(new ShortcutEvent(ShortcutEvent.FOCUS_CHAT_WINDOW));
             break;
+		  case "caption":
+			  dispatcher.dispatchEvent(new ShortcutEvent(ShortcutEvent.FOCUS_CAPTION_WINDOW));
+			  break;
          }
        }
 								
@@ -208,7 +210,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			private function onHelpButtonClicked():void {
-        DEFAULT_HELP_URL = BBB.getConfigManager().config.help.url;        
 				navigateToURL(new URLRequest(DEFAULT_HELP_URL))
 			}
 			
@@ -216,26 +217,24 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				LOGGER.debug("Received end meeting event.");
 				doLogout();
 			}
-			
-			
-			private function confirmLogout():void {
-				if (toolbarOptions.confirmLogout){
-					// Confirm logout using built-in alert
-					var alert:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.logout.confirm.message'), ResourceUtil.getInstance().getString('bbb.logout.confirm.title'), Alert.YES | Alert.NO, this, alertLogout, null, Alert.YES);
-					
-          var newX:Number = btnLogout.x + btnLogout.width - alert.width;
-					var newY:Number = btnLogout.y + btnLogout.height + 5;
-												
-					alert.validateNow();
-					alert.move(newX, newY);
-					//Accessibility.updateProperties();
-				}
-				else{
-					doLogout();
-				}
-			}
-			
-						
+
+            private function confirmLogout():void {
+                if (toolbarOptions.confirmLogout) {
+                    if (logoutAlert == null) {
+                        // Confirm logout using built-in alert
+                        logoutAlert = Alert.show(ResourceUtil.getInstance().getString('bbb.logout.confirm.message'), ResourceUtil.getInstance().getString('bbb.logout.confirm.title'), Alert.YES | Alert.NO, this, alertLogout, null, Alert.YES);
+
+                        var newX:Number = btnLogout.x + btnLogout.width - logoutAlert.width;
+                        var newY:Number = btnLogout.y + btnLogout.height + 5;
+
+                        logoutAlert.validateNow();
+                        logoutAlert.move(newX, newY);
+                    }
+                } else {
+                    doLogout();
+                }
+            }
+
 			private function alertLogout(e:CloseEvent):void {
 				// Check to see if the YES button was pressed.
 				if (e.detail==Alert.YES) {
@@ -249,6 +248,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					 */
 					callLater(doLogout);
 				}
+				logoutAlert = null;
 			}
 			
 			private function doLogout():void {
@@ -314,12 +314,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					//}
 				}
 			}
-						
-			private function gotConfigParameters(e:ConfigEvent):void{
-				shortcutKeysBtn.includeInLayout = shortcutKeysBtn.visible = e.config.shortcutKeysShowButton; 
-				DEFAULT_HELP_URL = e.config.helpURL;
-			}
 			
+			public function initOptions(e:Event):void {
+				shortcutKeysBtn.includeInLayout = shortcutKeysBtn.visible = BBB.getConfigManager().config.shortcutKeys['showButton'];
+				DEFAULT_HELP_URL = BBB.getConfigManager().config.help['url'];
+			}
+
 			private function onDisconnectTest():void{
 				var d:Dispatcher = new Dispatcher();
 				var e:LogoutEvent = new LogoutEvent(LogoutEvent.DISCONNECT_TEST);
@@ -378,7 +378,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		]]>
 	</mx:Script>
 	
-	<common:TabIndexer id="quickLinksIndexer" startIndex="102" tabIndices="{[usersLinkBtn, webcamLinkButton, presentationLinkBtn, chatLinkBtn]}"/>
+	<common:TabIndexer id="quickLinksIndexer" startIndex="102" tabIndices="{[usersLinkBtn, webcamLinkButton, presentationLinkBtn, chatLinkBtn, captionLinkBtn]}"/>
 	<common:TabIndexer id="buttonsIndexer" startIndex="{quickLinksIndexer.startIndex + numButtons + 10}"
 					   tabIndices="{[recordBtn, muteMeBtn, shortcutKeysBtn, helpBtn, btnLogout]}"/>
 
@@ -396,6 +396,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         <mx:LinkButton id="chatLinkBtn" click="onQuickLinkClicked('chat')" label="{ResourceUtil.getInstance().getString('bbb.chat.quickLink.label')}" 
                        accessibilityDescription="{chatLinkBtn.label}" toolTip="{chatLinkBtn.label}"
                        height="22" styleName="quickWindowLinkStyle" />
+		<mx:LinkButton id="captionLinkBtn" click="onQuickLinkClicked('caption')" label="{ResourceUtil.getInstance().getString('bbb.caption.quickLink.label')}" 
+					   accessibilityDescription="{captionLinkBtn.label}" toolTip="{captionLinkBtn.label}"
+					   height="22" styleName="quickWindowLinkStyle" />
     </mx:HBox>
 	<mx:HBox id="addedBtns"/>
 	<views:RecordButton id="recordBtn"/>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MicWarning.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MicWarning.mxml
deleted file mode 100755
index e2f913b87198a0f2bc57d512338725103e9d9886..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MicWarning.mxml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
-				xmlns:mate="http://mate.asfusion.com/" 
-				width="400"
-				horizontalAlign="center"
-				title="{ResourceUtil.getInstance().getString('bbb.micWarning.title')}" >
-	<mx:Script>
-		<![CDATA[
-			import mx.managers.PopUpManager;
-			
-			import org.bigbluebutton.util.i18n.ResourceUtil;
-			
-			public var micsettings:MicSettings;
-			
-			private function joinAnyway():void {                          
-				PopUpManager.removePopUp(this);
-				micsettings.joinConference();
-			}
-		]]>
-	</mx:Script>
-	<mx:Text width="100%" textAlign="center" text="{ResourceUtil.getInstance().getString('bbb.micWarning.message')}" />  
-	<mx:HBox>      																		     
-		<mx:Button label="{ResourceUtil.getInstance().getString('bbb.micWarning.joinBtn.label')}" click="joinAnyway();" /> 
-		<mx:Button label="{ResourceUtil.getInstance().getString('bbb.micWarning.testAgain.label')}" click="PopUpManager.removePopUp(this);"/> 
-	</mx:HBox> 
-</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/OldLocaleWarnWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/OldLocaleWarnWindow.mxml
old mode 100755
new mode 100644
index 2598a1f870c0b9bd046c4547529a4cb0fc528d0c..f30a1111166e7d852ce20190af291fdc01bc5688
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/OldLocaleWarnWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/OldLocaleWarnWindow.mxml
@@ -25,17 +25,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     x="168" y="86" layout="vertical" width="400" height="150" horizontalAlign="center">
 	<mx:Script>
 		<![CDATA[
-			import mx.managers.PopUpManager;
-			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.core.BBB;
-			import org.bigbluebutton.util.i18n.ResourceUtil; 
-			
+			import org.bigbluebutton.core.PopUpUtil;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+
 			private static const LOGGER:ILogger = getClassLogger(OldLocaleWarnWindow);      
 			private const windowTitleDefault:String = "Warning: Old Language Version";
 			private const reminder1Default:String = "You have an old language translation of BigBlueButton.";
 			private const reminder2Default:String = "Please clear your browser cache and try again.";
+
 			[Bindable] private var windowTitle:String;
 			[Bindable] private var oldLocalesReminder1:String;
 			[Bindable] private var oldLocalesReminder2:String;
@@ -55,25 +55,25 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				if ((reminder2 == null) || (reminder2 == "")) oldLocalesReminder2 = reminder2Default;
 				else oldLocalesReminder2 = reminder2;
 			}
-			
-      private function redirect():void { 
-				var logoutURL:String = BBB.getLogoutURL();
-				var request:URLRequest = new URLRequest(logoutURL);
-				LOGGER.debug("Log out url: " + logoutURL);
-				request.method = URLRequestMethod.GET;
-				var urlLoader:URLLoader = new URLLoader();
-				urlLoader.addEventListener(Event.COMPLETE, handleComplete);	
-				urlLoader.load(request);
-      }
-            
+
+            private function redirect():void {
+                var logoutURL:String = BBB.getLogoutURL();
+                var request:URLRequest = new URLRequest(logoutURL);
+                LOGGER.debug("Log out url: " + logoutURL);
+                request.method = URLRequestMethod.GET;
+                var urlLoader:URLLoader = new URLLoader();
+                urlLoader.addEventListener(Event.COMPLETE, handleComplete);
+                urlLoader.load(request);
+            }
+
 			private function handleComplete(e:Event):void {	
 				var request:URLRequest = new URLRequest(BBB.getLogoutURL());
 				navigateToURL(request, '_self');
-				PopUpManager.removePopUp(this);				
+				PopUpUtil.removePopUp(this);				
 			}
 			
             private function onUserLoggedOutWindowClose(e:Event):void {
-            	PopUpManager.removePopUp(this);
+            	PopUpUtil.removePopUp(this);
             }
 			
 		]]>
@@ -82,4 +82,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mx:Label text="{oldLocalesReminder2}"/>
 	<mx:Button id="okBtn" label="OK" click="redirect()"/>
 
-</mx:TitleWindow> 
\ No newline at end of file
+</mx:TitleWindow>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/ShortcutHelpWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/ShortcutHelpWindow.mxml
index ecaddd20eb7d3f9a4f25908f2e978ef0bf7d7705..10505e152e7f07c86c1580f8ecc64b721b060acd 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/ShortcutHelpWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/ShortcutHelpWindow.mxml
@@ -69,22 +69,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 											  'bbb.shortcutkey.present.fitWidth', 'bbb.shortcutkey.present.fitPage'];
 			
 			private var chatResource:Array = ['bbb.shortcutkey.chat.focusTabs', 'bbb.shortcutkey.chat.focusBox', 'bbb.shortcutkey.chat.sendMessage',
-											  'bbb.shortcutkey.chat.closePrivate', 'bbb.shortcutkey.chat.explanation', 'bbb.shortcutkey.chat.chatbox.gofirst', 
-											  'bbb.shortcutkey.chat.chatbox.goback', 'bbb.shortcutkey.chat.chatbox.advance', 'bbb.shortcutkey.chat.chatbox.golatest',
-											  'bbb.shortcutkey.chat.chatbox.repeat', 'bbb.shortcutkey.chat.chatbox.goread'];
+											  'bbb.shortcutkey.chat.closePrivate'];
 			
 			private var userResource:Array = ['bbb.shortcutkey.users.focusUsers', 'bbb.shortcutkey.users.makePresenter', 'bbb.shortcutkey.users.mute', 
-											  /*'bbb.shortcutkey.users.kick',*/ 'bbb.shortcutkey.users.muteall'];
+											  'bbb.shortcutkey.users.kick', 'bbb.shortcutkey.users.muteall', 'bbb.shortcutkey.users.focusBreakoutRooms',
+											  'bbb.shortcutkey.users.listenToBreakoutRoom', 'bbb.shortcutkey.users.joinBreakoutRoom'];
 			
 			[Bindable]
 			private var shownKeys:ArrayCollection;
 			
 			private var modifier:String;
 			private var globalModifier:String;
+			private var globalAlternateModifier:String;
 			
 			private function init():void {
 				modifier = ExternalInterface.call("determineModifier");
 				globalModifier = ExternalInterface.call("determineGlobalModifier");
+				globalAlternateModifier = ExternalInterface.call("determineGlobalAlternateModifier");
 				
 				ShortcutOptions.initialize();
 				
@@ -195,8 +196,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 								|| convKey == ResourceUtil.getInstance().getString('bbb.shortcutkey.specialKeys.right') 
 								|| convKey == ResourceUtil.getInstance().getString('bbb.shortcutkey.specialKeys.down')){
 						keyList.addItem({shortcut:convKey, func:(ResourceUtil.getInstance().getString(resource[i] + '.function'))});
-					}
-					else{
+					} else if (convKey == ResourceUtil.getInstance().getString('bbb.shortcutkey.specialKeys.minus')
+								|| convKey == ResourceUtil.getInstance().getString('bbb.shortcutkey.specialKeys.plus')) {
+						keyList.addItem({shortcut:globalAlternateModifier + convKey, func:(ResourceUtil.getInstance().getString(resource[i] + '.function'))});
+					} else{
 						keyList.addItem({shortcut:mod + convKey, func:(ResourceUtil.getInstance().getString(resource[i] + '.function'))});
 					}
 				}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/WarningButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/WarningButton.mxml
index 50013250951b357b8ba4157c9f3c70e624e1c9c8..507d5d47b217b7914ac2cc3416116162eb8041b2 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/WarningButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/WarningButton.mxml
@@ -36,14 +36,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import flash.globalization.DateTimeFormatter;
 			import flash.globalization.DateTimeStyle;
 			import flash.globalization.LocaleID;
-
+			
 			import mx.controls.ToolTip;
 			import mx.core.FlexGlobals;
-			import mx.managers.PopUpManager;
 			import mx.managers.ToolTipManager;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.main.events.ClientStatusEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 			
@@ -124,15 +124,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				}
 				return -1;
 			}
-			
-			private function handleButtonClick():void {
-				hideNotification();
-				
-				var clientStatusWindow:ClientStatusWindow = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, ClientStatusWindow, true) as ClientStatusWindow;
-				clientStatusWindow.setMessages(messages);
-				PopUpManager.centerPopUp(clientStatusWindow);
-			}
-			
+
+            private function handleButtonClick():void {
+                hideNotification();
+
+                var clientStatusWindow:ClientStatusWindow = PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, ClientStatusWindow, true) as ClientStatusWindow
+                if (clientStatusWindow) {
+                    clientStatusWindow.setMessages(messages);
+                }
+            }
+
 			private function handleMove():void {
 				if (notification) {
 					var location:Point = localToGlobal(new Point(0,0));
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
old mode 100755
new mode 100644
index 4435fe9a5c53eebddd1b23951e7b7edfcc416c0c..a5dc0f7c1f9ae8c7ee64babc99159d531fe27231
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
@@ -24,8 +24,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				creationComplete="onCreationComplete()" 
 				styleName="micSettingsWindowStyle"
 				showCloseButton="false" 
-				close="onCancelClicked()" 
-				keyDown="handleKeyDown(event)">
+				close="onCancelClicked()">
 	
 	<mate:Listener type="{WebRTCEchoTestStartedEvent.WEBRTC_ECHO_TEST_STARTED}" method="handleWebRTCEchoTestStartedEvent" />
 	<mate:Listener type="{WebRTCEchoTestEvent.WEBRTC_ECHO_TEST_ENDED}" method="handleWebRTCEchoTestEndedEvent" />
@@ -41,13 +40,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import mx.managers.PopUpManager;
-			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.UsersUtil;
-			import org.bigbluebutton.main.api.JSLog;
 			import org.bigbluebutton.modules.phone.PhoneModel;
 			import org.bigbluebutton.modules.phone.events.WebRTCCallEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCEchoTestEvent;
@@ -55,7 +52,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.modules.phone.events.WebRTCJoinedVoiceConferenceEvent;
 			import org.bigbluebutton.modules.phone.models.Constants;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
-      
+
 			private static const LOGGER:ILogger = getClassLogger(WebRTCEchoTest);      
 			private static var DEFAULT_HELP_URL:String = "http://www.bigbluebutton.org/content/videos";
 			
@@ -65,28 +62,24 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			override public function move(x:Number, y:Number):void {
 				return;
 			}
-			
-			private function onCancelClicked():void {
 
-				if (dotTimer) dotTimer.stop();
-				PopUpManager.removePopUp(this);
-			}
-			
-			private function handleKeyDown(event:KeyboardEvent):void {
-				
-			}
-			
-			private function onCreationComplete():void {
-				setCurrentState("connecting");
-				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.connecting');
-				dotTimer = new Timer(200, 0);
-				dotTimer.addEventListener(TimerEvent.TIMER, dotAnimate);
-				dotTimer.start();
-        
-        var testState:String = PhoneModel.getInstance().webRTCModel.state;
-        if (testState == Constants.DO_ECHO_TEST) {
-          webRTCEchoTestStarted();
-        }
+            private function onCancelClicked():void {
+                if (dotTimer)
+                    dotTimer.stop();
+                PopUpUtil.removePopUp(this);
+            }
+
+            private function onCreationComplete():void {
+                setCurrentState("connecting");
+                lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.connecting');
+                dotTimer = new Timer(200, 0);
+                dotTimer.addEventListener(TimerEvent.TIMER, dotAnimate);
+                dotTimer.start();
+
+                var testState:String = PhoneModel.getInstance().webRTCModel.state;
+                if (testState == Constants.DO_ECHO_TEST) {
+                    webRTCEchoTestStarted();
+                }
 			}
 			
 			private function dotAnimate(e:TimerEvent):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
index b4568e8f6803307e0084b425e4a9f6367a0b2c8b..3e948a57089ba72e2d69983af78559b13895c0c9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
@@ -29,27 +29,24 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			creationComplete="onCreationComplete()">
 	
 	<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
-	
+	<mate:Listener type="{ShortcutEvent.FOCUS_CAPTION_WINDOW}" method="focusWindow" />
+
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import flexlib.controls.tabBarClasses.SuperTab;
-			
 			import mx.binding.utils.BindingUtils;
 			import mx.binding.utils.ChangeWatcher;
 			import mx.collections.ArrayCollection;
-			import mx.controls.Alert;
 			import mx.controls.Button;
-			import mx.events.FlexEvent;
-			import mx.managers.PopUpManager;
+			
+			import flexlib.controls.tabBarClasses.SuperTab;
 			
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
 			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.main.views.MainCanvas;
 			import org.bigbluebutton.modules.caption.events.RequestTranscriptsEvent;
-			import org.bigbluebutton.modules.caption.events.SendEditCaptionHistoryEvent;
-			import org.bigbluebutton.modules.caption.events.SendUpdateCaptionOwnerEvent;
 			import org.bigbluebutton.modules.caption.model.CaptionOptions;
 			import org.bigbluebutton.modules.caption.model.Transcript;
 			import org.bigbluebutton.modules.caption.model.Transcripts;
@@ -163,10 +160,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					addTextTab();
 				}
 				
-				var tab:Button = captionTabs.getTabAt(0);
-				if (tab != null) {
-					tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A));
-				}
+				captionTabs.selectedIndex = 0;
+				
+				// When the tab is switched we want to autofocus to the area that we likely want to immediately interact with, 
+				// but if we move focus immediately the tab's contents aren't actually visible on the screen. This results in 
+				// a screen reader not recognizing the focus shift. We need to delay the focus change for a couple of frames, 
+				// but there isn't a good event to listen for so a short Timer was used instead.
+				textTab.delayedFocusTextArea();
 			}
 			
 			private function onTranscriptOwnerIDChange(o:Object):void {
@@ -233,7 +233,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					setTextTabLabel(currentTranscript.ownerID);
 				}
 			}
-			
+
+			private function focusWindow(e:ShortcutEvent):void {
+				focusManager.setFocus(titleBarOverlay);
+			}
 		]]>
 	</mx:Script>
 	<mx:Box width="100%" height="100%" horizontalAlign="left">
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/TextTab.as b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/TextTab.as
index f4dd6d2884f9069cd01a954c6dfb5e5bb8cc41f6..b60470ff1b9254458b7f67458954e5657b2b3632 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/TextTab.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/TextTab.as
@@ -19,6 +19,7 @@
 
 package org.bigbluebutton.modules.caption.views {
 	import com.asfusion.mate.events.Dispatcher;
+	import com.asfusion.mate.events.Listener;
 	
 	import flash.events.Event;
 	import flash.events.KeyboardEvent;
@@ -36,6 +37,7 @@ package org.bigbluebutton.modules.caption.views {
 	import mx.controls.Button;
 	import mx.events.FlexEvent;
 	
+	import org.bigbluebutton.common.events.LocaleChangeEvent;
 	import org.bigbluebutton.core.managers.UserManager;
 	import org.bigbluebutton.modules.caption.events.SendEditCaptionHistoryEvent;
 	import org.bigbluebutton.modules.caption.events.SendUpdateCaptionOwnerEvent;
@@ -74,6 +76,8 @@ package org.bigbluebutton.modules.caption.views {
 		private var outputArea:TextArea2;
 		private var claimButton:Button;
 		
+		private var focusSwitchTimer:Timer;
+		
 		public function TextTab(startIndex:int, captionOptions:CaptionOptions) {
 			super();
 			
@@ -98,8 +102,6 @@ package org.bigbluebutton.modules.caption.views {
 			addChild(outputArea);
 			
 			claimButton = new Button();
-			claimButton.label = ResourceUtil.getInstance().getString('bbb.caption.option.takeowner');
-			claimButton.toolTip = ResourceUtil.getInstance().getString('bbb.caption.option.takeowner.tooltip');
 			claimButton.height = 22; 
 			claimButton.visible = false;
 			claimButton.includeInLayout = false;
@@ -111,6 +113,12 @@ package org.bigbluebutton.modules.caption.views {
 			_sendTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onSendTimerComplete);
 			
 			addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
+			
+			var localeListener:Listener = new Listener();
+			localeListener.type = LocaleChangeEvent.LOCALE_CHANGED;
+			localeListener.method = localeChanged;
+			
+			resourcesChanged();
 		}
 		
 		private function onCreationComplete(e:FlexEvent):void {
@@ -120,6 +128,40 @@ package org.bigbluebutton.modules.caption.views {
 			removeEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
 		}
 		
+		private function localeChanged(e:Event):void{
+			resourcesChanged();
+		}
+		
+		override protected function resourcesChanged():void{
+			super.resourcesChanged();
+			
+			if (inputArea != null) {
+				inputArea.toolTip = ResourceUtil.getInstance().getString('bbb.caption.transcript.inputArea.toolTip');
+			}
+			
+			if (outputArea != null) {
+				outputArea.toolTip = ResourceUtil.getInstance().getString('bbb.caption.transcript.outputArea.toolTip');
+			}
+			
+			if (claimButton != null) {
+				claimButton.label = ResourceUtil.getInstance().getString('bbb.caption.option.takeowner');
+				claimButton.toolTip = ResourceUtil.getInstance().getString('bbb.caption.option.takeowner.tooltip');
+			}
+		}
+		
+		public function delayedFocusTextArea():void {
+			focusSwitchTimer = new Timer(250, 1);
+			focusSwitchTimer.addEventListener(TimerEvent.TIMER, function():void {
+				focusTextArea();
+			});
+			focusSwitchTimer.start();
+		}
+		
+		public function focusTextArea():void {
+			var areaToFocus:TextArea2 = (inputArea.visible ? inputArea : outputArea);
+			areaToFocus.setFocus();
+		}
+		
 		public function setCurrentTranscript(t:Transcript):void {
 			if (transcriptChangeWatcher != null && transcriptChangeWatcher.isWatching()) {
 				transcriptChangeWatcher.unwatch();
@@ -134,9 +176,16 @@ package org.bigbluebutton.modules.caption.views {
 		}
 		
 		public function transcriptOwnerIDChange(ownerID:String):void {
+			//check focus targets before switching visibility
+			var focusedTextArea:TextArea2 = null;
+			
 			if (ownerID == UserManager.getInstance().getConference().getMyUserId()) {
 				claimButton.visible = claimButton.includeInLayout = false;
 				
+				if (focusManager && focusManager.getFocus() == outputArea) {
+					delayedFocusTextArea();
+				}
+				
 				//release text
 				inputArea.visible = inputArea.includeInLayout = true;
 				outputArea.visible = outputArea.includeInLayout = false;
@@ -145,18 +194,15 @@ package org.bigbluebutton.modules.caption.views {
 			} else {
 				claimButton.visible = claimButton.includeInLayout = UserManager.getInstance().getConference().amIModerator();
 				
-				if (ownerID == "") {
-					//unclaimed text
-					inputArea.visible = inputArea.includeInLayout = false;
-					outputArea.visible = outputArea.includeInLayout = true;
-					inputArea.getInternalTextField().type = TextFieldType.DYNAMIC;
-				} else {
-					//claimed by other
-					inputArea.visible = inputArea.includeInLayout = false;
-					outputArea.visible = outputArea.includeInLayout = true;
-					inputArea.getInternalTextField().type = TextFieldType.DYNAMIC;
+				if (focusManager && focusManager.getFocus() == outputArea) {
+					delayedFocusTextArea();
 				}
 				
+				//unclaimed text
+				inputArea.visible = inputArea.includeInLayout = false;
+				outputArea.visible = outputArea.includeInLayout = true;
+				inputArea.getInternalTextField().type = TextFieldType.DYNAMIC;
+				
 				resetOverwriteVars();
 				resetTextToSendVars();
 			}
@@ -189,6 +235,8 @@ package org.bigbluebutton.modules.caption.views {
 		
 		private function onClaimButtonClick(e:MouseEvent):void {
 			claimTranscript(currentTranscript.locale, currentTranscript.localeCode, true);
+			
+			delayedFocusTextArea();
 		}
 		
 		private function claimTranscript(locale:String, localeCode:String, claim:Boolean):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatMessage.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatMessage.as
index 65328c4ba871ecf2d357107896f18f6235500d5f..9f00c500305d3a50cc998d2b38503ea29bc1301b 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatMessage.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatMessage.as
@@ -17,6 +17,7 @@
 *
 */
 package org.bigbluebutton.modules.chat.model {
+	import org.bigbluebutton.util.i18n.ResourceUtil;
 	
 	public class ChatMessage {
 		[Bindable] public var lastSenderId:String;
@@ -42,8 +43,8 @@ package org.bigbluebutton.modules.chat.model {
 		
 		public function toString() : String {
 			var result:String;
-			// Remember to localize this later
-			result = "Chat message " + name + " said " + stripTags(text) + " at " + time;  
+			var accName:String = (!name || name == "" || name == " "? ResourceUtil.getInstance().getString("bbb.chat.chatMessage.systemMessage") : name);
+			result = ResourceUtil.getInstance().getString("bbb.chat.chatMessage.stringRespresentation", [accName, stripTags(text), time]);
 			return result;
 		}
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
index d6c6a4f2138dffe63c77bc0fe79bf71629181b72..fee79c20a2cffdbbb6ab0b8574ddb702f2c2bd17 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
@@ -18,7 +18,13 @@
  */
 package org.bigbluebutton.modules.chat.views
 {
+  import flash.display.CapsStyle;
+  import flash.display.Graphics;
+  import flash.display.JointStyle;
+  import flash.display.Sprite;
+  
   import mx.controls.List;
+  import mx.controls.listClasses.IListItemRenderer;
   
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
@@ -31,7 +37,11 @@ package org.bigbluebutton.modules.chat.views
     {
       super();
     }
-    
+	
+	override protected function drawHighlightIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void {
+		//intentionally empty to not show on hover
+	}
+	
     override protected function measure():void
     {
       super.measure();
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
index 705544162c3ecc45ce8af54b4d8e528f58c25f38..facc384988756afd879c4ceb66b59d02ff680b26 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
@@ -48,12 +48,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   </mx:Style>
   
 	<mate:Listener type="{ChatOptionsEvent.CHANGE_FONT_SIZE}" method="changeFontSize" />
-	<mate:Listener type="{ShortcutEvent.ADVANCE_MESSAGE}" method="advanceMessage" />
-	<mate:Listener type="{ShortcutEvent.GOBACK_MESSAGE}" method="goBackOneMessage" />
-	<mate:Listener type="{ShortcutEvent.REPEAT_MESSAGE}" method="repeatMessage" />
-	<mate:Listener type="{ShortcutEvent.GOLATEST_MESSAGE}" method="goToLatestMessage" />
-	<mate:Listener type="{ShortcutEvent.GOFIRST_MESSAGE}" method="goToFirstMessage" />
-	<mate:Listener type="{ShortcutEvent.GOREAD_MESSAGE}" method="goToLatestReadMessage" />
   <mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
   <mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
   <mate:Listener type="{ShortcutEvent.FOCUS_CHAT_INPUT}" method="focusChatInput" />
@@ -62,7 +56,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <mate:Listener type="{ShortcutEvent.FOCUS_CHAT_BOX}" method="focusChatBox" />
   <mate:Listener type="{ShortcutEvent.CHANGE_FONT_COLOUR}" method="focusColourPicker" />
   <mate:Listener type="{ShortcutEvent.SEND_MESSAGE}" method="remoteSendMessage" />
-  <mate:Listener type="{ShortcutEvent.CHAT_DEBUG}" method="chatDebugInfo" />
   <mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" receive="refreshChat(event)"/>
 	
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
@@ -79,6 +72,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.as3commons.lang.StringUtils;
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
+			import org.bigbluebutton.core.KeyboardUtil;
 			import org.bigbluebutton.core.TimerUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
@@ -106,36 +100,30 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 			private static const LOGGER:ILogger = getClassLogger(ChatBox);      
       
-      public var publicChat:Boolean = false;
-      public var chatWithUserID:String;
-      public var chatWithUsername:String
+			public var publicChat:Boolean = false;
+			public var chatWithUserID:String;
+			public var chatWithUsername:String
       
 			public var read:Boolean = true;
 			public var userHasLeft:Boolean = false;
 			
 			private var globalDispatcher:Dispatcher = new Dispatcher();
-      [Bindable] public var colorPickerColours:Array = ['0x000000', '0x7A7A7A' ,'0xFF0000', '0xFF8800',
-        '0x88FF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF'];
+			[Bindable] public var colorPickerColours:Array = ['0x000000', '0x7A7A7A' ,'0xFF0000', '0xFF8800',
+			'0x88FF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF'];
       
 			[Bindable]
 			private var backgroundColor:uint = 0x000000;
 			private var lastSenderId:String = "";
 			private var lastTime:String = "";
 			
-	    [Bindable]
-	    private var chatMessages:ChatConversation = new ChatConversation();
-      
+			[Bindable]
+			private var chatMessages:ChatConversation = new ChatConversation();
+
 			private var lastCount:Number = 0;			
 			private var scrollTimer:Timer;
 			private var currentMessage:int;
 			private var latestMessage:int; 
 			
-			private var reachedLatest:String = ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatBox.reachedLatest');
-			private var reachedFirst:String = ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatBox.reachedFirst');
-			private var navLatestString:String = ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatBox.navigatedLatest');
-			private var navRecentString:String = ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatBox.navigatedLatestRead');
-			private var navFirstString:String = ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatBox.navigatedFirst');
-			
 			public var focus:Boolean = false;
 			private var keyCombos:Object;
 			
@@ -145,8 +133,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var indicatorNeeded:Boolean = false
 			private var repeat:Boolean = false;
 			
-		      [Bindable]
-		      private var chatListHeight:Number = 100;
+			[Bindable]
+			private var chatListHeight:Number = 100;
 			
 			[Bindable] public var chatOptions:ChatOptions = new ChatOptions();	
       
@@ -161,26 +149,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				currentMessage = -1;
 				latestMessage = -1;
 				
-				this.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);	
-				
 				ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing	
 				
-				hotkeyCapture();
-				
 				// Listen for the ENTER key to send the message.
 				txtMsgArea.addEventListener(TextEvent.TEXT_INPUT, handleTextInput);
 				txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, handleMsgAreaKeyDown);
 				
 				queryForChatHistory();
 				
-				if(chatMessagesList.accessibilityProperties == null)
-					chatMessagesList.accessibilityProperties = new AccessibilityProperties();
-				
 				chatMessagesList.accessibilityProperties.description = ResourceUtil.getInstance().getString('bbb.accessibility.chat.initialDescription');
 				
-				if(Capabilities.hasAccessibility)
-					Accessibility.updateProperties();
-				
 				if (publicChat && UserManager.getInstance().getConference().isBreakout){
 					var timerListener : Listener = new Listener();
 					timerListener.type = BreakoutRoomEvent.UPDATE_REMAINING_TIME_BREAKOUT;
@@ -400,16 +378,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				}
 			}
 			
-			
-			// Determines for navigateMessages() whether the message to be spoken by the screen-reader needs an extra space added to the end or not
-			private function setDescription():Boolean{
-				var chatHistorySpacer:Boolean = false;
-				if (chatMessagesList.accessibilityProperties.description == chatMessages.messages.getItemAt(currentMessage).toString()) {
-		          	chatHistorySpacer = true;
-		        }
-				return chatHistorySpacer;
-			}
-			
 			public function getLatestMessage():int{
 				return latestMessage;
 			}
@@ -420,189 +388,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			private function localeChanged(e:Event):void {
 				var modifier:String = ExternalInterface.call("determineModifier");
-		  		loadKeyCombos(modifier);
 				
 				addContextMenuItems();
 			}
-
-			private function loadKeyCombos(modifier:String):void {
-				keyCombos = new Object(); // always start with a fresh array
-				//keyCombos[modifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.debug') as String)] = ShortcutEvent.CHAT_DEBUG;
-				//keyCombos[modifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.repeat') as String)] = ShortcutEvent.REPEAT_MESSAGE;
-				keyCombos[modifier+(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.goread') as String)] = ShortcutEvent.GOREAD_MESSAGE;
-				// Special cases: Using the arrow keys with no modifiers
-				keyCombos[(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.advance') as String)] = ShortcutEvent.ADVANCE_MESSAGE;
-				keyCombos[(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.goback') as String)] = ShortcutEvent.GOBACK_MESSAGE;
-				keyCombos[(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.golatest') as String)] = ShortcutEvent.GOLATEST_MESSAGE;
-				keyCombos[(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.gofirst') as String)] = ShortcutEvent.GOFIRST_MESSAGE;
-				keyCombos[(ResourceUtil.getInstance().getString('bbb.shortcutkey.chat.chatbox.repeat') as String)] = ShortcutEvent.REPEAT_MESSAGE;
-			}
-			
-			public function hotkeyCapture():void{
-			    this.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
-		    }
-			
-			private function handleKeyDown(e:KeyboardEvent) :void {
-		  		var modifier:String = ExternalInterface.call("determineModifier");
-		  		loadKeyCombos(modifier);
-		  
-		  		var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") + (e.altKey   ? "alt+"     : "") + e.keyCode;
-				
-				if (keyCombos[keyPress]) {
-					LOGGER.debug("WATERFALL: Caught shortcut in chat box, {0}", [keyCombos[keyPress]]);
-					var event:ShortcutEvent = new ShortcutEvent(keyCombos[keyPress]);
-					event.otherUserID = chatWithUserID;
-					globalDispatcher.dispatchEvent(event);
-				}
-		    }
-			      
-			private function advanceMessage(e:ShortcutEvent):void{
-				if (e.otherUserID == chatWithUserID){
-					if (currentMessage < (chatMessages.numMessages() - 1)){
-						currentMessage++;
-					} else {
-						chatMessagesList.accessibilityProperties.description += " ";
-						repeat = true;
-					}
-					navigationMaintenance();
-				}
-			}
-			
-			private function goBackOneMessage(e:ShortcutEvent):void {
-				if (e.otherUserID == chatWithUserID){
-					if (currentMessage > 0){
-						currentMessage--;
-					}
-					else if (currentMessage < 0){
-						currentMessage = 0;
-						latestMessage = 0;
-					}
-					else{
-						chatMessagesList.accessibilityProperties.description += " ";
-						repeat = true;
-					}
-					navigationMaintenance();
-				}
-			}
-			
-			private function repeatMessage(e:ShortcutEvent):void {
-				if (currentMessage < 0){
-					currentMessage = 0;
-					latestMessage = 0;
-					if (chatMessages.messages.length > 0)
-						chatMessagesList.accessibilityProperties.description = chatMessages.messages.getItemAt(currentMessage).toString();
-				}
-				if (e.otherUserID == chatWithUserID){
-					chatMessagesList.accessibilityProperties.description += " ";
-					repeat = true;
-					navigationMaintenance();
-				}
-			}
-			
-			private function goToLatestMessage(e:ShortcutEvent):void {
-				if (latestMessage < 0){
-					currentMessage = 0;
-					latestMessage = 0;
-				}
-				if (e.otherUserID == chatWithUserID){
-					currentMessage = chatMessages.numMessages() - 1;
-					navToLatest = true;
-					spacerNeeded = setDescription();
-					indicatorNeeded = true;
-					chatMessagesList.accessibilityProperties.description = navLatestString + " " + chatMessages.messages.getItemAt(currentMessage).toString();
-					navigationMaintenance();
-				}
-			}
-			
-			private function goToFirstMessage(e:ShortcutEvent):void {
-				if (e.otherUserID == chatWithUserID){
-					currentMessage = 0;
-					navToFirst = true;
-					spacerNeeded = setDescription();
-					indicatorNeeded = true;
-					chatMessagesList.accessibilityProperties.description = navFirstString + " " + chatMessages.messages.getItemAt(currentMessage).toString();
-					navigationMaintenance();
-				}
-			}
-			
-			private function goToLatestReadMessage(e:ShortcutEvent):void {
-				if (e.otherUserID == chatWithUserID){
-					if (latestMessage < 0) {
-						latestMessage = 0;
-					}
-					currentMessage = latestMessage;
-					chatMessagesList.accessibilityProperties.description = navRecentString + " " + chatMessages.messages.getItemAt(currentMessage).toString();
-					navigationMaintenance();
-				}
-			}
-			
-			private function navigationMaintenance():void {
-				// Update the latestMessage counter for new message notifications
-				if (currentMessage > latestMessage)
-					latestMessage = currentMessage;
-					
-				if (!repeat){
-				// Make it clear to the user that they have either navigated to or reached one end of the message history or the other.
-					if (currentMessage == 0){
-						if (!navToFirst){
-							indicatorNeeded = true;
-							chatMessagesList.accessibilityProperties.description = reachedFirst + " " + chatMessages.messages.getItemAt(currentMessage).toString();
-						}
-					}
-					else if (currentMessage == chatMessages.numMessages() - 1){
-						if (!navToLatest){
-							indicatorNeeded = true;
-							chatMessagesList.accessibilityProperties.description = reachedLatest + " " + chatMessages.messages.getItemAt(currentMessage).toString();			
-						}
-					}
-					else{
-						// Set the accessibility description to the indicated message
-						chatMessagesList.accessibilityProperties.description = chatMessages.messages.getItemAt(currentMessage).toString();
-					}
-					
-					// Add a single space to the end of the accessibilityProperties.description if necessary to ensure that it reflects the current message after being updated.
-					if (spacerNeeded || setDescription()){
-						chatMessagesList.accessibilityProperties.description += " ";
-					}
-				}
-				if(Capabilities.hasAccessibility)
-					Accessibility.updateProperties();
-				navToFirst = false;
-				navToLatest = false;
-				spacerNeeded = false;
-				indicatorNeeded = false
-				repeat = false;
-				LOGGER.debug("Done with navigationMaintenance(); description is now {0}", [chatMessagesList.accessibilityProperties.description]);
-			}
-			
-			// General-purpose developer method, used during testing of ChatBox accessibility
-			private function chatDebugInfo(e:ShortcutEvent):void{
-				LOGGER.debug("----CHAT DEBUG INFORMATION----");
-					var num:int = chatMessages.numMessages();
-					LOGGER.debug("Printing all chat messages of the {0} present:", [num]);
-					for (var i:int = 0; i < num; i++){
-						if (chatMessages.messages.getItemAt(i) != null)
-							LOGGER.debug("Message {0}: {1}", [i, chatMessages.messages.getItemAt(i).toString()]);
-						else
-							LOGGER.debug("Message {0} is NULL", [i]);
-					}
-					
-					/*
-					LogUtil.debug("chatWithUserID is: " + chatWithUserID);
-					LogUtil.debug("currentMessage is: " + currentMessage);
-					LogUtil.debug("latestMessage is: " + latestMessage);
-					LogUtil.debug("Focused message is: " + chatMessages.messages.getItemAt(currentMessage).toString());
-					LogUtil.debug("Number of messages is: " + chatMessages.messages.length);
-					LogUtil.debug("chatMessagesList.accessibilityProperties.description is: " + chatMessagesList.accessibilityProperties.description);
-					*/
-					//LogUtil.debug("repeat is: " + repeat);
-					//LogUtil.debug("navToFirst is: " + navToFirst);
-					//LogUtil.debug("indicatorNeeded is: " + indicatorNeeded);
-					//LogUtil.debug("navToLatest is: " + navToLatest);
-					//LogUtil.debug(" is: " + ); 
-				
-				LOGGER.debug("------------------------------");
-			}
      
       private function sendStartCustomPollEvent(answers:Array):void {
         var dispatcher:Dispatcher = new Dispatcher();
@@ -775,9 +563,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<common:TabIndexer id="tabIndexer" tabIndices="{[chatMessagesList, txtMsgArea, sendBtn, cmpColorPicker]}"/>
 
 	<mx:VBox width="100%" height="{chatListHeight}" verticalScrollPolicy="off">
-		<chat:AdvancedList width="100%" height="{chatListHeight - timerBox.height}" id="chatMessagesList" selectable="false" variableRowHeight="true" 
+		<chat:AdvancedList width="100%" height="{chatListHeight - timerBox.height}" id="chatMessagesList" selectable="true" variableRowHeight="true" 
 						   itemRenderer="org.bigbluebutton.modules.chat.views.ChatMessageRenderer" verticalScrollPolicy="on" horizontalScrollPolicy="off" wordWrap="true"
 						   dataProvider="{chatMessages.messages}"
+						   styleName="chatMessageListStyle"
 						   accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.messageList')}" />
 		<mx:HBox id="timerBox" styleName="breakoutRoomTimerBox"
 				 includeInLayout="false" visible="false"
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
index 4be28c107ce20ca33f36e8f0da72e38f30e0ebeb..c069e69268fc26d7baebec27d9a93cca1c6ced67 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
@@ -43,6 +43,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import org.bigbluebutton.common.IBbbModuleWindow;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
+			import org.bigbluebutton.core.KeyboardUtil;
 			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.modules.chat.model.ChatOptions;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -97,8 +98,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		    private function handleKeyDown(e:KeyboardEvent) :void {
 		      var modifier:String = ExternalInterface.call("determineModifier");
 			  loadKeyCombos(modifier);			  
-			  var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") +
-		                            (e.altKey   ? "alt+"     : "") + e.keyCode;		                              
+			  var keyPress:String = KeyboardUtil.buildPressedKeys(e);
 		      if (keyCombos[keyPress]) {
 		        disp.dispatchEvent(new ShortcutEvent(keyCombos[keyPress]));
 		      }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
index b775cee7d301a711a64f8197142d00f6e9b05c6b..08b3a9b3d4f9666ed5e1f73e2ee1149b5bb5d146 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
@@ -18,27 +18,29 @@ You should have received a copy of the GNU Lesser General Public License along
 with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 -->
-<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" 
-			xmlns:mate="http://mate.asfusion.com/"
-			toolTip="{ResourceUtil.getInstance().getString('bbb.layout.combo.toolTip')}"
-			prompt="{ResourceUtil.getInstance().getString('bbb.layout.combo.prompt')}"
-			height="{LayoutButton.BUTTON_SIZE}" creationComplete="init()"
-			disabledColor="{getStyle('color')}" rowCount="10"
-			styleName="languageSelectorStyle" >
-	
+<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
+             xmlns:mate="http://mate.asfusion.com/"
+             toolTip="{ResourceUtil.getInstance().getString('bbb.layout.combo.toolTip')}"
+             prompt="{ResourceUtil.getInstance().getString('bbb.layout.combo.prompt')}"
+             height="{LayoutButton.BUTTON_SIZE}"
+             creationComplete="init()"
+             disabledColor="{getStyle('color')}"
+             rowCount="10"
+             styleName="languageSelectorStyle">
+
 	<mate:Listener type="{SwitchedLayoutEvent.SWITCHED_LAYOUT_EVENT}" method="onLayoutChanged" />
 	<mate:Listener type="{LayoutsReadyEvent.LAYOUTS_READY}" method="populateLayoutsList"/>
-  <mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
+	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
 	<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
   
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
-			
+
 			import mx.collections.ArrayCollection;
 			import mx.events.DropdownEvent;
 			import mx.events.ListEvent;
-			
+
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
@@ -51,87 +53,92 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.modules.layout.events.LayoutsReadyEvent;
 			import org.bigbluebutton.modules.layout.model.LayoutModel;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
-			
-			private static const LOGGER:ILogger = getClassLogger(LayoutsCombo);      
-      
-			private var _dispatcher:Dispatcher = new Dispatcher();
-      [Bindable] private var layoutNames:ArrayCollection = new ArrayCollection();
-      
-      private function init():void {
-        //trace(LOG + "initing");
-        dataProvider = layoutNames;
-        populateComboBox();
-        this.addEventListener(DropdownEvent.OPEN, openDropdownHandler);
-      }
-      
-      private function lockSettingsChanged(e:LockControlEvent):void {
-		  var conference:Conference = UserManager.getInstance().getConference();
-		  var thisUser:BBBUser = conference.getMyUser();
-		  this.enabled = ! thisUser.lockedLayout;
-      }
-      
-			private function populateLayoutsList(e:LayoutsReadyEvent):void {
-        //trace(LOG + " handling layout ready event.");       
-        populateComboBox();
-			}
-      
-      private function populateComboBox():void {
-        //trace(LOG + " populating layout combo.");  
-        layoutNames = new ArrayCollection();         
-        var layouts:Array = LayoutModel.getInstance().getLayoutNames();
-        
-        var idx:int = 0, currentLayoutIndex:int = -1;
-        for each (var lay:Object in layouts) {
-          var translatedName:String = ResourceUtil.getInstance().getString(lay.name)
-          if (translatedName == "undefined") translatedName = lay.name;
-          var item:Object = {index: idx, label: translatedName, localeKey: lay.name, currentLayout: lay.currentLayout };
-          //trace(LOG + " layout [" + lay.name + ", current=" + lay.currentLayout + "]");
-          layoutNames.addItem(item);
-          if (lay.currentLayout) {
-            currentLayoutIndex = idx;
-          }
-          idx++;
-        }
-        dataProvider = layoutNames;
-        selectedIndex = currentLayoutIndex;
-        invalidateDisplayList();        
-      }
-						
-			private function onLayoutChanged(e:SwitchedLayoutEvent):void {
-				lockSettingsChanged(null);
-        //trace(LOG + " handling SwitchedLayoutEvent layout=[" + e.layoutID + "]");
-        populateComboBox();
-        //trace(LOG + " selected layout coming in is: " + selectedIndex);
-				var idx:int = -1;					
-				for each (var obj:Object in dataProvider) {
-					if (obj.localeKey == e.layoutID)
-						idx = obj.index;
-				}
-				selectedIndex = idx;
-				if (idx == -1) {
-					prompt = e.layoutID;
-				} else {
-					prompt = ResourceUtil.getInstance().getString('bbb.layout.combo.prompt');
-				}
-				invalidateDisplayList();
-				
-				//trace(LOG + " selected layout afterwards is: " + selectedIndex);
-			}
+
+			private static const LOGGER:ILogger = getClassLogger(LayoutsCombo);
+
+            private var _dispatcher:Dispatcher = new Dispatcher();
+
+            [Bindable]
+            private var layoutNames:ArrayCollection = new ArrayCollection();
+
+            private function init():void {
+                dataProvider = layoutNames;
+                populateComboBox();
+                this.addEventListener(DropdownEvent.OPEN, openDropdownHandler);
+                this.addEventListener(KeyboardEvent.KEY_UP, keyboardUpHandler);
+            }
+
+            private function lockSettingsChanged(e:LockControlEvent):void {
+                var conference:Conference = UserManager.getInstance().getConference();
+                var thisUser:BBBUser = conference.getMyUser();
+                this.enabled = !thisUser.lockedLayout;
+            }
+
+            private function populateLayoutsList(e:LayoutsReadyEvent):void {
+                populateComboBox();
+            }
+
+            private function populateComboBox():void {
+                layoutNames = new ArrayCollection();
+                var layouts:Array = LayoutModel.getInstance().getLayoutNames();
+
+                var idx:int = 0, currentLayoutIndex:int = -1;
+                for each (var lay:Object in layouts) {
+                    var translatedName:String = ResourceUtil.getInstance().getString(lay.name)
+                    if (translatedName == "undefined")
+                        translatedName = lay.name;
+                    var item:Object = {index: idx, label: translatedName, localeKey: lay.name, currentLayout: lay.currentLayout};
+                    layoutNames.addItem(item);
+                    if (lay.currentLayout) {
+                        currentLayoutIndex = idx;
+                    }
+                    idx++;
+                }
+                dataProvider = layoutNames;
+                selectedIndex = currentLayoutIndex;
+                invalidateDisplayList();
+            }
+
+            private function onLayoutChanged(e:SwitchedLayoutEvent):void {
+                lockSettingsChanged(null);
+                populateComboBox();
+                var idx:int = -1;
+                for each (var obj:Object in dataProvider) {
+                    if (obj.localeKey == e.layoutID)
+                        idx = obj.index;
+                }
+                selectedIndex = idx;
+                if (idx == -1) {
+                    prompt = e.layoutID;
+                } else {
+                    prompt = ResourceUtil.getInstance().getString('bbb.layout.combo.prompt');
+                }
+                invalidateDisplayList();
+            }
 			
 			private function localeChanged(e:LocaleChangeEvent):void {
-				//trace(LOG + " locale change recieved");
 				populateComboBox();
 			}
-			
-			private function openDropdownHandler(e:DropdownEvent):void {
-				// a new dropdown object is created everytime the menu is opened
-				this.dropdown.addEventListener(ListEvent.ITEM_CLICK, itemClickHandler);
-			}
-			
-			private function itemClickHandler(e:ListEvent):void {
-				_dispatcher.dispatchEvent(new ChangeLayoutEvent(e.currentTarget.selectedItem.localeKey));
-			}
-					
+            private function openDropdownHandler(e:DropdownEvent):void {
+                // a new dropdown object is created everytime the menu is opened
+                this.dropdown.addEventListener(ListEvent.ITEM_CLICK, itemSelectHandler);
+            }
+
+            private function keyboardUpHandler(e:KeyboardEvent):void {
+                if (e.keyCode == Keyboard.ENTER || e.keyCode == Keyboard.SPACE) {
+                    setNewLayout(this.selectedItem.localeKey);
+                }
+            }
+
+            private function itemSelectHandler(e:ListEvent):void {
+                this.dropdown.removeEventListener(ListEvent.ITEM_CLICK, itemSelectHandler);
+                setNewLayout(e.currentTarget.selectedItem.localeKey);
+            }
+
+            private function setNewLayout(layout:String):void {
+                _dispatcher.dispatchEvent(new ChangeLayoutEvent(layout));
+            }
+
 		]]>
 	</mx:Script>
 </mx:ComboBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollChoicesModal.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollChoicesModal.mxml
old mode 100755
new mode 100644
index 1fc81ff939c8c970b69d400dcf6de5f6d2454f09..ac09347c03254fe6af69a2ed68e00a476a764b8e
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollChoicesModal.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollChoicesModal.mxml
@@ -27,14 +27,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import mx.managers.PopUpManager;
-			
 			import org.as3commons.lang.ArrayUtils;
 			import org.as3commons.lang.StringUtils;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.modules.polling.events.StartCustomPollEvent;
 			import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
-			
+
 			private var _presentationWindow : PresentationWindow;
 			
 			public function setPresentationWindow(window:PresentationWindow):void {
@@ -47,7 +46,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					_presentationWindow.slideView.onZoomSlide(100);
 					var dispatcher:Dispatcher = new Dispatcher();
 					dispatchEvent(new StartCustomPollEvent("Custom", answers));
-					PopUpManager.removePopUp(this);
+					PopUpUtil.removePopUp(this);
 				}
 			}
 			
@@ -83,7 +82,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mx:HBox width="100%" horizontalGap="10" horizontalAlign="right">
 		<mx:Button id="publishButton" click="publishButton_clickHandler(event)"
 				   label="{ResourceUtil.getInstance().getString('bbb.polling.startButton.label')}"/>
-		<mx:Button id="closeButton" click="PopUpManager.removePopUp(this)"
+		<mx:Button id="closeButton" click="PopUpUtil.removePopUp(this)"
 				   label="{ResourceUtil.getInstance().getString('bbb.polling.closeButton.label')}"/>
 	</mx:HBox>
 	
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollResultsModal.as b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollResultsModal.as
old mode 100755
new mode 100644
index b18ba6a137edc7aca6298098540c9a86deee270f..0a1e8509311af06104d83b5c49cd4366b5b7641a
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollResultsModal.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/PollResultsModal.as
@@ -14,8 +14,8 @@ package org.bigbluebutton.modules.polling.views
 	import mx.controls.Label;
 	import mx.controls.TextArea;
 	import mx.core.ScrollPolicy;
-	import mx.managers.PopUpManager;
 	
+	import org.bigbluebutton.core.PopUpUtil;
 	import org.bigbluebutton.modules.polling.events.PollStoppedEvent;
 	import org.bigbluebutton.modules.polling.events.PollVotedEvent;
 	import org.bigbluebutton.modules.polling.events.ShowPollResultEvent;
@@ -193,7 +193,7 @@ package org.bigbluebutton.modules.polling.views
 			_stopPollListener.method = null;
 			_stopPollListener = null;
 			
-			PopUpManager.removePopUp(this);
+			PopUpUtil.removePopUp(this);
 		}
 		
 		private function dotAnimate(e:TimerEvent):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
old mode 100755
new mode 100644
index 31d1645957e3941dace2629ba09d1eb80741d26c..c7fad768e6a93e433b9087583a88f562d7f66fec
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
@@ -24,10 +24,10 @@ package org.bigbluebutton.modules.present.managers
 	import flash.geom.Point;
 	
 	import mx.core.FlexGlobals;
-	import mx.managers.PopUpManager;
 	
 	import org.bigbluebutton.common.IBbbModuleWindow;
 	import org.bigbluebutton.common.events.OpenWindowEvent;
+	import org.bigbluebutton.core.PopUpUtil;
 	import org.bigbluebutton.modules.present.events.PresentModuleEvent;
 	import org.bigbluebutton.modules.present.events.UploadEvent;
 	import org.bigbluebutton.modules.present.ui.views.FileUploadWindow;
@@ -36,7 +36,6 @@ package org.bigbluebutton.modules.present.managers
 	public class PresentManager
 	{
 		private var globalDispatcher:Dispatcher;
-		private var uploadWindow:FileUploadWindow;
 		private var presentWindow:PresentationWindow;
 		
 		public function PresentManager() {
@@ -62,24 +61,23 @@ package org.bigbluebutton.modules.present.managers
 			event.window = window;
 			globalDispatcher.dispatchEvent(event);
 		}
-	
-		public function handleOpenUploadWindow(e:UploadEvent):void{
-			if (uploadWindow != null) return;
 
-			uploadWindow = FileUploadWindow(PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, FileUploadWindow, true));
-			uploadWindow.maxFileSize = e.maxFileSize;
-			
-			var point1:Point = new Point();
-			point1.x = FlexGlobals.topLevelApplication.width / 2;
-			point1.y = FlexGlobals.topLevelApplication.height / 2;  
-			
-			uploadWindow.x = point1.x - (uploadWindow.width/2);
-			uploadWindow.y = point1.y - (uploadWindow.height/2);
+		public function handleOpenUploadWindow(e:UploadEvent):void{
+			var uploadWindow : FileUploadWindow = PopUpUtil.createModalPopUp(FlexGlobals.topLevelApplication as DisplayObject, FileUploadWindow, false) as FileUploadWindow;
+			if (uploadWindow) {
+				uploadWindow.maxFileSize = e.maxFileSize;
+				
+				var point1:Point = new Point();
+				point1.x = FlexGlobals.topLevelApplication.width / 2;
+				point1.y = FlexGlobals.topLevelApplication.height / 2;  
+				
+				uploadWindow.x = point1.x - (uploadWindow.width/2);
+				uploadWindow.y = point1.y - (uploadWindow.height/2);
+			}
 		}
 		
 		public function handleCloseUploadWindow():void{
-			PopUpManager.removePopUp(uploadWindow);
-			uploadWindow = null;
+			PopUpUtil.removePopUp(FileUploadWindow);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
old mode 100755
new mode 100644
index 990a666584178b4a3fe67fe7ffd6d6cf8ed94aca..68d7c133b2f1d800fb8880f76de40dfe1749420d
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
@@ -20,10 +20,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 -->
 
-<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" 
-	xmlns:mate="http://mate.asfusion.com/"
-	 layout="absolute" width="580" height="410" styleName="presentationFileUploadWindowStyle"
-      initialize="initData();">
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+                xmlns:mate="http://mate.asfusion.com/"
+                layout="absolute"
+                width="580"
+                height="410"
+				verticalScrollPolicy="off"
+				horizontalScrollPolicy="off"
+                styleName="presentationFileUploadWindowStyle"
+                initialize="initData();">
 
     <mate:Dispatcher id="globalDispatch" />
     <mate:Listener type="{UploadProgressEvent.UPLOAD_PROGRESS_UPDATE}" method="handleUploadProgressUpdate" />
@@ -308,9 +313,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <mx:TextArea borderSkin="{null}"
 				 text="{ResourceUtil.getInstance().getString('bbb.fileupload.title')}"
                  editable="false" styleName="presentationUploadTitleStyle"
-                 width="400" left="0"/>
-    <mx:HBox id="fileUploadBox" width="100%" paddingLeft="5" paddingTop="0" verticalAlign="middle"> 
-      <mx:Label id="lblFileName" width="{fileUploadBox.width-selectBtn.width-uploadBtn.width-30}" selectable="false" click="selectFile()" text="{ResourceUtil.getInstance().getString('bbb.fileupload.lblFileName.defaultText')}" />
+                 width="100%"/>
+    <mx:HBox id="fileUploadBox" width="100%" paddingLeft="5" paddingRight="5" paddingTop="0" verticalAlign="middle"> 
+      <mx:Label id="lblFileName" truncateToFit="true" width="{fileUploadBox.width-selectBtn.width-uploadBtn.width-30}" selectable="false" click="selectFile()" text="{ResourceUtil.getInstance().getString('bbb.fileupload.lblFileName.defaultText')}" />
 	  <mx:Button id="selectBtn" label="{ResourceUtil.getInstance().getString('bbb.fileupload.selectBtn.label')}" 
 				   toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.selectBtn.toolTip')}" 
 				   click="selectFile()" styleName="presentationUploadChooseFileButtonStyle"/>
@@ -318,11 +323,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                  toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.uploadBtn.toolTip')}"  click="startUpload()"
                  enabled="false" icon="{bulletGoIcon}"/>
     </mx:HBox>
-    <mx:HBox id="progressReportBox" width="100%" paddingLeft="10" paddingTop="5" paddingBottom="10" includeInLayout="true" visible="false">
+    <mx:HBox id="progressReportBox" width="100%" paddingLeft="10" paddingRight="10" paddingTop="5" paddingBottom="10" includeInLayout="true" visible="false">
       <mx:Label id="progBarLbl" text="{ResourceUtil.getInstance().getString('bbb.fileupload.progBarLbl')}" 
                 styleName="presentationUploadProgressBarLabelStyle" visible="false"/>
       <mx:ProgressBar id="progressBar" mode="manual" label="{ResourceUtil.getInstance().getString('bbb.fileupload.progBarLbl')}"
-                      styleName="presentationUploadProgressBarStyle" labelPlacement="center" width="460" visible="false"/>
+                      styleName="presentationUploadProgressBarStyle" labelPlacement="center" width="100%" visible="false"/>
     </mx:HBox>
 	<mx:Box width="100%" height="100%" paddingLeft="5" paddingRight="5">
 		<mx:Box width="100%" height="100%" verticalAlign="middle" horizontalAlign="center" styleName="presentationUploadFileFormatHintBoxStyle">
@@ -330,7 +335,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		</mx:Box>
     </mx:Box>
     <mx:Canvas width="100%" height="145" verticalScrollPolicy="off">
-      <mx:List width="100%" height="142" left="5" top="5" right="5" bottom="5" id="uploadedFilesList" alternatingItemColors="[#EFEFEF, #FEFEFE]" allowMultipleSelection="false"
+      <mx:List height="142" left="5" top="5" right="5" bottom="5" id="uploadedFilesList" alternatingItemColors="[#EFEFEF, #FEFEFE]" allowMultipleSelection="false"
                itemRenderer="org.bigbluebutton.modules.present.ui.views.UploadedPresentationRenderer"
                dragEnabled="false" dataProvider="{presentationNamesAC}">
       </mx:List>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/GotoPageDialog.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/GotoPageDialog.mxml
deleted file mode 100755
index fbf635d6ec958da3b1afcc0c3a1891fd5962cc23..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/GotoPageDialog.mxml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?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/>.
-
--->
-
-<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" 
-				width="195" height="70" 
-				layout="horizontal" 
-				creationComplete="onCreationComplete()" 
-				keyDown="onKeyDown(event)">
-	<mx:Script>
-		<![CDATA[
-			import mx.managers.PopUpManager;
-			
-			import org.bigbluebutton.modules.present.events.PresenterCommands;
-			
-			public static const SWITCH_PAGE:String = "switch to page";
-			[Bindable] public var totalSlides:int;
-			public var window:PresentationWindow;
-			
-			private function closeDialog():void{
-				if( !isNaN( Number( txtPageNum.text ) ) ){
-					var page:Number = parseInt(txtPageNum.text);
-					if( page > 0 && page <= totalSlides ){
-						dispatchEvent(new PresenterCommands(PresenterCommands.GOTO_SLIDE, page));
-					}
-				}
-				PopUpManager.removePopUp(this);
-				
-			}
-			
-			private function onCreationComplete():void{
-				txtPageNum.setFocus();
-			}
-			
-			private function onKeyDown(e:KeyboardEvent):void{
-				if (e.keyCode == Keyboard.ENTER){
-					closeDialog();
-				}
-			}
-		]]>
-	</mx:Script>
-	
-	<mx:Label text="Page" />
-	<mx:TextInput id="txtPageNum" width="25" />
-	<mx:Label id="totalPages" text="{'/' + totalSlides}" />
-	<mx:Button id="okButton" click="closeDialog()" label="Ok" />
-	
-</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
index 5e404e53902fdc4f446f6dac28789a73b237f41d..7a61d2bf89a9e15479a270c728c53fd8832ccf6e 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
@@ -71,7 +71,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import mx.controls.Menu;
 			import mx.events.MenuEvent;
-			import mx.events.ResizeEvent;
 			import mx.managers.PopUpManager;
 			
 			import flexlib.mdi.events.MDIWindowEvent;
@@ -81,6 +80,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.common.IBbbModuleWindow;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.KeyboardUtil;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.main.events.MadePresenterEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
@@ -107,13 +108,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
              		
 			private static const LOGGER:ILogger = getClassLogger(PresentationWindow);      
       
-      public static const TITLE:String = "Presentation";
+      		public static const TITLE:String = "Presentation";
 			private static const GOTO_PAGE_BUTTON:String = "Go to Page...";
 			
 			[Bindable] 
-      private var thumbY:Number;
+      		private var thumbY:Number;
 			public var uploadWindow:FileUploadWindow = null;
-			private var pageDialog:GotoPageDialog;
 			
 			[Bindable] private var DEFAULT_X_POSITION:Number = 237;
 			[Bindable] private var DEFAULT_Y_POSITION:Number = 0;
@@ -142,9 +142,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var pollMenuData:Array;
 			private var pollMenu:Menu;
 			
-			private var pollResultsPopUp:PollResultsModal
-			private var pollChoicesPopUp:PollChoicesModal
-			
 			[Embed(source="../../../polling/sounds/Poll.mp3")] 
 			private var noticeSoundClass:Class;
 			private var noticeSound:Sound = new noticeSoundClass() as Sound;
@@ -225,7 +222,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				var modifier:String = ExternalInterface.call("determineModifier");
 				loadKeyCombos(modifier);
 				  
-				var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") + (e.altKey   ? "alt+"     : "") + e.keyCode;
+				var keyPress:String = KeyboardUtil.buildPressedKeys(e);
 				                          
 				if (keyCombos[keyPress]) {
 				    //globalDispatcher.dispatchEvent(new ShortcutEvent(keyCombos[keyPress]));
@@ -639,15 +636,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				pollMenu.show();
 
 			}
-			
-			private function sendStartCustomPollEvent(pollType:String):void {
-				// Let's reset the page to display full size so we can display the result
-				// on the bottom right-corner.
-				pollChoicesPopUp = PopUpManager.createPopUp(this, PollChoicesModal, true) as PollChoicesModal;
-				pollChoicesPopUp.setPresentationWindow(this);
-				PopUpManager.centerPopUp(pollChoicesPopUp);
-			}
-			
+
+            private function sendStartCustomPollEvent(pollType:String):void {
+                // Let's reset the page to display full size so we can display the result
+                // on the bottom right-corner.
+                var pollChoicesPopUp:PollChoicesModal = PopUpUtil.createModalPopUp(this, PollChoicesModal, true) as PollChoicesModal;
+                if (pollChoicesPopUp) {
+                    pollChoicesPopUp.setPresentationWindow(this);
+                }
+            }
+
 			private function sendStartPollEvent(pollType:String):void {
 				// Let's reset the page to display full size so we can display the result
 				// on the bottom right-corner.
@@ -703,9 +701,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				// the event for this doesn't exist yet
 				if (UsersUtil.amIPresenter()) {
 					// display the results view
-					pollResultsPopUp = PopUpManager.createPopUp(this, PollResultsModal, true) as PollResultsModal;
-					pollResultsPopUp.setPoll(e.poll);
-					PopUpManager.centerPopUp(pollResultsPopUp);
+					var pollResultsPopUp : PollResultsModal = PopUpUtil.createModalPopUp(this, PollResultsModal, true) as PollResultsModal;
+					if (pollResultsPopUp) {
+						pollResultsPopUp.setPoll(e.poll);
+					}
 				} else {
 					//switch to vote state
 					setControlBarState("vote");
@@ -769,7 +768,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			private function pollStoppedHandler(e:PollStoppedEvent):void {
 				setControlBarState("presenter");
-				PopUpManager.removePopUp(pollResultsPopUp);
+				PopUpUtil.removePopUp(PollResultsModal);
 			}
 			
 			private function pollShowResultHandler(e:PollShowResultEvent):void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
index af93712d3a4a445da1002feffd9bcb7a2e953f28..97f5424eb859a9575ed8a3cc6f99935f28197e91 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
@@ -50,11 +50,11 @@ package org.bigbluebutton.modules.screenshare.managers {
             if (shareWindow != null) shareWindow.stopSharing();
         }
         
-        public function startSharing(uri:String, room:String):void {
+        public function startSharing(uri:String, room:String, tunnel:Boolean):void {
             LOGGER.debug("DS:PublishWindowManager::opening desk share window");
             if (shareWindow == null) {
               shareWindow = new ScreensharePublishWindow();
-              shareWindow.initWindow(service.getConnection(), uri, room);
+              shareWindow.initWindow(service.getConnection(), uri, room, tunnel);
               shareWindow.visible = true;
               openWindow(shareWindow);
             }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
index de6bd81eb4342a99b3877c44be5c08c24debe850..e9084d4dae7e9d5a83839030f74f3f53a2b383ee 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
@@ -152,13 +152,13 @@ package org.bigbluebutton.modules.screenshare.managers {
 
             if (option.tryWebRTCFirst && !BrowserCheck.isWebRTCSupported()) {
               usingJava = true;
-              publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom());
+              publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), module.tunnel());
               sharing = true;
               service.requestShareToken();
             } else {
               sharing = true;
               usingJava = false;
-              publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom());
+              publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), module.tunnel());
               service.requestShareToken();
             }
         }
@@ -204,7 +204,7 @@ package org.bigbluebutton.modules.screenshare.managers {
             toolbarButtonManager.startedSharing();
             var option:ScreenshareOptions = new ScreenshareOptions();
             option.parseOptions();
-            publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom());
+            publishWindowManager.startSharing(module.getCaptureServerUri(), module.getRoom(), module.tunnel());
             sharing = true;
         }
         
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
index 995c0212d9887b5812f299676d957346f65ede1e..f5f7ad77be9c91524ac4d75f1abc6200864fd97d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
@@ -25,6 +25,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   implements="org.bigbluebutton.common.IBbbModuleWindow"
   xmlns:mate="http://mate.asfusion.com/"
   xmlns:dspub="flexlib.mdi.containers.*"
+  xmlns:common="org.bigbluebutton.common.*"
   backgroundColor="#C0C0C0"
   initialize="init()"
   creationComplete="onCreationComplete()"	
@@ -49,13 +50,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <![CDATA[
       import com.asfusion.mate.events.Dispatcher;
       
-      import mx.core.UIComponent;
-      
       import org.as3commons.logging.api.ILogger;
       import org.as3commons.logging.api.getClassLogger;
       import org.bigbluebutton.common.Images;
       import org.bigbluebutton.common.events.LocaleChangeEvent;
-      import org.bigbluebutton.core.BBB;
       import org.bigbluebutton.core.UsersUtil;
       import org.bigbluebutton.core.managers.ReconnectionManager;
       import org.bigbluebutton.main.events.BBBEvent;
@@ -66,8 +64,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       import org.bigbluebutton.modules.screenshare.events.RequestToRestartSharing;
       import org.bigbluebutton.modules.screenshare.events.RequestToStopSharing;
       import org.bigbluebutton.modules.screenshare.events.ScreenSharePausedEvent;
-      import org.bigbluebutton.modules.screenshare.events.ShareStoppedEvent;
       import org.bigbluebutton.modules.screenshare.events.ShareStartEvent;
+      import org.bigbluebutton.modules.screenshare.events.ShareStoppedEvent;
       import org.bigbluebutton.modules.screenshare.events.ShareWindowEvent;
       import org.bigbluebutton.modules.screenshare.events.StartShareRequestSuccessEvent;
       import org.bigbluebutton.modules.screenshare.events.StopSharingButtonEvent;
@@ -89,6 +87,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       private var connection:Connection;
       private var uri:String;
       private var room:String;
+      private var tunnel:Boolean = false;
       private var sharingFullScreen:Boolean = false;
       private var streaming:Boolean = false;
       
@@ -134,14 +133,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         
         windowControls.maximizeRestoreBtn.enabled = false;
         
-        titleBarOverlay.tabIndex = baseIndex;
+        titleBarOverlay.tabIndex = dsOptions.baseTabIndex;
         titleBarOverlay.focusEnabled = true;
         
-        minimizeBtn.tabIndex = baseIndex+1;
-        maximizeRestoreBtn.tabIndex = baseIndex+2;
-        closeBtn.tabIndex = baseIndex+3;
-        
         resourcesChanged();
+		
+		focusManager.setFocus(titleBarOverlay);
+		
+		if (tunnel) {
+			helpInfoBox.visible = helpInfoBox.includeInLayout = false;
+			previewBox.visible = previewBox.includeInLayout = false;
+			tunnelBox.visible = tunnelBox.includeInLayout = true;
+			
+			shareTypeBox.visible = false;
+			cancelBtn.visible = cancelBtn.includeInLayout = true;
+			startBtn.visible = startBtn.includeInLayout = false;
+			stopBtn.visible = stopBtn.includeInLayout = false;
+		}
       }
       
       private function remoteFocus(e:ShortcutEvent):void{
@@ -179,10 +187,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       */
       public function resetWidthAndHeight():void{/* do nothing */}
       
-      public function initWindow(connection:Connection, uri:String, room:String):void {
+      public function initWindow(connection:Connection, uri:String, room:String, tunnel:Boolean):void {
         this.connection = connection;
         this.uri = uri;
         this.room = room;
+		this.tunnel = tunnel;
       }
       
       private function handleStartShareRequestSuccessEvent(event:StartShareRequestSuccessEvent):void {
@@ -521,7 +530,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       private function switchView(showHelp:Boolean):void {
         helpInfoBox.visible = helpInfoBox.includeInLayout = showHelp;
         previewBox.visible = !showHelp;
-        
+		
         shareTypeBox.visible = showHelp;
         cancelBtn.visible = cancelBtn.includeInLayout = showHelp;
         startBtn.visible = startBtn.includeInLayout = showHelp;
@@ -530,6 +539,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     ]]>
   </mx:Script>
   
+	<common:TabIndexer id="tabIndexer" startIndex="{dsOptions.baseTabIndex + 1}"
+					   tabIndices="{[minimizeBtn, maximizeRestoreBtn, closeBtn, helpButton, shareTypeCombo, startBtn, cancelBtn, stopBtn, pauseBtn, restartBtn]}"/>
+	
   <!--http://stackoverflow.com/questions/369120/why-does-mxstates-have-trouble-being-resolved-to-a-component-implementation-->
   <mx:Box id="publishView" height="100%" width="100%" styleName="desktopShareViewStyle">
     <mx:VBox id="helpInfoBox" width="100%" height="100%" verticalAlign="middle" verticalGap="12">
@@ -542,8 +554,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                        styleName="micSettingsWindowHelpButtonStyle"
                        right="0"
                        click="onHelpButtonClicked()"
-                       toolTip="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpbutton.toolTip')}"
-                       accessibilityName="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpbutton.accessibilityName')}"/>
+                       toolTip="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpButton.toolTip')}"
+                       accessibilityName="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpButton.accessibilityName')}"/>
       </mx:HBox>
       <mx:HBox id="helpBox" width="100%" horizontalAlign="center">
         <mx:VBox width="30%" horizontalAlign="center">
@@ -568,7 +580,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       <mx:Box id="videoHolder" width="100%" height="90%" horizontalAlign="center">
         <mx:UIComponent id="videoWrapper" width="100%" height="100%" />
         <mx:VBox id="pauseBox" visible="false" includeInLayout="false" styleName="desksharePublishPauseBox" >
-          <mx:Label width="100%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.pauseMessage.label')}" />
+          <mx:Text width="100%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.pauseMessage.label')}" />
         </mx:VBox>
 	  </mx:Box>
       <mx:Button id="pauseBtn"
@@ -582,10 +594,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                  label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restart.label')}" />
     </mx:VBox>
     <mx:VBox id="errorBox" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="center" verticalAlign="middle">
-      <mx:Label id="startFailedLbl" width="70%" visible="false" includeInLayout="false" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.startFailed.label')}"/>
-      <mx:Label id="restartFailedLbl" width="70%" textAlign="center" visible="false" includeInLayout="false" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restartFailed.label')}"/>
-      <mx:Label id="jwsCrashedLbl" width="70%" textAlign="center" visible="false" includeInLayout="false" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.jwsCrashed.label')}"/>
-      <mx:Label width="70%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.commonErrorMessage.label')}"/>
+      <mx:Text id="startFailedLbl" width="70%" visible="false" includeInLayout="false" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.startFailed.label')}"/>
+      <mx:Text id="restartFailedLbl" width="70%" textAlign="center" visible="false" includeInLayout="false" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restartFailed.label')}"/>
+      <mx:Text id="jwsCrashedLbl" width="70%" textAlign="center" visible="false" includeInLayout="false" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.jwsCrashed.label')}"/>
+      <mx:Text width="70%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.commonErrorMessage.label')}"/>
+    </mx:VBox>
+    <mx:VBox id="tunnelBox" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="center" verticalAlign="middle">
+      <mx:Text width="80%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.tunnelingErrorMessage.one')}" />
+      <mx:Text width="80%" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.tunnelingErrorMessage.two')}" />
     </mx:VBox>
   </mx:Box>
   <mx:ControlBar horizontalAlign="right">
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
old mode 100755
new mode 100644
index a6b9c4f470e1ac13bf0154ba4147ea012257417c..758013bcff68959ac06ade464c27420664ba574c
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
@@ -22,7 +22,7 @@
 
 <MDIWindow xmlns="flexlib.mdi.containers.*"
            xmlns:mx="http://www.adobe.com/2006/mxml"
-           width="600"
+		   width="600"
            height="400"
            initialize="init()"
            creationComplete="onCreationComplete()"
@@ -38,27 +38,25 @@
 
     <mx:Script>
         <![CDATA[
-      import com.asfusion.mate.events.Dispatcher;     
-      import flexlib.mdi.events.MDIWindowEvent;      
-      import mx.core.UIComponent;      
+      import mx.core.UIComponent;
+      
+      import flexlib.mdi.events.MDIWindowEvent;
+      
+      import org.as3commons.logging.api.ILogger;
+      import org.as3commons.logging.api.getClassLogger;
       import org.bigbluebutton.common.Images;
       import org.bigbluebutton.common.events.LocaleChangeEvent;
-      import org.bigbluebutton.core.managers.UserManager;
+      import org.bigbluebutton.core.UsersUtil;
+      import org.bigbluebutton.core.managers.ReconnectionManager;
       import org.bigbluebutton.main.api.JSLog;
+      import org.bigbluebutton.main.events.BBBEvent;
       import org.bigbluebutton.main.views.MainCanvas;
-      import org.bigbluebutton.modules.screenshare.events.CursorEvent;
-      import org.bigbluebutton.modules.screenshare.events.StartedViewingEvent;
       import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
       import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
       import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
       import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
-      import org.bigbluebutton.util.i18n.ResourceUtil;
-      import org.as3commons.logging.api.ILogger;
-      import org.as3commons.logging.api.getClassLogger;
-      import org.bigbluebutton.core.managers.ReconnectionManager;
-      import org.bigbluebutton.main.events.BBBEvent;
       import org.bigbluebutton.modules.screenshare.services.red5.Connection;
-      import org.bigbluebutton.core.UsersUtil;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
       
       private static const LOG:String = "SC::ScreenshareViewWIndow - ";
       private static const LOGGER:ILogger = getClassLogger(ScreenshareViewWindow);
@@ -70,7 +68,7 @@
 			[Bindable] public var fitToWidthIcon:Class = images.magnifier;
 			[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
 					
-      private var streamAvailable:Boolean = false;
+			private var streamAvailable:Boolean = false;
       
 			private var video:Video;
 			private var ns:NetStream;
@@ -100,7 +98,7 @@
 			}
 									
 			private function onCreationComplete():void{
-        viewScreenshareStream();
+				viewScreenshareStream();
         
 				videoHolder.addChild(video);				
 				this.addChild(videoHolder);
@@ -116,14 +114,14 @@
 				minimizeBtn.tabIndex = baseIndex+1;
 				maximizeRestoreBtn.tabIndex = baseIndex+2;
 				closeBtn.tabIndex = baseIndex+3;
-               
-        var logData:Object = UsersUtil.initLogData();
-        logData.tags = ["screenshare"];
-        logData.width = videoWidth;
-        logData.height = videoHeight;
-        logData.streamId = streamId;
-        
-        LOGGER.info(JSON.stringify(logData));
+
+				var logData:Object = UsersUtil.initLogData();
+				logData.tags = ["screenshare"];
+				logData.width = videoWidth;
+				logData.height = videoHeight;
+				logData.streamId = streamId;
+				
+				LOGGER.info(JSON.stringify(logData));
 			}
 			
 			private function onResizeEndEvent(event:MDIWindowEvent):void {
@@ -238,22 +236,24 @@
 			public function getPrefferedPosition():String{
 				return MainCanvas.DESKTOP_SHARING_VIEW;
 			}
-												
-			/**
-			 * resizes the desktop sharing video to fit to this window
-			 */
-			private function fitToWindow():void{
-        if (!streamAvailable) return;
-        
-				if (videoIsSmallerThanWindow()) {
-					fitWindowToVideo();
-				}
-				
-				// Ignore if we are displaying the actual size of the video
-				if (! btnActualSize.selected) {
-					fitVideoToWindow();
-				}
-			}
+
+            /**
+             * resizes the desktop sharing video to fit to this window
+             */
+            private function fitToWindow():void {
+                if (!streamAvailable)
+                    return;
+
+                if (videoIsSmallerThanWindow()) {
+                    fitWindowToVideo();
+                }
+
+                // Ignore if we are displaying the actual size of the video
+                if (!btnActualSize.selected) {
+                    fitVideoToWindow();
+                }
+            }
+
 			
 			private function fitVideoToWindow():void {
 				if (this.width < this.height) {
@@ -344,13 +344,12 @@
 			private function localeChanged(e:Event):void{
 				resourcesChanged();
 			}
-            
-       public function handleDisconnectedEvent(event:BBBEvent):void {
-          if (event.payload.type == ReconnectionManager.DESKSHARE_CONNECTION) {
-            closeWindow();  
-          }
-      }
-			
+
+            public function handleDisconnectedEvent(event:BBBEvent):void {
+                if (event.payload.type == ReconnectionManager.DESKSHARE_CONNECTION) {
+                    closeWindow();
+                }
+            }			
 		]]>
     </mx:Script>
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml
old mode 100755
new mode 100644
index 742bdbca18329cfc37b57bd11ea481ace99fbf5a..7148f74a81c6fb6f57e57d570ac3b08f9fba4438
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/BreakoutRoomSettings.mxml
@@ -24,6 +24,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				xmlns:s="library://ns.adobe.com/flex/spark" 
 				xmlns:mx="library://ns.adobe.com/flex/mx"
 				xmlns:mate="http://mate.asfusion.com/"
+				xmlns:common="org.bigbluebutton.common.*"
 				width="630" height="650"
 				close="onCloseClicked()"
 				visible="false"
@@ -35,8 +36,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import mx.collections.ArrayCollection;
 			import mx.controls.Alert;
-			import mx.managers.PopUpManager;
 			
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.events.BreakoutRoomEvent;
 			import org.bigbluebutton.main.model.users.BBBUser;
@@ -56,7 +57,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private static var assignement : Dictionary;
 
 			private function onCloseClicked():void {
-				PopUpManager.removePopUp(this);
+				PopUpUtil.removePopUp(this);
 			}
 
 			/**
@@ -87,7 +88,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					event.record = recordCheckbox.selected;
 					dispatcher.dispatchEvent(event);
 					storeAssignement();
-					PopUpManager.removePopUp(this);
+					PopUpUtil.removePopUp(this);
 				} else {
 					Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers'));
 				}
@@ -114,7 +115,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					}
 				}
 				if (usersInvited) {
-					PopUpManager.removePopUp(this);
+					PopUpUtil.removePopUp(this);
 				} else {
 					Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers'));
 				}
@@ -292,8 +293,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		
 		<mx:HBox id="durationBox" width="100%" paddingTop="12">
 			<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.timeLimit')}" />
-			<mx:NumericStepper id="durationStepper" value="15" minimum="1" maximum="600" 
-							   accessibilityName="{ResourceUtil.getInstance().getString('bbb.users.breakout.durationStepper.accessibilityName')}"/>
+			<common:AccessibleNumericStepper id="durationStepper" value="15" minimum="1" maximum="600" 
+							   toolTip="{ResourceUtil.getInstance().getString('bbb.users.breakout.durationStepper.accessibilityName')}"/>
 			<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.minutes')}"/>
 		</mx:HBox>
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
old mode 100755
new mode 100644
index 79aacc9b0e015fbcaeb0a36cfbc82b2eef689cf5..7749b72bb0472cacf76fb26e307e578d185f33d6
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/EmojiGrid.as
@@ -23,15 +23,14 @@ package org.bigbluebutton.modules.users.views {
 	import flash.events.MouseEvent;
 	
 	import mx.containers.HBox;
-	import mx.containers.Tile;
 	import mx.containers.VBox;
 	import mx.controls.Button;
 	import mx.controls.Label;
 	import mx.core.ScrollPolicy;
 	import mx.events.FlexMouseEvent;
-	import mx.managers.PopUpManager;
 	
 	import org.bigbluebutton.common.Images;
+	import org.bigbluebutton.core.PopUpUtil;
 	import org.bigbluebutton.core.managers.UserManager;
 	import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
 	import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -121,7 +120,7 @@ package org.bigbluebutton.modules.users.views {
 		 * Hides the menu
 		 */
 		public function hide():void {
-			PopUpManager.removePopUp(this);
+			PopUpUtil.removePopUp(this);
 		}
 	}
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml
index 65f5cfdb93e8f91e3ccdcf12d7f2e0294e768b64..e298ebd151ca58103766a0b92b743e7d56a2d3bc 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/RoomActionsRenderer.mxml
@@ -51,8 +51,8 @@
 		]]>
 	</mx:Script>
 
-	<mx:Button id="joinImg" width="20" height="20"
-			   includeInLayout="{UserManager.getInstance().getConference().breakoutRoomsReady}" visible="{joinImg.includeInLayout}"
+	<mx:Button id="joinBtn" width="20" height="20"
+			   includeInLayout="{UserManager.getInstance().getConference().breakoutRoomsReady}" visible="{joinBtn.includeInLayout}"
 			   icon="{images.join}" toolTip="{ResourceUtil.getInstance().getString('bbb.users.roomsGrid.join')}"
 			   click="requestBreakoutJoinUrl(event)"/>
 	<mx:Button id="listenBtn" toggle="true"
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
old mode 100755
new mode 100644
index 53a54fa47199b2b710fec7f6c1075ed79d19fda6..b398bc5dd55809ab79b4a95c1e0b838c01c37833
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
@@ -25,6 +25,7 @@
 					 xmlns:flc="flexlib.controls.*"
 					 implements="org.bigbluebutton.common.IBbbModuleWindow"
 					 xmlns:mate="http://mate.asfusion.com/"
+					 xmlns:views="org.bigbluebutton.main.views.*"
 					 creationComplete="onCreationComplete()"
 					 title="{ResourceUtil.getInstance().getString('bbb.users.title')}"
 					 showCloseButton="false">
@@ -33,6 +34,7 @@
 	<mate:Listener type="{ShortcutEvent.RAISE_HAND}" method="remoteRaiseHand" />
 	<mate:Listener type="{ShortcutEvent.FOCUS_USERS_WINDOW}" method="focusWindow" />
 	<mate:Listener type="{ShortcutEvent.MUTE_ALL_BUT_PRES}" method="remoteMuteAllButPres" />
+	<mate:Listener type="{ShortcutEvent.OPEN_BREAKOUT_ROOMS}" method="handleOpenBreakoutRooms" />
 	<mate:Listener type="{MeetingMutedEvent.MEETING_MUTED}" method="handleMeetingMuted" />
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="handleChangedLockSettingsEvent" />
 	<mate:Listener type="{BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT}" method="handleRemainingTimeUpdate" />
@@ -47,8 +49,10 @@
 			import mx.collections.ArrayCollection;
 			import mx.controls.Alert;
 			import mx.controls.Menu;
+			import mx.controls.dataGridClasses.DataGridColumn;
 			import mx.controls.listClasses.IListItemRenderer;
 			import mx.core.FlexGlobals;
+			import mx.core.mx_internal;
 			import mx.events.CloseEvent;
 			import mx.events.CollectionEvent;
 			import mx.events.ListEvent;
@@ -60,6 +64,8 @@
 			import org.bigbluebutton.common.IBbbModuleWindow;
 			import org.bigbluebutton.common.Images;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
+			import org.bigbluebutton.core.KeyboardUtil;
+			import org.bigbluebutton.core.PopUpUtil;
 			import org.bigbluebutton.core.TimerUtil;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
@@ -127,7 +133,10 @@
 			private const KICK_USER:String = "Kick User";
 			private const MUTE_USER:String = "Mute User";
 			private const MUTE_ALL_USER:String = "Mute All User";
-			
+			private const FOCUS_BREAKOUT_ROOMS_LIST:String = "Focus Breakout Rooms";
+			private const LISTEN_TO_BREAKOUT_ROOM:String = "Listen To Breakout Room";
+			private const JOIN_BREAKOUT_ROOM:String = "Join Breakout Room";
+
 			private var muteMeRolled:Boolean = false;
 			
 			private function onCreationComplete():void {
@@ -251,12 +260,12 @@
 				dispatcher.dispatchEvent(rollEvent);
 			}
 
-			private function openEmojiStatusMenu():void {
-				var grid:EmojiGrid = PopUpManager.createPopUp(DisplayObject(FlexGlobals.topLevelApplication), EmojiGrid, false) as EmojiGrid;
-				var menuXY:Point = emojiStatusBtn.localToGlobal(new Point(emojiStatusBtn.width + 2, emojiStatusBtn.height - grid.height));
-				grid.x = menuXY.x;
-				grid.y = menuXY.y;
-			}
+            private function openEmojiStatusMenu():void {
+                var grid:EmojiGrid = PopUpUtil.createNonModelPopUp(DisplayObject(FlexGlobals.topLevelApplication), EmojiGrid, false) as EmojiGrid;
+                var menuXY:Point = emojiStatusBtn.localToGlobal(new Point(emojiStatusBtn.width + 2, emojiStatusBtn.height - grid.height));
+                grid.x = menuXY.x;
+                grid.y = menuXY.y;
+            }
 
 			private function openSettings():void {
 				paramsMenuData = [];
@@ -362,50 +371,11 @@
 
 			private function removeJoinAlert():void {
 				if (joinAlert != null) {
+					// @todo: any way using PopUpUtil ?
 					PopUpManager.removePopUp(joinAlert);
 				}
 			}
 
-			/*private function unlockAll():void {
-				LogUtil.traceObject("Action: unlockAll");
-				if (amIModerator) {
-					if (roomLocked) {
-						var unlockCommand:LockControlEvent = new LockControlEvent(LockControlEvent.UNLOCK_ALL);
-						dispatchEvent(unlockCommand);
-						roomLocked = false;
-					} else {
-						LogUtil.error("Action: unlockAll, but room is not locked");
-					}
-				}
-			}
-			
-			private function lockAll():void {
-				LogUtil.traceObject("Action: lockAll");
-				if (amIModerator) {
-					if (!roomLocked) {
-						var lockCommand:LockControlEvent = new LockControlEvent(LockControlEvent.LOCK_ALL);
-						dispatchEvent(lockCommand);
-						roomLocked = true;
-					} else {
-						LogUtil.error("Action: lockAll, but room is already locked");
-					}
-				}
-			}
-			
-			private function lockAlmostAll():void {
-				LogUtil.traceObject("Action: lockAlmostAll");
-				
-				if (amIModerator) {
-					if (!roomLocked) {
-						var lockCommand:LockControlEvent = new LockControlEvent(LockControlEvent.LOCK_ALMOST_ALL);
-						dispatchEvent(lockCommand);
-						roomLocked = true;
-					} else {
-						LogUtil.error("Action: lockAlmostAll, but room is already locked");
-					}
-				}
-			}
-			*/
 			private function handleMeetingMuted(e:MeetingMutedEvent):void {
 				roomMuted = MeetingModel.getInstance().meetingMuted;
 			}
@@ -475,6 +445,9 @@
 				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.kick') as String)] = KICK_USER;
 				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.mute') as String)] = MUTE_USER;
 				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.muteall') as String)] = MUTE_ALL_USER;
+				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.focusBreakoutRooms') as String)] = FOCUS_BREAKOUT_ROOMS_LIST;
+				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.listenToBreakoutRoom') as String)] = LISTEN_TO_BREAKOUT_ROOM;
+				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.users.joinBreakoutRoom') as String)] = JOIN_BREAKOUT_ROOM;
 				//TODO Include shortcuts to lock control
 				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.general.maximize') as String)] = ShortcutEvent.MAXIMIZE_USERS;
 				keyCombos[modifier + (ResourceUtil.getInstance().getString('bbb.shortcutkey.general.minimize') as String)] = ShortcutEvent.MINIMIZE_USERS;
@@ -483,8 +456,7 @@
 			// Handle general-access hotkeys, regardless of what window the user is focused in
 			private function handleKeyDown(e:KeyboardEvent):void {
 				if (keyCombos == null) loadKeyCombos(modifier);
-				var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") +
-					(e.altKey   ? "alt+"     : "") + e.keyCode;		                              
+				var keyPress:String = KeyboardUtil.buildPressedKeys(e);
 				if (keyCombos[keyPress]) {
 					switch (keyCombos[keyPress]) {
 						case FOCUS_USERS_LIST:
@@ -502,6 +474,15 @@
 						case MUTE_ALL_USER:
 							muteAll();
 							break;
+						case FOCUS_BREAKOUT_ROOMS_LIST:
+							remoteFocusBreakoutRooms();
+							break;
+						case LISTEN_TO_BREAKOUT_ROOM:
+							listenToBreakoutRoom();
+							break;
+						case JOIN_BREAKOUT_ROOM:
+							joinBreakoutRoom();
+							break;
 						case ShortcutEvent.MAXIMIZE_USERS:
 							remoteMaximize();
 							break;
@@ -565,11 +546,11 @@
 			
 			public function remoteMuteUser():void {
 				if (amIModerator && usersGrid.selectedIndex != -1) {
-					var selData:Object = usersGrid.selectedItem;
+					var selData:BBBUser = (usersGrid.selectedItem) as BBBUser;
 					
 					if (selData.voiceJoined) {
 						var e:VoiceConfEvent = new VoiceConfEvent(VoiceConfEvent.MUTE_USER);
-						e.userid = selData.voiceUserid;
+						e.userid = selData.userID;
 						e.mute = !selData.voiceMuted;
 						dispatchEvent(e);
 					}
@@ -581,6 +562,33 @@
 				usersGrid.drawFocus(true);
 			}
 			
+			public function remoteFocusBreakoutRooms() : void {
+				if (roomsGrid && roomsGrid.visible) {
+					focusManager.setFocus(roomsGrid);
+					roomsGrid.drawFocus(true);			
+				}
+			}
+			
+			public function listenToBreakoutRoom() : void {
+				if (roomsGrid && roomsBox.visible && roomsGrid.selectedIndex > -1) {
+					// roomsGrid.selectedIndex + 1 is needed as the first index of rendererArray contains the header renderes
+					var renderer : RoomActionsRenderer = roomsGrid.mx_internal::rendererArray[roomsGrid.selectedIndex + 1][2];
+					if (renderer.listenBtn.visible) {
+						renderer.listenBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
+					}
+				}
+			}
+			
+			public function joinBreakoutRoom() : void {
+				if (roomsGrid && roomsBox.visible && roomsGrid.selectedIndex > -1) {
+					// roomsGrid.selectedIndex + 1 is needed as the first index of rendererArray contains the header renderes
+					var renderer : RoomActionsRenderer = roomsGrid.mx_internal::rendererArray[roomsGrid.selectedIndex + 1][2];
+					if (renderer.joinBtn.visible) {
+						renderer.joinBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
+					}
+				}
+			}
+			
 			private function remoteMuteAllButPres(e:ShortcutEvent):void{
 				if (!roomMuted) {
 					muteAlmostAll();
@@ -588,7 +596,13 @@
 					muteAll();
 				}
 			}
-			
+
+			private function handleOpenBreakoutRooms(e:ShortcutEvent):void{
+				if (breakoutOptions.enabled && amIModerator && !UserManager.getInstance().getConference().isBreakout) {
+					breakoutRooms();
+				}
+			}
+
 			private function breakoutRoomNameLabelFunction(item:Object, column:DataGridColumn) : String {
 				return ResourceUtil.getInstance().getString('bbb.users.roomsGrid.room') + " " + item.sequence;
 			}
@@ -606,20 +620,20 @@
 
 	<mdi:TabIndexer id="tabIndexer" startIndex="{partOptions.baseTabIndex + 5}" tabIndices="{[usersGrid, roomsGrid, closeRoomsBtn, emojiStatusBtn, settingsBtn]}"/>
 	
-	<mx:DataGrid id="usersGrid" dataProvider="{users}" editable="false" sortableColumns="true"
+	<views:BBBDataGrid id="usersGrid" dataProvider="{users}" editable="false" sortableColumns="true"
     	dragEnabled="false" width="100%" height="100%" draggableColumns="false"
     	itemRollOver="onItemRollOver(event)"
 		itemRollOut="onItemRollOut(event)" 
 		accessibilityName="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.accessibilityName')}" >
-    	<mx:columns>
+    	<views:columns>
     		<mx:DataGridColumn dataField="userStatus" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer')}" editable="false" width="45" minWidth="45"
     			itemRenderer="org.bigbluebutton.modules.users.views.StatusItemRenderer" sortable="false" />
     		<mx:DataGridColumn dataField="displayName" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.nameItemRenderer')}" editable="false" sortable="false" minWidth="60"
     			itemRenderer="org.bigbluebutton.modules.users.views.NameItemRenderer"/>
     		<mx:DataGridColumn dataField="media" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer')}" sortable="false" width="110" minWidth="110"
     			itemRenderer="org.bigbluebutton.modules.users.views.MediaItemRenderer"/>
-    	</mx:columns>
-    </mx:DataGrid>
+    	</views:columns>
+    </views:BBBDataGrid>
 	
 	<mx:VBox id="roomsBox" styleName="breakoutRoomsBox"
 			 visible="{breakoutRoomsList.length > 0 &amp;&amp; amIModerator}"
@@ -632,11 +646,11 @@
 					  text="..." toolTip="{ResourceUtil.getInstance().getString('bbb.users.breakout.timer.toolTip')}"/>
 		</mx:HBox>
 
-		<mx:DataGrid id="roomsGrid" editable="false" sortableColumns="false"
+		<views:BBBDataGrid id="roomsGrid" editable="false" sortableColumns="false"
 					 dataProvider="{breakoutRoomsList}" dataTipFunction="breakoutRoomsToolTip"
 					 dragEnabled="false" width="100%" height="100%" draggableColumns="false"
 					 accessibilityName="{ResourceUtil.getInstance().getString('bbb.users.breakout.breakoutRooms')}">
-			<mx:columns>
+			<views:columns>
 				<mx:DataGridColumn labelFunction="breakoutRoomNameLabelFunction"
 								   showDataTips="true"
 								   headerText="{ResourceUtil.getInstance().getString('bbb.users.roomsGrid.room')}" />
@@ -647,8 +661,8 @@
 								   visible="{amIModerator}"
 								   headerText="{ResourceUtil.getInstance().getString('bbb.users.roomsGrid.action')}"
 								   itemRenderer="org.bigbluebutton.modules.users.views.RoomActionsRenderer"/>
-			</mx:columns>
-		</mx:DataGrid>
+			</views:columns>
+		</views:BBBDataGrid>
 
 		<mx:Button id="closeRoomsBtn" label="{ResourceUtil.getInstance().getString('bbb.users.breakout.closeAllRooms')}"
 				   click="endAllBreakoutRoomsHandler(event)" width="100%"/>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMapDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMapDelegate.as
index d4f148cbd1f5f71260a164c8a5d36fa0a5d26895..32c88f2475c023800c951badbf5f89f0c704eede 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMapDelegate.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/maps/VideoEventMapDelegate.as
@@ -60,8 +60,8 @@ package org.bigbluebutton.modules.videoconf.maps
 
   public class VideoEventMapDelegate
   {
-	private static const LOGGER:ILogger = getClassLogger(VideoEventMapDelegate);
-	private static var PERMISSION_DENIED_ERROR:String = "PermissionDeniedError";
+    private static const LOGGER:ILogger = getClassLogger(VideoEventMapDelegate);
+    private static var PERMISSION_DENIED_ERROR:String = "PermissionDeniedError";
 
     private var options:VideoConfOptions = new VideoConfOptions();
     private var uri:String;
@@ -71,7 +71,6 @@ package org.bigbluebutton.modules.videoconf.maps
 
     private var _dispatcher:IEventDispatcher;
     private var _ready:Boolean = false;
-    private var _isPublishing:Boolean = false;
     private var _isPreviewWebcamOpen:Boolean = false;
     private var _isWaitingActivation:Boolean = false;
     private var _chromeWebcamPermissionDenied:Boolean = false;
@@ -79,18 +78,17 @@ package org.bigbluebutton.modules.videoconf.maps
     private var _videoDock:VideoDock;
     private var _graphics:GraphicsWrapper = new GraphicsWrapper();
     private var streamList:ArrayList = new ArrayList();
-    private var numberOfWindows:Object = new Object();
-
-	private var _restream:Boolean = false;
-	private var _cameraIndex:int;
-	private var _videoProfile:VideoProfile;
-	
-	private var globalDispatcher:Dispatcher;
-	
+
+    private var _restream:Boolean = false;
+    private var _myCamSettings:ArrayCollection = null;
+
+    private var globalDispatcher:Dispatcher;
+
     public function VideoEventMapDelegate(dispatcher:IEventDispatcher)
     {
       _dispatcher = dispatcher;
-	  globalDispatcher = new Dispatcher();
+      globalDispatcher = new Dispatcher();
+      _myCamSettings = new ArrayCollection();
     }
 
     private function get me():String {
@@ -119,14 +117,14 @@ package org.bigbluebutton.modules.videoconf.maps
       }
     }
 
-	public function handleStreamStoppedEvent(event:StreamStoppedEvent):void {
-		if (UserManager.getInstance().getConference().amIThisUser(event.userId)) {
-			closePublishWindowByStream(event.streamId);
-		} else {
-			closeViewWindowWithStream(event.userId, event.streamId);
-		}
-	}
-	
+    public function handleStreamStoppedEvent(event:StreamStoppedEvent):void {
+      if (UserManager.getInstance().getConference().amIThisUser(event.userId)) {
+        closePublishWindowByStream(event.streamId);
+      } else {
+        closeViewWindowWithStream(event.userId, event.streamId);
+      }
+    }
+
     public function handleUserLeftEvent(event:UserLeftEvent):void {
       LOGGER.debug("VideoEventMapDelegate:: [{0}] handleUserLeftEvent. ready = [{1}]", [me, _ready]);
 
@@ -136,7 +134,7 @@ package org.bigbluebutton.modules.videoconf.maps
     }
 
     public function handleUserJoinedEvent(event:UserJoinedEvent):void {
-		LOGGER.debug("VideoEventMapDelegate:: [{0}] handleUserJoinedEvent. ready = [{1}]", [me, _ready]);
+     LOGGER.debug("VideoEventMapDelegate:: [{0}] handleUserJoinedEvent. ready = [{1}]", [me, _ready]);
 
       if (!_ready) return;
 
@@ -165,7 +163,7 @@ package org.bigbluebutton.modules.videoconf.maps
 
         var event:ToolbarButtonEvent = new ToolbarButtonEvent(ToolbarButtonEvent.ADD);
         event.button = button;
-		event.module="Webcam";
+        event.module="Webcam";
         _dispatcher.dispatchEvent(event);
       }
     }
@@ -221,7 +219,7 @@ package org.bigbluebutton.modules.videoconf.maps
     }
 
     private function openWebcamWindows():void {
-		LOGGER.debug("VideoEventMapDelegate:: [{0}] openWebcamWindows. ready = [{1}]", [me, _ready]);
+      LOGGER.debug("VideoEventMapDelegate:: [{0}] openWebcamWindows. ready = [{1}]", [me, _ready]);
 
       var uids:ArrayCollection = UsersUtil.getUserIDs();
 
@@ -308,45 +306,42 @@ package org.bigbluebutton.modules.videoconf.maps
 
     public function connectToVideoApp():void {
       proxy = new VideoProxy(uri);
-	  proxy.reconnectWhenDisconnected(true);
+      proxy.reconnectWhenDisconnected(true);
       proxy.connect();
     }
 
     public function startPublishing(e:StartBroadcastEvent):void{
-	  LOGGER.debug("VideoEventMapDelegate:: [{0}] startPublishing:: Publishing stream to: {1}/{2}", [me, proxy.connection.uri, e.stream]);
+      LOGGER.debug("VideoEventMapDelegate:: [{0}] startPublishing:: Publishing stream to: {1}/{2}", [me, proxy.connection.uri, e.stream]);
       proxy.startPublishing(e);
 
-	  _isWaitingActivation = false;
-      _isPublishing = true;
-      UsersUtil.setIAmPublishing(true);
+      _isWaitingActivation = false;
 
-      var broadcastEvent:BroadcastStartedEvent = new BroadcastStartedEvent();
-      streamList.addItem(e.stream);
-      broadcastEvent.stream = e.stream;
-      broadcastEvent.userid = UsersUtil.getMyUserID();
-      broadcastEvent.isPresenter = UsersUtil.amIPresenter();
-      broadcastEvent.camSettings = UsersUtil.amIPublishing();
+      var arr: ArrayCollection = UsersUtil.amIPublishing();
+      for (var i:int = 0; i < arr.length; i++) {
+        var broadcastEvent:BroadcastStartedEvent = new BroadcastStartedEvent();
+        streamList.addItem(e.stream);
+        broadcastEvent.stream = e.stream;
+        broadcastEvent.userid = UsersUtil.getMyUserID();
+        broadcastEvent.isPresenter = UsersUtil.amIPresenter();
+        broadcastEvent.camSettings = arr.getItemAt(i) as CameraSettingsVO;
 
-      _dispatcher.dispatchEvent(broadcastEvent);
-	  if (proxy.videoOptions.showButton) {
-		  button.callLater(button.publishingStatus, [button.START_PUBLISHING]);
-	  }
+        _dispatcher.dispatchEvent(broadcastEvent);
+      }
+
+      if (proxy.videoOptions.showButton) {
+       button.callLater(button.publishingStatus, [button.START_PUBLISHING]);
+      }
     }
 
     public function stopPublishing(e:StopBroadcastEvent):void{
       LOGGER.debug("VideoEventMapDelegate:: [{0}] Stop publishing. ready = [{1}]", [me, _ready]);
-      checkLastBroadcasting();
+      UsersUtil.removeCameraSettings(e.camId);
+
       streamList.removeItem(e.stream);
       stopBroadcasting(e.stream);
       button.setCamAsInactive(e.camId);
     }
 
-    private function checkLastBroadcasting():void {
-      LOGGER.debug("[VideoEventMapDelegate:checkLastBroadcasting]");
-      _isPublishing = streamList.length > 0;
-      UsersUtil.setIAmPublishing(streamList.length > 0);
-    }
-
     private function stopBroadcasting(stream:String = ""):void {
       if (stream == null) stream = "";
       LOGGER.debug("Stopping broadcast{0}", [(stream.length > 0? " of stream [" + stream + "]": "")]);
@@ -383,18 +378,18 @@ package org.bigbluebutton.modules.videoconf.maps
 
     public function handleClosePublishWindowEvent(event:ClosePublishWindowEvent):void {
       LOGGER.debug("Closing publish window");
-      if (_isPublishing || _chromeWebcamPermissionDenied) {
+      if (_myCamSettings.length > 0 || _chromeWebcamPermissionDenied) {
         stopBroadcasting();
       }
     }
 
     public function handleShareCameraRequestEvent(event:ShareCameraRequestEvent):void {
-		LOGGER.debug("[VideoEventMapDelegate:handleShareCameraRequestEvent]");
-		if (options.skipCamSettingsCheck) {
-			skipCameraSettingsCheck();
-		} else {
-			openWebcamPreview(event.publishInClient, event.defaultCamera, event.camerasArray);
-		}
+     LOGGER.debug("[VideoEventMapDelegate:handleShareCameraRequestEvent] {0} {1}", [options.skipCamSettingsCheck, event.toString()]);
+     if (options.skipCamSettingsCheck) {
+       skipCameraSettingsCheck();
+     } else {
+       openWebcamPreview(event.publishInClient, event.defaultCamera, event.camerasArray);
+     }
     }
 
     public function handleStopAllShareCameraRequestEvent(event:StopShareCameraRequestEvent):void {
@@ -407,12 +402,15 @@ package org.bigbluebutton.modules.videoconf.maps
       var userID:String = UsersUtil.getMyUserID();
       var camIndex:int = event.camId;
 
+      // remove the camera from the settings so it does not resume sharing on refresh
+      removeCamera(camIndex);
+
       _graphics.removeVideoByCamIndex(userID, camIndex);
     }
 
-	public function handleCamSettingsClosedEvent(event:BBBEvent):void{
-		_isPreviewWebcamOpen = false;
-	}
+    public function handleCamSettingsClosedEvent(event:BBBEvent):void{
+      _isPreviewWebcamOpen = false;
+    }
 
     private function openWebcamPreview(publishInClient:Boolean, defaultCamera:String, camerasArray:Object):void {
       var openEvent:BBBEvent = new BBBEvent(BBBEvent.OPEN_WEBCAM_PREVIEW);
@@ -421,7 +419,7 @@ package org.bigbluebutton.modules.videoconf.maps
       openEvent.payload.camerasArray = camerasArray;
       openEvent.payload.chromePermissionDenied = _chromeWebcamPermissionDenied;
 
-	  _isPreviewWebcamOpen = true;
+      _isPreviewWebcamOpen = true;
 
       _dispatcher.dispatchEvent(openEvent);
     }
@@ -432,13 +430,13 @@ package org.bigbluebutton.modules.videoconf.maps
       var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
       event.window = _videoDock;
       globalDispatcher.dispatchEvent(event);
-	  proxy.reconnectWhenDisconnected(false);
+      proxy.reconnectWhenDisconnected(false);
       proxy.disconnect();
     }
 
     private function closeAllWindows():void {
       LOGGER.debug("VideoEventMapDelegate:: closing all windows");
-      if (_isPublishing) {
+      if (_myCamSettings.length > 0) {
         stopBroadcasting();
       }
 
@@ -459,7 +457,7 @@ package org.bigbluebutton.modules.videoconf.maps
       if (options.showButton){
         LOGGER.debug("****************** Switching to viewer. Show video button?=[{0}]", [UsersUtil.amIPresenter()]);
         displayToolbarButton();
-        if (_isPublishing && options.presenterShareOnly) {
+        if (_myCamSettings.length > 0 && options.presenterShareOnly) {
           stopBroadcasting();
         }
       }
@@ -478,33 +476,58 @@ package org.bigbluebutton.modules.videoconf.maps
       openWebcamWindows();
     }
 
+    private function addCamera(camIndex:int, videoProfile:VideoProfile):void {
+      var camSettings:CameraSettingsVO = new CameraSettingsVO();
+      camSettings.camIndex = camIndex;
+      camSettings.videoProfile = videoProfile;
+      camSettings.isPublishing = true;
+
+      if(!_myCamSettings.contains(camSettings)) {
+          _myCamSettings.addItem(camSettings);
+      }
+    }
+
+    private function removeCamera(camIndex:int):void {
+      for(var i:int = 0; i < _myCamSettings.length; i++) {
+        if (_myCamSettings.getItemAt(i) != null && _myCamSettings.getItemAt(i).camIndex == camIndex) {
+          _myCamSettings.removeItemAt(i);
+        }
+      }
+    }
+
     public function handleCameraSetting(event:BBBEvent):void {
-	  _cameraIndex = event.payload.cameraIndex;
-      _videoProfile = event.payload.videoProfile;
-	  _restream = event.payload.restream;
-      LOGGER.debug("VideoEventMapDelegate::handleCameraSettings [{0},{1}]", [_cameraIndex, _videoProfile.id]);
-      initCameraWithSettings(_cameraIndex, _videoProfile);
-    }
-
-	public function handleEraseCameraSetting(event:BBBEvent):void {
-		_cameraIndex = -1;
-		_videoProfile = null;
-		_restream = event.payload.restream;
-	}
-	
-	private function handleRestream():void {
-		if(_restream){
-			LOGGER.debug("VideoEventMapDelegate::handleRestream [{0},{1}]", [_cameraIndex, _videoProfile.id]);
-			initCameraWithSettings(_cameraIndex, _videoProfile);
-		}
-	}
-	
+      var camIndex:int = event.payload.cameraIndex;
+      var videoProfile:VideoProfile = event.payload.videoProfile;
+
+      addCamera(camIndex, videoProfile);
+
+      _restream = event.payload.restream;
+      LOGGER.debug("VideoEventMapDelegate::handleCameraSettings [{0},{1}] _restream={2}", [camIndex, videoProfile.id, _restream]);
+      initCameraWithSettings(camIndex, videoProfile);
+    }
+
+    public function handleEraseCameraSetting(event:BBBEvent):void {
+     _myCamSettings = new ArrayCollection();
+
+     LOGGER.debug("VideoEventMapDelegate::handleEraseCameraSetting [{0}]", [event.toString()]);
+     _restream = event.payload.restream;
+    }
+
+    private function handleRestream():void {
+     if(_restream){
+      for each(var aCamSettings:CameraSettingsVO in _myCamSettings) {
+       LOGGER.debug("VideoEventMapDelegate::handleRestream [{0},{1}]", [aCamSettings.camIndex, aCamSettings.videoProfile.id]);
+       initCameraWithSettings(aCamSettings.camIndex, aCamSettings.videoProfile);
+      }
+     }
+    }
+
     private function initCameraWithSettings(camIndex:int, videoProfile:VideoProfile):void {
       var camSettings:CameraSettingsVO = new CameraSettingsVO();
       camSettings.camIndex = camIndex;
       camSettings.videoProfile = videoProfile;
-
-      UsersUtil.setCameraSettings(camSettings);
+      camSettings.isPublishing = true;
+      UsersUtil.addCameraSettings(camSettings);
 
       _isWaitingActivation = true;
       button.setCamAsActive(camIndex);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserVideo.as b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserVideo.as
old mode 100644
new mode 100755
index 7755ab3b26d740a3f485c2e48584f6ecea007d9a..1c4f8fef5ddaeef4f1419438ee55d0e7ad8e2b5c
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserVideo.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserVideo.as
@@ -67,7 +67,14 @@ package org.bigbluebutton.modules.videoconf.views
        */   
       var d:Date = new Date();
       var curTime:Number = d.getTime(); 
-      return profile.id + "-" + userId + "-" + curTime;
+      var streamId: String = profile.id + "-" + userId + "-" + curTime;
+       if (UsersUtil.isRecorded()) {
+          // Append recorded to stream name to tell server to record this stream.
+          // ralam (feb 27, 2017)
+          streamId += "-recorded";
+        }
+        
+        return streamId;
     }
 
     public static function getVideoProfile(stream:String):VideoProfile {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/VideoDock.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/VideoDock.mxml
index 1cceb3502ce358646eb6e203beb3d37a72399d90..67fa27195c0ce52f8d57bcca011b8799fe710b5a 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/VideoDock.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/VideoDock.mxml
@@ -40,6 +40,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import mx.core.UIComponent;
 			
+			import org.bigbluebutton.core.KeyboardUtil;
 			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.main.views.MainCanvas;
 			import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
@@ -73,8 +74,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function handleKeyDown(e:KeyboardEvent) :void {
 				var modifier:String = ExternalInterface.call("determineModifier");
 				loadKeyCombos(modifier);
-				var keyPress:String = (e.ctrlKey  ? "control+" : "") + (e.shiftKey ? "shift+"   : "") +
-					(e.altKey   ? "alt+"     : "") + e.keyCode;
+				var keyPress:String = KeyboardUtil.buildPressedKeys(e);
 				if (keyCombos[keyPress]) {
 					disp.dispatchEvent(new ShortcutEvent(keyCombos[keyPress]));
 				}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as b/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
index a29d34af03943a0de3fd11b46bf680c657b83892..b4c14ead32196277569434031ba16376658765b3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
@@ -1,247 +1,237 @@
-/**
-* 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.util.i18n
-{
-	import com.asfusion.mate.events.Dispatcher;
-	
-	import flash.events.Event;
-	import flash.events.EventDispatcher;
-	import flash.events.IEventDispatcher;
-	import flash.external.ExternalInterface;
-	import flash.net.URLLoader;
-	import flash.net.URLRequest;
-	
-	import mx.core.FlexGlobals;
-	import mx.events.ResourceEvent;
-	import mx.resources.IResourceManager;
-	import mx.resources.ResourceManager;
-	import mx.utils.URLUtil;
-    import org.bigbluebutton.core.UsersUtil;
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	import org.bigbluebutton.common.events.LocaleChangeEvent;
-	import org.bigbluebutton.main.events.AppVersionEvent;
-
-	public class ResourceUtil extends EventDispatcher {
-		private static const LOGGER:ILogger = getClassLogger(ResourceUtil);
-
-		public static const LOCALES_FILE:String = "client/conf/locales.xml";
-		public static const VERSION:String = "0.9.0";
-    
-		private static var instance:ResourceUtil = null;
-		private var inited:Boolean = false;
-		
-		private static var BBB_RESOURCE_BUNDLE:String = 'bbbResources';
-		private static var MASTER_LOCALE:String = "en_US";
-		
-		[Bindable] public var localeCodes:Array = new Array();
-		[Bindable] public var localeNames:Array = new Array();
-		[Bindable] public var localeIndex:Number;
-		
-		private var eventDispatcher:IEventDispatcher;
-		private var resourceManager:IResourceManager;
-		private var preferredLocale:String
-		
-		
-		public function ResourceUtil(enforcer:SingletonEnforcer) {
-			if (enforcer == null) {
-				throw new Error( "You Can Only Have One ResourceUtil" );
-			}
-			initialize();
-		}
-		
-		private function isInited():Boolean {
-			return inited;
-		}
-		
-		public function initialize():void {
-			resourceManager = ResourceManager.getInstance();
-			// Add a random string on the query so that we always get an up-to-date config.xml
-			var date:Date = new Date();
-			
-			var _urlLoader:URLLoader = new URLLoader();     
-			_urlLoader.addEventListener(Event.COMPLETE, handleComplete);
-      
-      		var localeReqURL:String = buildRequestURL() + LOCALES_FILE + "?a=" + date.time;
-			_urlLoader.load(new URLRequest(localeReqURL));
-		}
-		
-    private function buildRequestURL():String {
-      var swfURL:String = FlexGlobals.topLevelApplication.url;
-      var protocol:String = URLUtil.getProtocol(swfURL);
-      var serverName:String = URLUtil.getServerNameWithPort(swfURL);        
-      return protocol + "://" + serverName + "/";
-    }
-    
-		private function handleComplete(e:Event):void{
-			parse(new XML(e.target.data));		
-									
-			preferredLocale = getDefaultLocale();
-			if (preferredLocale != MASTER_LOCALE) {
-				loadMasterLocale(MASTER_LOCALE);
-			}
-			setPreferredLocale(preferredLocale);
-		}
-		
-		private function parse(xml:XML):void{		 	
-			var list:XMLList = xml.locale;
-			var locale:XML;
-						
-			for each(locale in list){
-				localeCodes.push(locale.@code);
-				localeNames.push(locale.@name);
-			}							
-		}
-		
-		private function getDefaultLocale():String {
-			return ExternalInterface.call("getLanguage");
-		}
-		
-		private function isPreferredLocaleAvailable(prefLocale:String):Boolean {
-			for (var i:Number = 0; i < localeCodes.length; i++){
-				if (prefLocale == localeCodes[i]) 
-					return true;
-			}
-			return false;
-		}
-		
-		private function getIndexForLocale(prefLocale:String):int {
-			for (var i:Number = 0; i < localeCodes.length; i++){
-				if (prefLocale == localeCodes[i]) 
-					return i;
-			}
-			return -1;
-		}
-		
-		public function getPreferredLocaleName():String {
-			return localeNames[localeIndex];
-		}
-		
-		public function setPreferredLocale(locale:String):void {
-			if (isPreferredLocaleAvailable(locale)) {
-				preferredLocale = locale;
-			}else{
-				preferredLocale = MASTER_LOCALE;
-			}
-			localeIndex = getIndexForLocale(preferredLocale);
-			changeLocale(preferredLocale);
-		}
-		
-		private function loadMasterLocale(locale:String):void {					
-			/**
-			 *  http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#localeChain
-			 *  Always load the default language, so if the chosen language 
-			 *  doesn't provide a resource, the default language resource is used
-			 */
-			loadResource(locale);					
-		}
-		
-		private function loadResource(language:String):IEventDispatcher {
-			// Add a random string on the query so that we don't get a cached version.
-			
-			var date:Date = new Date();
-			var localeURI:String = buildRequestURL() + 'client/locale/' + language + '_resources.swf?a=' + date.time;
-			return resourceManager.loadResourceModule( localeURI, false);
-		}		
-		
-		public static function getInstance():ResourceUtil {
-			if (instance == null) {
-				instance = new ResourceUtil(new SingletonEnforcer);
-			} 
-			return instance;
-        }
-        
-		public function changeLocale(locale:String):void{        	
-			eventDispatcher = loadResource(locale);
-			eventDispatcher.addEventListener(ResourceEvent.COMPLETE, localeChangeComplete);
-			eventDispatcher.addEventListener(ResourceEvent.ERROR, handleResourceNotLoaded);
-		}
-		
-		private function localeChangeComplete(event:ResourceEvent):void {
-			// Set the preferred locale and master as backup.
-			if (preferredLocale != MASTER_LOCALE) {
-				resourceManager.localeChain = [preferredLocale, MASTER_LOCALE];
-				localeIndex = getIndexForLocale(preferredLocale);
-			} else {
-				if (preferredLocale != MASTER_LOCALE) {
-                    var logData:Object = UsersUtil.initLogData();
-                    logData.tags = ["locale"];
-                    logData.message = "Failed to load locale = " + preferredLocale;
-                    LOGGER.info(JSON.stringify(logData));
-				}
-	
-				resourceManager.localeChain = [MASTER_LOCALE];
-				preferredLocale = MASTER_LOCALE;
-				localeIndex = getIndexForLocale(preferredLocale);
-			}
-			sendAppAndLocaleVersions();
-			update();
-		}
-		
-		private function sendAppAndLocaleVersions():void {
-			var dispatcher:Dispatcher = new Dispatcher();
-			var versionEvent:AppVersionEvent = new AppVersionEvent();
-			versionEvent.configLocaleVersion = false;
-			dispatcher.dispatchEvent(versionEvent);			
-		}		
-		
-		/**
-		 * Defaults to DEFAULT_LANGUAGE when an error is thrown by the ResourceManager 
-		 * @param event
-		 */        
-		private function handleResourceNotLoaded(event:ResourceEvent):void{
-			resourceManager.localeChain = [MASTER_LOCALE];
-			preferredLocale = MASTER_LOCALE;
-			localeIndex = getIndexForLocale(preferredLocale);
-			update();
-		}
-		
-		public function update():void{
-			var dispatcher:Dispatcher = new Dispatcher;
-			dispatcher.dispatchEvent(new LocaleChangeEvent(LocaleChangeEvent.LOCALE_CHANGED));
-			dispatchEvent(new Event(Event.CHANGE));
-		}
-		
-		[Bindable("change")]
-		public function getString(resourceName:String, parameters:Array = null, locale:String = null):String{
-			/**
-			 * Get the translated string from the current locale. If empty, get the string from the master
-			 * locale. Locale chaining isn't working because mygengo actually puts the key and empty value
-			 * for untranslated strings into the locale file. So, when Flash does a lookup, it will see that
-			 * the key is available in the locale and thus not bother falling back to the master locale.
-			 *    (ralam dec 15, 2011).
-			 */
-			var localeTxt:String = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, null);
-			if ((localeTxt == "") || (localeTxt == null)) {
-				localeTxt = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, MASTER_LOCALE);
-			}
-			return localeTxt;
-		}
-		
-		public function getCurrentLanguageCode():String{
-			return preferredLocale;
-		}
-				
-		public function getLocaleCodeForIndex(index:int):String {
-			return localeCodes[index];
-		}
-	}
-}
-
-class SingletonEnforcer{}
+/**
+* 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.util.i18n
+{
+	import com.asfusion.mate.events.Dispatcher;
+	
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.events.IEventDispatcher;
+	import flash.external.ExternalInterface;
+	import flash.net.URLLoader;
+	import flash.net.URLRequest;
+	
+	import mx.core.FlexGlobals;
+	import mx.events.ResourceEvent;
+	import mx.resources.IResourceManager;
+	import mx.resources.ResourceManager;
+	import mx.utils.URLUtil;
+	
+	import org.as3commons.lang.StringUtils;
+	import org.as3commons.logging.api.ILogger;
+	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.common.events.LocaleChangeEvent;
+	import org.bigbluebutton.core.UsersUtil;
+	import org.bigbluebutton.main.events.AppVersionEvent;
+
+	public class ResourceUtil extends EventDispatcher {
+		private static const LOGGER:ILogger = getClassLogger(ResourceUtil);
+
+		public static const LOCALES_FILE:String = "client/conf/locales.xml";
+		public static const VERSION:String = "0.9.0";
+    
+		private static var instance:ResourceUtil = null;
+		private var inited:Boolean = false;
+		
+		private static var BBB_RESOURCE_BUNDLE:String = 'bbbResources';
+		private static var MASTER_LOCALE:String = "en_US";
+		
+		[Bindable] public var localeCodes:Array = new Array();
+		[Bindable] public var localeNames:Array = new Array();
+		[Bindable] public var localeIndex:int;
+		
+		private var eventDispatcher:IEventDispatcher;
+		private var resourceManager:IResourceManager;
+		private var preferredLocale:String
+		
+		
+		public function ResourceUtil(enforcer:SingletonEnforcer) {
+			if (enforcer == null) {
+				throw new Error( "You Can Only Have One ResourceUtil" );
+			}
+			initialize();
+		}
+		
+		private function isInited():Boolean {
+			return inited;
+		}
+		
+		public function initialize():void {
+			resourceManager = ResourceManager.getInstance();
+			// Add a random string on the query so that we always get an up-to-date config.xml
+			var date:Date = new Date();
+			
+			var _urlLoader:URLLoader = new URLLoader();     
+			_urlLoader.addEventListener(Event.COMPLETE, handleComplete);
+      
+      		var localeReqURL:String = buildRequestURL() + LOCALES_FILE + "?a=" + date.time;
+			_urlLoader.load(new URLRequest(localeReqURL));
+		}
+		
+    private function buildRequestURL():String {
+      var swfURL:String = FlexGlobals.topLevelApplication.url;
+      var protocol:String = URLUtil.getProtocol(swfURL);
+      var serverName:String = URLUtil.getServerNameWithPort(swfURL);        
+      return protocol + "://" + serverName + "/";
+    }
+    
+		private function handleComplete(e:Event):void{
+			parse(new XML(e.target.data));		
+									
+			preferredLocale = getDefaultLocale();
+			if (preferredLocale != MASTER_LOCALE) {
+				loadMasterLocale(MASTER_LOCALE);
+			}
+			setPreferredLocale(preferredLocale);
+		}
+		
+		private function parse(xml:XML):void{		 	
+			var list:XMLList = xml.locale;
+			var locale:XML;
+						
+			for each(locale in list){
+				localeCodes.push(locale.@code.toString());
+				localeNames.push(locale.@name.toString());
+			}							
+		}
+		
+		private function getDefaultLocale():String {
+			return ExternalInterface.call("getLanguage");
+		}
+		
+		private function getIndexForLocale(prefLocale:String):int {
+			return localeCodes.indexOf(prefLocale);
+		}
+		
+		public function getPreferredLocaleName():String {
+			return localeNames[localeIndex];
+		}
+		
+		public function setPreferredLocale(locale:String):void {
+			if (localeCodes.indexOf(locale) > -1) {
+				preferredLocale = locale;
+			}else{
+				preferredLocale = MASTER_LOCALE;
+			}
+			localeIndex = getIndexForLocale(preferredLocale);
+			changeLocale(preferredLocale);
+		}
+		
+		private function loadMasterLocale(locale:String):void {					
+			/**
+			 *  http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#localeChain
+			 *  Always load the default language, so if the chosen language 
+			 *  doesn't provide a resource, the default language resource is used
+			 */
+			loadResource(locale);					
+		}
+		
+		private function loadResource(language:String):IEventDispatcher {
+			// Add a random string on the query so that we don't get a cached version.
+			
+			var date:Date = new Date();
+			var localeURI:String = buildRequestURL() + 'client/locale/' + language + '_resources.swf?a=' + date.time;
+			return resourceManager.loadResourceModule( localeURI, false);
+		}		
+		
+		public static function getInstance():ResourceUtil {
+			if (instance == null) {
+				instance = new ResourceUtil(new SingletonEnforcer);
+			} 
+			return instance;
+        }
+        
+		public function changeLocale(locale:String):void{        	
+			eventDispatcher = loadResource(locale);
+			eventDispatcher.addEventListener(ResourceEvent.COMPLETE, localeChangeComplete);
+			eventDispatcher.addEventListener(ResourceEvent.ERROR, handleResourceNotLoaded);
+		}
+		
+		private function localeChangeComplete(event:ResourceEvent):void {
+			// Set the preferred locale and master as backup.
+			if (preferredLocale != MASTER_LOCALE) {
+				resourceManager.localeChain = [preferredLocale, MASTER_LOCALE];
+			} else {
+				if (preferredLocale != MASTER_LOCALE) {
+                    var logData:Object = UsersUtil.initLogData();
+                    logData.tags = ["locale"];
+                    logData.message = "Failed to load locale = " + preferredLocale;
+                    LOGGER.info(JSON.stringify(logData));
+				}
+	
+				resourceManager.localeChain = [MASTER_LOCALE];
+				preferredLocale = MASTER_LOCALE;
+			}
+			localeIndex = getIndexForLocale(preferredLocale);
+			sendAppAndLocaleVersions();
+			update();
+		}
+		
+		private function sendAppAndLocaleVersions():void {
+			var dispatcher:Dispatcher = new Dispatcher();
+			var versionEvent:AppVersionEvent = new AppVersionEvent();
+			versionEvent.configLocaleVersion = false;
+			dispatcher.dispatchEvent(versionEvent);			
+		}		
+		
+		/**
+		 * Defaults to DEFAULT_LANGUAGE when an error is thrown by the ResourceManager 
+		 * @param event
+		 */        
+		private function handleResourceNotLoaded(event:ResourceEvent):void{
+			resourceManager.localeChain = [MASTER_LOCALE];
+			preferredLocale = MASTER_LOCALE;
+			localeIndex = getIndexForLocale(preferredLocale);
+			update();
+		}
+		
+		public function update():void{
+			var dispatcher:Dispatcher = new Dispatcher;
+			dispatcher.dispatchEvent(new LocaleChangeEvent(LocaleChangeEvent.LOCALE_CHANGED));
+			dispatchEvent(new Event(Event.CHANGE));
+		}
+		
+		[Bindable("change")]
+		public function getString(resourceName:String, parameters:Array = null, locale:String = null):String{
+			/**
+			 * @fixme: to be reviewed when all locales from transifex are updated (gtriki feb 7, 2017)
+			 * Get the translated string from the current locale. If empty, get the string from the master
+			 * locale. Locale chaining isn't working because mygengo actually puts the key and empty value
+			 * for untranslated strings into the locale file. So, when Flash does a lookup, it will see that
+			 * the key is available in the locale and thus not bother falling back to the master locale.
+			 *    (ralam dec 15, 2011).
+			 */
+			var localeTxt:String = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, null);
+			if (StringUtils.isEmpty(localeTxt)) {
+				localeTxt = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, MASTER_LOCALE);
+			}
+			return localeTxt;
+		}
+		
+		public function getCurrentLanguageCode():String{
+			return preferredLocale;
+		}
+				
+		public function getLocaleCodeForIndex(index:int):String {
+			return localeCodes[index];
+		}
+	}
+}
+
+class SingletonEnforcer{}
diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf
index 5d8f76f64c166daf68a437bdadc43d761440e379..c0e7ff00d4b4172f4693a82ee0a7cda41cfaa131 100755
--- a/bigbluebutton-config/bin/bbb-conf
+++ b/bigbluebutton-config/bin/bbb-conf
@@ -638,10 +638,10 @@ while [ $# -gt 0 ]; do
 
 	if [ "$1" = "--lti" -o "$1" = "-lti" ]; then
 		if [ -z "$SALT" ]; then
-			if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties ]; then
-				LTI_URL='http://'$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | sed -n '/^ltiEndPoint/{s/^.*=//;p}')'/lti/tool'
-				CUSTOMER=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | sed -n '/^ltiConsumer/{s/^.*=//;s/:.*//p}')
-				SECRET=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | sed -n '/^ltiConsumer/{s/^[^:]*://;p}')
+			if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties ]; then
+				LTI_URL='http://'$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | sed -n '/^ltiEndPoint/{s/^.*=//;p}')'/lti/tool'
+				CUSTOMER=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | sed -n '/^ltiConsumer/{s/^.*=//;s/:.*//p}')
+				SECRET=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | sed -n '/^ltiConsumer/{s/^[^:]*://;p}')
 				echo
 				echo "       URL: $LTI_URL"
 				echo "  Customer: $CUSTOMER"
@@ -889,13 +889,13 @@ check_configuration() {
 		fi
 	fi
 
-	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties ]; then
-                LTI_SALT=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | tr -d '\r' | sed -n '/^bigbluebuttonSalt/{s/.*=//;p}')
+	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties ]; then
+                LTI_SALT=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | tr -d '\r' | sed -n '/^bigbluebuttonSalt/{s/.*=//;p}')
                 BBB_SALT=$(cat ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties | grep -v '#' | tr -d '\r' | sed -n '/securitySalt/{s/.*=//;p}')
 
 		if [ "$LTI_SALT" != "$BBB_SALT" ]; then
 			echo "# Warning: LTI shared secret (salt) mismatch:"
-			echo "#  ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties                      = $LTI_SALT"
+			echo "#  ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties                      = $LTI_SALT"
 			echo "#  ${SERVLET_DIR}/bigbluebutton/WEB-INF/classes/bigbluebutton.properties  = $BBB_SALT"
 			echo 
 		fi
@@ -1395,8 +1395,8 @@ check_state() {
 
 	fi
 
-	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties ]; then
-		LTI_URL='http://'$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | sed -n '/^ltiEndPoint/{s/^.*=//;p}')'/lti/tool'
+	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties ]; then
+		LTI_URL='http://'$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | sed -n '/^ltiEndPoint/{s/^.*=//;p}')'/lti/tool'
 		echo "# Warning: The IMS Learning Tools Integration (LTI) is accessible from:"
 		echo "#"
 		echo "#    $LTI_URL"
@@ -1460,6 +1460,14 @@ check_state() {
                 echo "#    sudo bbb-conf --setip $BBB_WEB_IP"
                 echo "#"
 	fi
+
+        if [ -z $(cat /usr/share/red5/webapps/screenshare/WEB-INF/screenshare.properties | tr -d '\r' | sed -n "/useH264[ ]*=[ ]*/{s/useH264[ ]*=[ ]*//;p}") ]; then
+                echo "# Error: Detected there is no value set for useH264 in"
+                echo "#"
+                echo "#   /usr/share/red5/webapps/screenshare/WEB-INF/screenshare.properties"
+                echo "#"
+        fi
+
 	exit 0
 }
 
@@ -1542,10 +1550,10 @@ if [ $CHECK ]; then
 		echo "                               url: $BBB_WEB_URL"
 	fi
 
-	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties ]; then
-		LTI_URL=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties | grep -v '#' | sed -n '/^bigbluebuttonURL/{s/.*http[s]:\/\///;s/\/.*//;p}' | tr -d '\015')
+	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties ]; then
+		LTI_URL=$(cat ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties | grep -v '#' | sed -n '/^bigbluebuttonURL/{s/.*http[s]:\/\///;s/\/.*//;p}' | tr -d '\015')
 		echo
-		echo "${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties (LTI integration)"
+		echo "${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties (LTI integration)"
 		echo "                           api url: $LTI_URL"
 	fi
 
@@ -1562,13 +1570,6 @@ if [ $CHECK ]; then
 	echo "/usr/share/red5/webapps/bigbluebutton/WEB-INF/red5-web.xml (red5)"
 	echo "                  voice conference: $CONFERENCING_MODULE"
 
-	CAPTURE_VIDEO="$(cat /usr/share/red5/webapps/video/WEB-INF/red5-web.xml | sed -n '/recordVideoStream/{s/^.*="//g;s/"\/>//g;p}')"
-	echo "                     capture video: $CAPTURE_VIDEO"
-
-	# CAPTURE_DESKTOP="$(cat /usr/share/red5/webapps/deskshare/WEB-INF/red5-web.xml | grep -m 1 '<constructor-arg index="0" value'  | sed -n '/constructor-arg/{s/^.*="//g;s/"\/>//g;p}')"
-	# echo "                   capture desktop: $CAPTURE_DESKTOP"
-
-
 	if [ -f /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml ]; then
 		PLAYBACK_IP=$(cat /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml | grep -v '#' | sed -n '/^playback_host/{s/.*:[ ]*//;s/;//;p}' | tail -n 1)
 		echo
@@ -1791,15 +1792,15 @@ if [ -n "$HOST" ]; then
 	fi
 	
 
-	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties ]; then
-		echo "Assigning $HOST for LTI integration in ${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties"
+	if [ -f ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties ]; then
+		echo "Assigning $HOST for LTI integration in ${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties"
 		# We don't wat to guess on http/https as the lti endpoint may be a different BigBlueButton server
         	sed -i "s/bigbluebuttonURL=http:\/\/.*/bigbluebuttonURL=http:\/\/$HOST\/bigbluebutton/g" \
-                	${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties
+                	${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties
         	sed -i "s/bigbluebuttonURL=https:\/\/.*/bigbluebuttonURL=https:\/\/$HOST\/bigbluebutton/g" \
-                	${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties
+                	${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties
         	sed -i "s/ltiEndPoint=.*/ltiEndPoint=$HOST/g" \
-                	${SERVLET_DIR}/lti/WEB-INF/classes/lti.properties
+                	${SERVLET_DIR}/lti/WEB-INF/classes/lti-config.properties
 	fi
 
 
diff --git a/bigbluebutton-config/cron.daily/bigbluebutton b/bigbluebutton-config/cron.daily/bigbluebutton
index 3e7b5df6cd7f34e98a5ef805ea5ede70351eee4d..7dd5a96b54c63ec9912d0b920df25a1396581a63 100755
--- a/bigbluebutton-config/cron.daily/bigbluebutton
+++ b/bigbluebutton-config/cron.daily/bigbluebutton
@@ -38,7 +38,7 @@ find /var/bigbluebutton/ -maxdepth 1 -type d -name "*-*" -mtime +$history -exec
 find /usr/share/red5/webapps/video/streams/ -name "*.flv" -mtime +$history -exec rm '{}' +
 find /usr/share/red5/webapps/video/streams/ -name "*.flv.ser" -mtime +$history -exec rm '{}' +
 find /usr/share/red5/webapps/video/streams/ -name "*.flv.info" -mtime +$history -exec rm '{}' +
-find /usr/share/red5/webapps/video/streams/ -name "*.flv.meta" -mtime +$history -exec rm '{}' +
+find /usr/share/red5/webapps/video/streams/ -name "*.meta" -mtime +$history -exec rm '{}' +
 find /usr/share/red5/webapps/video/streams/ -type d -empty -mtime +$history -exec rmdir '{}' +
 
 #
diff --git a/bigbluebutton-html5/.meteor/.finished-upgraders b/bigbluebutton-html5/.meteor/.finished-upgraders
index aa607041daf76c41f97d5a4a3ee88d4bd661ff91..ce276f3a3382d9f86fc54df8e35cdfc5a49005f4 100644
--- a/bigbluebutton-html5/.meteor/.finished-upgraders
+++ b/bigbluebutton-html5/.meteor/.finished-upgraders
@@ -13,3 +13,4 @@ notices-for-facebook-graph-api-2
 1.3.0-split-minifiers-package
 1.4.0-remove-old-dev-bundle-link
 1.4.1-add-shell-server-package
+1.4.3-split-account-service-packages
diff --git a/bigbluebutton-html5/.meteor/packages b/bigbluebutton-html5/.meteor/packages
index feb3fdeaa856396b9eb9d493e398f3643d8f675f..1eda3b6f6410b6a0e2bee54d70ccf48f3da90dc9 100644
--- a/bigbluebutton-html5/.meteor/packages
+++ b/bigbluebutton-html5/.meteor/packages
@@ -16,10 +16,10 @@ cfs:power-queue
 cfs:reactive-list
 cfs:micro-queue
 reactive-var@1.0.11
-ecmascript@0.6.1
+ecmascript@0.6.3
 react-meteor-data
-standard-minifier-css@1.3.2
-standard-minifier-js@1.2.1
+standard-minifier-css@1.3.3
+standard-minifier-js@1.2.2
 nathantreid:css-modules
-shell-server@0.2.1
-http@1.2.10
+shell-server@0.2.2
+http@1.2.11
diff --git a/bigbluebutton-html5/.meteor/release b/bigbluebutton-html5/.meteor/release
index 61f6c675b193f05a71670c35a1fbd6bf73a6ee15..e6940fd82f24544f09caba55c2bb73b1cb44f1a8 100644
--- a/bigbluebutton-html5/.meteor/release
+++ b/bigbluebutton-html5/.meteor/release
@@ -1 +1 @@
-METEOR@1.4.2.3
+METEOR@1.4.3.1
diff --git a/bigbluebutton-html5/.meteor/versions b/bigbluebutton-html5/.meteor/versions
index ec3598f2a58979837a0e497a892f6eab5d302953..c59c948ac75d25808492bab7beed94bbecf110b9 100644
--- a/bigbluebutton-html5/.meteor/versions
+++ b/bigbluebutton-html5/.meteor/versions
@@ -4,31 +4,31 @@ allow-deny@1.0.5
 amplify@1.0.0
 arunoda:npm@0.2.6
 autoupdate@1.3.12
-babel-compiler@6.13.0
+babel-compiler@6.14.1
 babel-runtime@1.0.1
 base64@1.0.10
 binary-heap@1.0.10
-blaze@2.2.0
+blaze@2.3.0
 blaze-tools@1.0.10
 boilerplate-generator@1.0.11
 caching-compiler@1.1.9
-caching-html-compiler@1.0.7
+caching-html-compiler@1.1.0
 callback-hook@1.0.10
 cfs:http-methods@0.0.32
 cfs:micro-queue@0.0.6
 cfs:power-queue@0.9.11
 cfs:reactive-list@0.0.9
 cfs:reactive-property@0.0.4
-check@1.2.4
+check@1.2.5
 clinical:nightwatch@2.0.1
-coffeescript@1.11.1_4
+coffeescript@1.12.3_1
 ddp@1.2.5
-ddp-client@1.3.2
+ddp-client@1.3.3
 ddp-common@1.2.8
-ddp-server@1.3.12
+ddp-server@1.3.13
 deps@1.0.12
 diff-sequence@1.0.7
-ecmascript@0.6.1
+ecmascript@0.6.3
 ecmascript-runtime@0.3.15
 ejson@1.0.13
 fastclick@1.0.13
@@ -36,30 +36,30 @@ francocatena:status@1.5.3
 geojson-utils@1.0.10
 html-tools@1.0.11
 htmljs@1.0.11
-http@1.2.10
+http@1.2.11
 id-map@1.0.9
 jquery@1.11.10
-launch-screen@1.1.0
+launch-screen@1.1.1
 livedata@1.0.18
-logging@1.1.16
+logging@1.1.17
 mdg:validation-error@0.5.1
-meteor@1.6.0
+meteor@1.6.1
 meteor-platform@1.2.6
 meteorblackbelt:underscore-deep@0.0.4
 meteorspark:util@0.2.0
-minifier-css@1.2.15
-minifier-js@1.2.15
-minimongo@1.0.19
+minifier-css@1.2.16
+minifier-js@1.2.18
+minimongo@1.0.20
 mizzao:timesync@0.4.0
-mobile-status-bar@1.0.13
-modules@0.7.7
-modules-runtime@0.7.7
-mongo@1.1.14
+mobile-status-bar@1.0.14
+modules@0.7.9
+modules-runtime@0.7.9
+mongo@1.1.15
 mongo-id@1.0.6
 mrt:external-file-loader@0.1.4
-nathantreid:css-modules@2.3.1
-npm-mongo@2.2.11_2
-observe-sequence@1.0.14
+nathantreid:css-modules@2.4.0
+npm-mongo@2.2.16_1
+observe-sequence@1.0.15
 ordered-dict@1.0.9
 promise@0.8.8
 raix:eventemitter@0.1.3
@@ -71,22 +71,22 @@ reload@1.1.11
 retry@1.0.9
 routepolicy@1.0.12
 session@1.1.7
-shell-server@0.2.1
+shell-server@0.2.2
 spacebars@1.0.13
-spacebars-compiler@1.0.13
+spacebars-compiler@1.1.0
 standard-app-packages@1.0.9
-standard-minifier-css@1.3.2
-standard-minifier-js@1.2.1
+standard-minifier-css@1.3.4
+standard-minifier-js@1.2.3
 tap:i18n@1.8.2
-templating@1.2.15
-templating-compiler@1.2.15
-templating-runtime@1.2.15
-templating-tools@1.0.5
+templating@1.3.0
+templating-compiler@1.3.0
+templating-runtime@1.3.0
+templating-tools@1.1.0
 tmeasday:check-npm-versions@0.3.1
-tracker@1.1.1
+tracker@1.1.2
 udondan:yml@3.2.2_1
 ui@1.0.12
 underscore@1.0.10
-url@1.0.11
-webapp@1.3.12
+url@1.1.0
+webapp@1.3.13
 webapp-hashing@1.0.9
diff --git a/bigbluebutton-html5/client/stylesheets/bbb-icons.css b/bigbluebutton-html5/client/stylesheets/bbb-icons.css
index f8cf62809ad5231d658d3580f8efa8019f1685f5..fe6d04a721e18c11421105aff37f1f5dc001c028 100755
--- a/bigbluebutton-html5/client/stylesheets/bbb-icons.css
+++ b/bigbluebutton-html5/client/stylesheets/bbb-icons.css
@@ -30,70 +30,67 @@
 }
 
 .icon-bbb-mute:before {
-  content: "\e931";
+  content: "\e932";
 }
 .icon-bbb-unmute:before {
-  content: "\e932";
+  content: "\e931";
 }
 .icon-bbb_file:before {
-  content: "\e92f";
+  content: "\e92e";
 }
 .icon-bbb_upload:before {
-  content: "\e930";
-}
-.icon-bbb_audio_close:before {
-  content: "\e901";
+  content: "\e92f";
 }
 .icon-bbb-fullscreen:before {
-  content: "\e92b";
+  content: "\e92a";
 }
 .icon-bbb-settings:before {
-  content: "\e92c";
+  content: "\e92b";
 }
-.icon-bbb-fit-to-screen:before {
-  content: "\e92a";
+.icon-bbb-fit_to_screen:before {
+  content: "\e929";
+}
+.icon-bbb-linte_tool:before {
+  content: "\e91c";
 }
-.icon-bbb-line-tool:before {
+.icon-bbb-circle_tool:before {
   content: "\e91d";
 }
-.icon-bbb-circle-tool:before {
+.icon-bbb-triangle_tool:before {
   content: "\e91e";
 }
-.icon-bbb-triangle-tool:before {
-  content: "\e91f";
+.icon-bbb-rectangle_tool:before {
+  content: "\e92f";
 }
-.icon-bbb-square-tool:before {
+.icon-bbb-text_tool:before {
   content: "\e920";
 }
-.icon-bbb-text-tool:before {
+.icon-bbb-plus:before {
   content: "\e921";
 }
-.icon-bbb-plus:before {
+.icon-bbb-fit_to_width:before {
   content: "\e922";
 }
-.icon-bbb-fit-to-width:before {
-  content: "\e923";
-}
 .icon-bbb-undo:before {
-  content: "\e925";
+  content: "\e924";
 }
-.icon-bbb-pen-tool:before {
-  content: "\e926";
+.icon-bbb-pen_tool:before {
+  content: "\e925";
 }
 .icon-bbb-lock:before {
-  content: "\e927";
+  content: "\e926";
 }
 .icon-bbb-polling:before {
-  content: "\e928";
+  content: "\e927";
 }
 .icon-bbb-desktop:before {
-  content: "\e929";
+  content: "\e928";
 }
 .icon-bbb-logout:before {
   content: "\e900";
 }
 .icon-bbb-video:before {
-  content: "\1f554";
+  content: "\e930";
 }
 .icon-bbb-more:before {
   content: "\e902";
@@ -102,136 +99,88 @@
   content: "\e903";
 }
 .icon-bbb-application:before {
+  content: "\e901";
+}
+.icon-bbb-video_off:before {
   content: "\e904";
 }
-.icon-bbb-video-off:before {
+.icon-bbb-user:before {
   content: "\e905";
 }
-.icon-bbb-user:before {
+.icon-bbb-up_arrow:before {
   content: "\e906";
 }
-.icon-bbb-up-arrow:before {
-  content: "\e907";
-}
-.icon-bbb-undecided:before {
-  content: "\e908";
+.icon-bbb-right_arrow:before {
+  content: "\e90a";
 }
-.icon-bbb-right-arrow:before {
+.icon-bbb-presentation:before {
   content: "\e90b";
 }
-.icon-bbb-presentation:before {
+.icon-bbb-listen:before {
   content: "\e90c";
 }
-.icon-bbb-listen:before {
+.icon-bbb-left_arrow:before {
   content: "\e90d";
 }
-.icon-bbb-left-arrow:before {
-  content: "\e90e";
-}
-.icon-bbb-hand:before {
+.icon-bbb-group_chat:before {
   content: "\e910";
 }
-.icon-bbb-group-chat:before {
-  content: "\e911";
-}
-.icon-bbb-confused:before {
+.icon-bbb-close:before {
   content: "\e912";
 }
-.icon-bbb-close:before {
+.icon-bbb-clear_status:before {
   content: "\e913";
 }
-.icon-bbb-clear-status:before {
+.icon-bbb-circle:before {
   content: "\e914";
 }
-.icon-bbb-circle:before {
+.icon-bbb-substract:before {
   content: "\e915";
 }
-.icon-bbb-circle-minus:before {
+.icon-bbb-circle_close:before {
   content: "\e916";
 }
-.icon-bbb-circle-close:before {
+.icon-bbb-add:before {
   content: "\e917";
 }
-.icon-bbb-circle-add:before {
+.icon-bbb-check:before {
   content: "\e918";
 }
-.icon-bbb-check:before {
+.icon-bbb-chat:before {
   content: "\e919";
 }
-.icon-bbb-chat:before {
+.icon-bbb-audio_on:before {
   content: "\e91a";
 }
-.icon-bbb-audio:before {
+.icon-bbb-audio_off:before {
   content: "\e91b";
 }
-.icon-bbb-audio-off:before {
-  content: "\e91c";
-}
-.rotate-quarter {
-  transform: rotate(-90deg);
-}
-.icon-bbb-fit-to-screen:before {
-    content: "\e92a";
-}
-.icon-bbb-full-screen:before {
-    content: "\e92b";
-}
-.icon-bbb-logout2:before {
-  content: "\e901";
-}
-.icon-bbb-line-tool:before {
-  content: "\e91d";
-}
-.icon-bbb-circle-tool:before {
-  content: "\e91e";
-}
-.icon-bbb-triangle-tool:before {
-  content: "\e91f";
-}
-.icon-bbb-square-tool:before {
-  content: "\e920";
-}
-.icon-bbb-text-tool:before {
-  content: "\e921";
-}
-.icon-bbb-plus:before {
-  content: "\e922";
-}
-.icon-bbb-fit-to-width:before {
-  content: "\e923";
-}
-.icon-bbb-undo:before {
-  content: "\e925";
-}
-.icon-bbb-pen-tool:before {
-  content: "\e926";
-}
-.icon-bbb-lock:before {
-  content: "\e927";
-}
 
 /* Aliases for emoji status */
-.icon-bbb-away:before {
-  content: "\e909";
+.icon-bbb-time:before {
+  content: "\e908";
 }
-.icon-bbb-raiseHand:before {
-  content: "\e910";
+.icon-bbb-hand:before {
+  content: "\e90f";
 }
-.icon-bbb-neutral:before {
-  content: "\e908";
+.icon-bbb-undecided:before {
+  content: "\e907";
 }
 .icon-bbb-happy:before {
-  content: "\e90f";
+  content: "\e90e";
 }
 .icon-bbb-sad:before {
-  content: "\e90a";
+  content: "\e909";
 }
-.icon-bbb-applause:before {
-  content: "\e924";
+.icon-bbb-confused:before {
+  content: "\e911";
 }
-.icon-bbb-thumbsUp:before {
-  content: "\e92e";
+.icon-bbb-applause:before {
+  content: "\e923";
 }
-.icon-bbb-thumbsDown:before {
+.icon-bbb-thumbs_up:before {
   content: "\e92d";
 }
+.icon-bbb-thumbs_down:before {
+  content: "\e92c";
+}
diff --git a/bigbluebutton-html5/client/stylesheets/toggleSwitch.css b/bigbluebutton-html5/client/stylesheets/toggleSwitch.css
new file mode 100644
index 0000000000000000000000000000000000000000..3a869076233a1070187f5e11b10a7d161e4de139
--- /dev/null
+++ b/bigbluebutton-html5/client/stylesheets/toggleSwitch.css
@@ -0,0 +1,131 @@
+.react-toggle {
+  display: inline-block;
+  position: relative;
+  cursor: pointer;
+  background-color: transparent;
+  border: 0;
+  padding: 0;
+
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+
+  -webkit-tap-highlight-color: rgba(0,0,0,0);
+  -webkit-tap-highlight-color: transparent;
+}
+
+.react-toggle-screenreader-only {
+  border: 0;
+  clip: rect(0 0 0 0);
+  height: 1px;
+  margin: -1px;
+  overflow: hidden;
+  padding: 0;
+  position: absolute;
+  width: 1px;
+}
+
+.react-toggle--disabled {
+  cursor: not-allowed;
+  opacity: 0.5;
+  -webkit-transition: opacity 0.25s;
+  transition: opacity 0.25s;
+}
+
+.react-toggle-track {
+  overflow: hidden;
+  width: 3.5rem;
+  height: 1.5rem;
+  padding: 0;
+  border-radius: 2rem;
+  background-color: #B7E5DA;
+  -webkit-transition: all 0.2s ease;
+  -moz-transition: all 0.2s ease;
+  transition: all 0.2s ease;
+}
+
+.react-toggle--checked .react-toggle-track {
+  background-color: #4DC0A2;
+}
+
+.react-toggle-track-check {
+  position: absolute;
+  color: white;
+  width: 1rem;
+  line-height: 1.5rem;
+  font-size: 0.8rem;
+  left: 0.5rem;
+  opacity: 0;
+  -webkit-transition: opacity 0.25s ease;
+  -moz-transition: opacity 0.25s ease;
+  transition: opacity 0.25s ease;
+}
+
+.react-toggle--checked .react-toggle-track-check {
+  opacity: 1;
+  -webkit-transition: opacity 0.25s ease;
+  -moz-transition: opacity 0.25s ease;
+  transition: opacity 0.25s ease;
+}
+
+.react-toggle-track-x {
+  position: absolute;
+  color: white;
+  width: 1rem;
+  line-height: 1.5rem;
+  font-size: 0.8rem;
+  left: 1.7rem;
+  opacity: 1;
+  -webkit-transition: opacity 0.25s ease;
+  -moz-transition: opacity 0.25s ease;
+  transition: opacity 0.25s ease;
+}
+
+.react-toggle--checked .react-toggle-track-x {
+  opacity: 0;
+}
+
+.react-toggle-thumb {
+  transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
+  position: absolute;
+  top: 1px;
+  left: 1px;
+  width: 1.35rem;
+  height: 1.35rem;
+  border-radius: 50%;
+  background-color: #FAFAFA;
+
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+
+  -webkit-transition: all 0.25s ease;
+  -moz-transition: all 0.25s ease;
+  transition: all 0.25s ease;
+
+  -webkit-box-shadow: 2px 0px 10px -1px rgba(0,0,0,0.4);
+  -moz-box-shadow: 2px 0px 102px -1px rgba(0,0,0,0.4);
+  box-shadow: 2px 0px 10px -1px rgba(0,0,0,0.4);
+}
+
+.react-toggle--checked .react-toggle-thumb {
+  left: 2.1rem;
+  -webkit-box-shadow: -2px 0px 10px -1px rgba(0,0,0,0.4);
+  -moz-box-shadow: -2px 0px 102px -1px rgba(0,0,0,0.4);
+  box-shadow: -2px 0px 10px -1px rgba(0,0,0,0.4);
+}
+
+.react-toggle--focus .react-toggle-thumb {
+  -webkit-box-shadow: 0px 0px 3px 2px #53bdee;
+  -moz-box-shadow: 0px 0px 3px 2px #53bdee;
+  box-shadow: 0px 0px 2px 3px #53bdee;
+}
+
+.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {
+  -webkit-box-shadow: 0px 0px 5px 5px #53bdee;
+  -moz-box-shadow: 0px 0px 5px 5px #53bdee;
+  box-shadow: 0px 0px 5px 5px #53bdee;
+}
diff --git a/bigbluebutton-html5/imports/api/meetings/server/handlers/permissionSettingsChange.js b/bigbluebutton-html5/imports/api/meetings/server/handlers/permissionSettingsChange.js
index 13cb61203932fdef8cfe75bc91edb74acb799d41..5e2ac30b538f7130ec311f36a14fd95ced1bf912 100644
--- a/bigbluebutton-html5/imports/api/meetings/server/handlers/permissionSettingsChange.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/handlers/permissionSettingsChange.js
@@ -2,7 +2,7 @@ import { check } from 'meteor/check';
 import Logger from '/imports/startup/server/logger';
 import Meetings from '/imports/api/meetings';
 import { Meteor } from 'meteor/meteor';
-import handleLockingMic from '/imports/api/users/server/modifiers/handleLockingMic';
+import lockAllViewersMic from '/imports/api/users/server/modifiers/lockAllViewersMic';
 
 export default function handlePermissionSettingsChange({ payload }) {
   const meetingId = payload.meeting_id;
@@ -41,7 +41,7 @@ export default function handlePermissionSettingsChange({ payload }) {
     }
 
     if (permissions.disableMic) {
-      handleLockingMic(meetingId, permissions);
+      lockAllViewersMic(meetingId);
     }
 
     if (numChanged) {
diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
index fc450369a71dfd8c38653eeffd19b9425f801734..438cc4188f7bcf132402741cd2ecbf668060317c 100755
--- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
@@ -2,7 +2,7 @@ import Meetings from '/imports/api/chat';
 import Logger from '/imports/startup/server/logger';
 import removeMeeting from './removeMeeting';
 
-import { clearUsersCollection } from '/imports/api/users/server/modifiers/clearUsersCollection';
+import clearUsers from '/imports/api/users/server/modifiers/clearUsers';
 import clearChats from '/imports/api/chat/server/modifiers/clearChats';
 import clearBreakouts from '/imports/api/breakouts/server/modifiers/clearBreakouts';
 import clearShapes from '/imports/api/shapes/server/modifiers/clearShapes';
@@ -22,7 +22,7 @@ export default function clearMeetings() {
     clearPolls();
     clearShapes();
     clearSlides();
-    clearUsersCollection();
+    clearUsers();
 
     return Logger.info('Cleared Meetings (all)');
   });
diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
index 7db9212fce5e839ed1eedcc4c179c08ef0c8a0dd..79608307ad93f7bbd7eb5350127925e43ad0d610 100755
--- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
@@ -2,7 +2,7 @@ import { check } from 'meteor/check';
 import Meetings from '/imports/api/meetings';
 import Logger from '/imports/startup/server/logger';
 
-import { clearUsersCollection } from '/imports/api/users/server/modifiers/clearUsersCollection';
+import clearUsers from '/imports/api/users/server/modifiers/clearUsers';
 import clearChats from '/imports/api/chat/server/modifiers/clearChats';
 import clearShapes from '/imports/api/shapes/server/modifiers/clearShapes';
 import clearSlides from '/imports/api/slides/server/modifiers/clearSlides';
@@ -31,7 +31,7 @@ export default function removeMeeting(meetingId) {
       clearPolls(meetingId);
       clearShapes(meetingId);
       clearSlides(meetingId);
-      clearUsersCollection(meetingId);
+      clearUsers(meetingId);
 
       return Logger.info(`Removed meeting id=${meetingId}`);
     }
diff --git a/bigbluebutton-html5/imports/api/phone/index.js b/bigbluebutton-html5/imports/api/phone/index.js
index aff4fdbf8ec53e50b22aca8c0053b15849b1f7f8..05101454fb0894b0425e385d99b4d2c7c9dbe8ae 100755
--- a/bigbluebutton-html5/imports/api/phone/index.js
+++ b/bigbluebutton-html5/imports/api/phone/index.js
@@ -1,3 +1,4 @@
+// TODO: This file should be a `service.js` somewhere in the /ui folder
 import Users from '/imports/api/users';
 import Meetings from '/imports/api/meetings';
 import Auth from '/imports/ui/services/auth';
diff --git a/bigbluebutton-html5/imports/api/phone/server/getStun.js b/bigbluebutton-html5/imports/api/phone/server/getStun.js
deleted file mode 100755
index df624bfbd4db88c64e550c226c6936238b9599d0..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/phone/server/getStun.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader } from '/imports/api/common/server/helpers';
-import { logger } from '/imports/startup/server/logger';
-import Meetings from '/imports/api/meetings';
-
-export default function getStun(credentials) {
-  const REDIS_CONFIG = Meteor.settings.redis;
-  const { meetingId, requesterUserId } = credentials;
-  const eventName = 'send_stun_turn_info_request_message';
-
-  let message = {
-    payload: {
-      meeting_id: meetingId,
-      requester_id: requesterUserId,
-    },
-  };
-
-  message = appendMessageHeader(eventName, message);
-  return publish(REDIS_CONFIG.channels.fromBBBUsers, message);
-};
diff --git a/bigbluebutton-html5/imports/api/phone/server/modifiers/eventHandlers.js b/bigbluebutton-html5/imports/api/phone/server/modifiers/eventHandlers.js
deleted file mode 100755
index e0e2e815a80fa25f2b9b92aa0612d6a850e3770c..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/phone/server/modifiers/eventHandlers.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { eventEmitter } from '/imports/startup/server';
-import { updateVoiceUser } from '/imports/api/users/server/modifiers/updateVoiceUser';
-
-eventEmitter.on('user_left_voice_message', function (arg) {
-  handleVoiceEvent(arg);
-});
-
-eventEmitter.on('user_joined_voice_message', function (arg) {
-  handleVoiceEvent(arg);
-});
-
-eventEmitter.on('user_voice_talking_message', function (arg) {
-  handleVoiceEvent(arg);
-});
-
-eventEmitter.on('user_voice_muted_message', function (arg) {
-  handleVoiceEvent(arg);
-});
-
-eventEmitter.on('user_listening_only', function (arg) {
-  const voiceUserObj = {
-    web_userid: arg.payload.userid,
-    listen_only: arg.payload.listen_only,
-  };
-  const meetingId = arg.payload.meeting_id;
-  return updateVoiceUser(meetingId, voiceUserObj, arg.callback);
-});
-
-const handleVoiceEvent = function (arg) {
-  const meetingId = arg.payload.meeting_id;
-  const voiceUser = arg.payload.user.voiceUser;
-  const voiceUserObj = {
-    web_userid: voiceUser.web_userid,
-    listen_only: arg.payload.listen_only,
-    talking: voiceUser.talking,
-    joined: voiceUser.joined,
-    locked: voiceUser.locked,
-    muted: voiceUser.muted,
-  };
-  return updateVoiceUser(meetingId, voiceUserObj, arg.callback);
-};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
index 0b42afd2db713c7447a664ca502e4d6a6b797d7d..08e3fc9a2c9a59d447fa9caa2d4281e5a91632bd 100644
--- a/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
+++ b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
@@ -1,8 +1,10 @@
 import Logger from '/imports/startup/server/logger';
 import { check } from 'meteor/check';
 import { inReplyToHTML5Client } from '/imports/api/common/server/helpers';
+import Presentations from '/imports/api/presentations';
 
 import addPresentation from '../modifiers/addPresentation';
+import removePresentation from '../modifiers/removePresentation';
 
 export default function handlePresentationInfoReply({ payload }) {
   if (!inReplyToHTML5Client({ payload })) {
@@ -15,6 +17,14 @@ export default function handlePresentationInfoReply({ payload }) {
   check(meetingId, String);
   check(presentations, Array);
 
+  const presentationsIds = presentations.map(_ => _.id);
+  const presentationsToRemove = Presentations.find({
+    meetingId,
+    'presentation.id': { $nin: presentationsIds },
+  }).fetch();
+
+  presentationsToRemove.forEach(p => removePresentation(meetingId, p.presentation.id));
+
   let presentationsAdded = [];
   presentations.forEach(presentation => {
     presentationsAdded.push(addPresentation(meetingId, presentation));
diff --git a/bigbluebutton-html5/imports/api/shapes/server/handlers/whiteboardGetReply.js b/bigbluebutton-html5/imports/api/shapes/server/handlers/whiteboardGetReply.js
index 1fd567c3bef345b6f98b478037a08364a85ba533..815868b99edbdb5d28cd2a45d1072aaa3a13d2ed 100644
--- a/bigbluebutton-html5/imports/api/shapes/server/handlers/whiteboardGetReply.js
+++ b/bigbluebutton-html5/imports/api/shapes/server/handlers/whiteboardGetReply.js
@@ -1,8 +1,10 @@
 import Logger from '/imports/startup/server/logger';
 import { check } from 'meteor/check';
 import { inReplyToHTML5Client } from '/imports/api/common/server/helpers';
+import Shapes from '/imports/api/shapes';
 
 import addShape from '../modifiers/addShape';
+import removeShape from '../modifiers/removeShape';
 
 export default function handleWhiteboardGetReply({ payload }) {
   if (!inReplyToHTML5Client({ payload })) {
@@ -15,6 +17,14 @@ export default function handleWhiteboardGetReply({ payload }) {
   check(meetingId, String);
   check(shapes, Array);
 
+  const shapesIds = shapes.map(_ => _.id);
+  const shapesToRemove = Shapes.find({
+    meetingId,
+    'shape.id': { $nin: shapesIds },
+  }).fetch();
+
+  shapesToRemove.forEach(s => removeShape(meetingId, s.shape.wb_id, s.shape.id));
+
   let shapesAdded = [];
   shapes.forEach(shape => {
     let whiteboardId = shape.wb_id;
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
index a118987bb2a9b03687624620109d0de0137faf15..b14f9d5dc4a5684abbeea67ea52f358a5b325c8c 100755
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
@@ -65,8 +65,9 @@ export default function addSlide(meetingId, presentationId, slide) {
 
     const { insertedId } = numChanged;
 
+    requestWhiteboardHistory(meetingId, slide.id);
+
     if (insertedId) {
-      requestWhiteboardHistory(meetingId, slide.id);
       return Logger.info(`Added slide id=${slide.id} to presentation=${presentationId}`);
     }
 
diff --git a/bigbluebutton-html5/imports/api/users/server/eventHandlers.js b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js
new file mode 100644
index 0000000000000000000000000000000000000000..44d58558c49b3630d60365f25ab26706e0eee852
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js
@@ -0,0 +1,26 @@
+import RedisPubSub from '/imports/startup/server/redis';
+import handleGetUsers from './handlers/getUsers';
+import handleRemoveUser from './handlers/removeUser';
+import handlePresenterAssigned from './handlers/presenterAssigned';
+import handleEmojiStatus from './handlers/emojiStatus';
+import handleLockedStatusChange from './handlers/lockedStatusChange';
+import handleUserJoined from './handlers/userJoined';
+import handleValidateAuthToken from './handlers/validateAuthToken';
+import handleVoiceUpdate from './handlers/voiceUpdate';
+import handleListeningOnly from './handlers/listeningOnly';
+
+RedisPubSub.on('validate_auth_token_reply', handleValidateAuthToken);
+RedisPubSub.on('get_users_reply', handleGetUsers);
+RedisPubSub.on('user_joined_message', handleUserJoined);
+RedisPubSub.on('user_eject_from_meeting', handleRemoveUser);
+RedisPubSub.on('disconnect_user_message', handleRemoveUser);
+RedisPubSub.on('user_left_message', handleRemoveUser);
+RedisPubSub.on('presenter_assigned_message', handlePresenterAssigned);
+RedisPubSub.on('user_emoji_status_message', handleEmojiStatus);
+RedisPubSub.on('user_locked_message', handleLockedStatusChange);
+RedisPubSub.on('user_unlocked_message', handleLockedStatusChange);
+RedisPubSub.on('user_left_voice_message', handleVoiceUpdate);
+RedisPubSub.on('user_joined_voice_message', handleVoiceUpdate);
+RedisPubSub.on('user_voice_talking_message', handleVoiceUpdate);
+RedisPubSub.on('user_voice_muted_message', handleVoiceUpdate);
+RedisPubSub.on('user_listening_only', handleListeningOnly);
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/emojiStatus.js b/bigbluebutton-html5/imports/api/users/server/handlers/emojiStatus.js
new file mode 100644
index 0000000000000000000000000000000000000000..859687930464f64ceb331022f8a428769c7482a1
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/emojiStatus.js
@@ -0,0 +1,37 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+import Users from '/imports/api/users';
+
+export default function handleEmojiStatus({ payload }) {
+  const meetingId = payload.meeting_id;
+  const userId = payload.userid;
+  const status = payload.emoji_status;
+
+  check(meetingId, String);
+  check(userId, String);
+  check(status, String);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const modifier = {
+    $set: {
+      'user.set_emoji_time': (new Date()).getTime(),
+      'user.emoji_status': status,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Assigning user emoji status: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Assigned user emoji status '${status}' id=${userId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/getUsers.js b/bigbluebutton-html5/imports/api/users/server/handlers/getUsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..8fdbca484648027a6bfb46dd6d128f0472f5f734
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/getUsers.js
@@ -0,0 +1,35 @@
+import { check } from 'meteor/check';
+import { inReplyToHTML5Client } from '/imports/api/common/server/helpers';
+import Logger from '/imports/startup/server/logger';
+import Users from '/imports/api/users';
+
+import addUser from '../modifiers/addUser';
+import removeUser from '../modifiers/removeUser';
+
+export default function handleGetUsers({ payload }) {
+  if (!inReplyToHTML5Client({ payload })) {
+    return;
+  }
+
+  const meetingId = payload.meeting_id;
+  const users = payload.users;
+
+  check(meetingId, String);
+  check(users, Array);
+
+  const usersIds = users.map(m => m.userid);
+
+  const usersToRemove = Users.find({
+    meetingId,
+    userId: { $nin: usersIds },
+  }).fetch();
+
+  usersToRemove.forEach(user => removeUser(meetingId, user.userId));
+
+  let usersAdded = [];
+  users.forEach(user => {
+    usersAdded.push(addUser(meetingId, user));
+  });
+
+  return usersAdded;
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/listeningOnly.js b/bigbluebutton-html5/imports/api/users/server/handlers/listeningOnly.js
new file mode 100644
index 0000000000000000000000000000000000000000..0bc55db33d7d7579cb89f584169566032a7f938c
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/listeningOnly.js
@@ -0,0 +1,36 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+import Users from '/imports/api/users';
+
+export default function handleListeningOnly({ payload }) {
+  const meetingId = payload.meeting_id;
+  const userId = payload.userid;
+  const listenOnly = payload.listen_only;
+
+  check(meetingId, String);
+  check(userId, String);
+  check(listenOnly, Boolean);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const modifier = {
+    $set: {
+      'user.listenOnly': listenOnly,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Assigning user listen only status: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Assigned listen only status '${listenOnly}' user=${userId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/lockedStatusChange.js b/bigbluebutton-html5/imports/api/users/server/handlers/lockedStatusChange.js
new file mode 100644
index 0000000000000000000000000000000000000000..faeea50ecbad2b9dc153454d16c0e3996a824bdd
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/lockedStatusChange.js
@@ -0,0 +1,58 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+import Users from '/imports/api/users';
+
+import muteToggle from '../methods/muteToggle';
+
+export default function handleLockedStatusChange({ payload }) {
+  const meetingId = payload.meeting_id;
+  const userId = payload.userid;
+  const isLocked = arg.payload.locked;
+
+  check(meetingId, String);
+  check(userId, String);
+  check(isLocked, String);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const User = Users.findOne(selector);
+  if (!User) {
+    throw new Meteor.Error(
+      'user-not-found', `You need a valid user to be able to set presenter`);
+  }
+
+  const modifier = {
+    $set: {
+      'user.locked': isLocked,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Assigning user locked status: ${err}`);
+    }
+
+    if (numChanged) {
+      if (User.user.role === 'VIEWER'
+          && !User.user.listenOnly
+          && !User.user.voiceUser.muted
+          && User.user.voiceUser.joined
+          && isLocked) {
+
+        const credentials = {
+          meetingId,
+          requesterUserId: userId,
+        };
+
+        muteToggle(credentials, userId, true);
+      }
+
+      return Logger.info(`Assigned locked status '${isLocked ? 'locked' : 'unlocked'}' id=${newPresenterId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/presenterAssigned.js b/bigbluebutton-html5/imports/api/users/server/handlers/presenterAssigned.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d4e1fe652383d375f0c82a1e3c0dbb89359d4d9
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/presenterAssigned.js
@@ -0,0 +1,61 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+import Users from '/imports/api/users';
+
+export default function handlePresenterAssigned({ payload }) {
+  const meetingId = payload.meeting_id;
+  const newPresenterId = payload.new_presenter_id;
+
+  check(meetingId, String);
+  check(newPresenterId, String);
+
+  const selector = {
+    meetingId,
+    userId: newPresenterId,
+  };
+
+  const modifier = {
+    $set: {
+      'user.presenter': true,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Assigning user as presenter: ${err}`);
+    }
+
+    if (numChanged) {
+      unassignCurrentPresenter(meetingId, newPresenterId);
+      return Logger.info(`Assigned user as presenter id=${newPresenterId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
+
+const unassignCurrentPresenter = (meetingId, newPresenterId) => {
+  const selector = {
+    meetingId,
+    userId: { $ne: newPresenterId },
+    'user.presenter': true,
+  };
+
+  const modifier = {
+    $set: {
+      'user.presenter': false,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Unassigning current presenter from collection: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Unassign current presenter meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/removeUser.js b/bigbluebutton-html5/imports/api/users/server/handlers/removeUser.js
new file mode 100644
index 0000000000000000000000000000000000000000..a99e54cac78cd91c1aa3c8e9b3672f4559b6419c
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/removeUser.js
@@ -0,0 +1,14 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+
+import removeUser from '../modifiers/removeUser';
+
+export default function handleRemoveUser({ payload }) {
+  const meetingId = payload.meeting_id;
+  const userId = payload.userid || payload.user.userid;
+
+  check(meetingId, String);
+  check(userId, String);
+
+  return removeUser(meetingId, userId);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/userJoined.js b/bigbluebutton-html5/imports/api/users/server/handlers/userJoined.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ab2b64f85f57870d4d585e0e1b894a3cacfb084
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/userJoined.js
@@ -0,0 +1,14 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+
+import addUser from '../modifiers/addUser';
+
+export default function handleUserJoined({ payload }) {
+  const meetingId = payload.meeting_id;
+  const user = payload.user;
+
+  check(meetingId, String);
+  check(user, Object);
+
+  return addUser(meetingId, user);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/validateAuthToken.js b/bigbluebutton-html5/imports/api/users/server/handlers/validateAuthToken.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a50aa0b398789fd64ac14347416bb56e0c5d853
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/validateAuthToken.js
@@ -0,0 +1,77 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+import Meetings from '/imports/api/meetings';
+import Users from '/imports/api/users';
+
+import addChat from '/imports/api/chat/server/modifiers/addChat';
+
+export default function handleValidateAuthToken({ payload }) {
+  const meetingId = payload.meeting_id;
+  const userId = payload.userid;
+  const validStatus = payload.valid;
+
+  check(meetingId, String);
+  check(userId, String);
+  check(validStatus, String);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const User = Users.findOne(selector);
+
+  if (!User) {
+    throw new Meteor.Error(
+      'user-not-found', `You need a valid user to be able validate the token`);
+  }
+
+  if (User.validated === validStatus) {
+    return;
+  }
+
+  const modifier = {
+    $set: {
+      validated: validStatus,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Validating auth token: ${err}`);
+    }
+
+    if (numChanged) {
+      if (validStatus) {
+        addWelcomeChatMessage(meetingId, userId);
+      }
+
+      return Logger.info(`Validated auth token as '${validStatus}' user=${userId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
+
+const addWelcomeChatMessage = (meetingId, userId) => {
+  const APP_CONFIG = Meteor.settings.public.app;
+  const CHAT_CONFIG = Meteor.settings.public.chat;
+
+  const Meeting = Meetings.findOne({ meetingId });
+
+  let welcomeMessage = APP_CONFIG.defaultWelcomeMessage
+      .concat(APP_CONFIG.defaultWelcomeMessageFooter)
+      .replace(/%%CONFNAME%%/, Meeting.meetingName);
+
+  const message = {
+    chat_type: CHAT_CONFIG.type_system,
+    message: welcomeMessage,
+    from_color: '0x3399FF',
+    to_userid: userId,
+    from_userid: CHAT_CONFIG.type_system,
+    from_username: '',
+    from_time: (new Date()).getTime(),
+  };
+
+  return addChat(meetingId, message);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/voiceUpdate.js b/bigbluebutton-html5/imports/api/users/server/handlers/voiceUpdate.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab4e8c51711e150aac48b060900f0e8f7b9d413c
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/handlers/voiceUpdate.js
@@ -0,0 +1,20 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+
+import updateVoiceUser from '../modifiers/updateVoiceUser';
+
+export default function handleVoiceUpdate({ payload }) {
+  const meetingId = payload.meeting_id;
+  const user = payload.user;
+
+  check(meetingId, String);
+  check(user, Object);
+
+  const voiceUser = user.voiceUser;
+  check(voiceUser, Object);
+
+  const userId = voiceUser.web_userid;
+  check(userId, String);
+
+  return updateVoiceUser(meetingId, userId, voiceUser);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/index.js b/bigbluebutton-html5/imports/api/users/server/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..92451ac76bf27410726e8f3cd2eebac46cd7b83e
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/index.js
@@ -0,0 +1,3 @@
+import './eventHandlers';
+import './methods';
+import './publishers';
diff --git a/bigbluebutton-html5/imports/api/users/server/methods.js b/bigbluebutton-html5/imports/api/users/server/methods.js
new file mode 100644
index 0000000000000000000000000000000000000000..fea522f81e68a5f0f451a09cb4cf45480f1d07ec
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods.js
@@ -0,0 +1,17 @@
+import { Meteor } from 'meteor/meteor';
+import kickUser from './methods/kickUser';
+import listenOnlyToggle from './methods/listenOnlyToggle';
+import userLogout from './methods/userLogout';
+import assignPresenter from './methods/assignPresenter';
+import muteToggle from './methods/muteToggle';
+import setEmojiStatus from './methods/setEmojiStatus';
+
+Meteor.methods({
+  kickUser,
+  listenOnlyToggle,
+  userLogout,
+  assignPresenter,
+  setEmojiStatus,
+  muteUser: (...args) => muteToggle(...args, true),
+  unmuteUser: (...args) => muteToggle(...args, false),
+});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/assignPresenter.js b/bigbluebutton-html5/imports/api/users/server/methods/assignPresenter.js
new file mode 100755
index 0000000000000000000000000000000000000000..3f873ee646e09444f5acbb503539f68b174800a7
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/assignPresenter.js
@@ -0,0 +1,42 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+import Users from '/imports/api/users';
+
+export default function assignPresenter(credentials, userId) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.users;
+  const EVENT_NAME = 'assign_presenter_request_message';
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(userId, String);
+
+  if (!isAllowedTo('setPresenter', credentials)) {
+    throw new Meteor.Error('not-allowed', `You are not allowed to setPresenter`);
+  }
+
+  const User = Users.findOne({
+    meetingId,
+    userId,
+  });
+  if (!User) {
+    throw new Meteor.Error(
+      'user-not-found', `You need a valid user to be able to set presenter`);
+  }
+
+  let payload = {
+    new_presenter_id: userId,
+    new_presenter_name: User.user.name,
+    meeting_id: meetingId,
+    assigned_by: requesterUserId,
+  };
+
+  Logger.verbose(`User '${userId}' setted as presenter by '${requesterUserId}' from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js b/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js
index 103104a388c3c4cef25eafe982e22cf089c982d9..86f189f8a562500544de2dba93216e7e4b27f75b 100755
--- a/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js
+++ b/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js
@@ -1,25 +1,31 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
 import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader, publish } from '/imports/api/common/server/helpers';
 
-Meteor.methods({
-  //meetingId: the meeting where the user is
-  //toKickUserId: the userid of the user to kick
-  //requesterUserId: the userid of the user that wants to kick
-  //authToken: the authToken of the user that wants to kick
-  kickUser(credentials, toKickUserId) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    let message;
-    if (isAllowedTo('kickUser', credentials)) {
-      message = {
-        payload: {
-          userid: toKickUserId,
-          ejected_by: requesterUserId,
-          meeting_id: meetingId,
-        },
-      };
-      message = appendMessageHeader('eject_user_from_meeting_request_message', message);
-      return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-    }
-  },
-});
+export default function kickUser(credentials, userId) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.users;
+  const EVENT_NAME = 'eject_user_from_meeting_request_message';
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(userId, String);
+
+  if (!isAllowedTo('kickUser', credentials)) {
+    throw new Meteor.Error('not-allowed', `You are not allowed to kickUser`);
+  }
+
+  let payload = {
+    userid: userId,
+    ejected_by: requesterUserId,
+    meeting_id: meetingId,
+  };
+
+  Logger.verbose(`User '${userId}' was kicked by '${requesterUserId}' from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js b/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js
deleted file mode 100755
index 55a19f156ebc397d6d337e046534f29f2bc25e4f..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader, publish } from '/imports/api/common/server/helpers';
-import Meetings from '/imports/api/meetings';
-import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
-
-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(credentials, isJoining) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    let username;
-    let voiceConf;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    const meetingObject = Meetings.findOne({
-      meetingId: meetingId,
-    });
-    const userObject = Users.findOne({
-      meetingId: meetingId,
-      userId: requesterUserId,
-    });
-
-    if (meetingObject != null) {
-      voiceConf = meetingObject.voiceConf;
-    }
-
-    if (userObject != null) {
-      username = userObject.user.name;
-    }
-
-    if (isJoining) {
-      if (isAllowedTo('joinListenOnly', credentials)) {
-        let message = {
-          payload: {
-            userid: requesterUserId,
-            meeting_id: meetingId,
-            voice_conf: voiceConf,
-            name: username,
-          },
-        };
-        message = appendMessageHeader('user_connected_to_global_audio', message);
-        logger.info(
-          `publishing a user listenOnly toggleRequest ${isJoining} ` +
-          `request for ${requesterUserId}`
-        );
-        publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
-      }
-    } else {
-      if (isAllowedTo('leaveListenOnly', credentials)) {
-        let message = {
-          payload: {
-            userid: requesterUserId,
-            meeting_id: meetingId,
-            voice_conf: voiceConf,
-            name: username,
-          },
-        };
-        message = appendMessageHeader('user_disconnected_from_global_audio', message);
-        logger.info(
-          `publishing a user listenOnly toggleRequest ${isJoining} ` +
-          `request for ${requesterUserId}`
-        );
-        publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
-      }
-    }
-  },
-
-});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyToggle.js b/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyToggle.js
new file mode 100755
index 0000000000000000000000000000000000000000..6bbc5237a12874aba257e8ca988ba73d895eb1fd
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyToggle.js
@@ -0,0 +1,60 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+import Meetings from '/imports/api/meetings';
+import Users from '/imports/api/users';
+
+export default function listenOnlyToggle(credentials, isJoining = true) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.meeting;
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(isJoining, Boolean);
+
+  if (isJoining) {
+    let EVENT_NAME = 'user_connected_to_global_audio';
+    if (!isAllowedTo('joinListenOnly', credentials)) {
+      throw new Meteor.Error('not-allowed', `You are not allowed to joinListenOnly`);
+    }
+  } else {
+    let EVENT_NAME = 'user_disconnected_from_global_audio';
+    if (!isAllowedTo('leaveListenOnly', credentials)) {
+      throw new Meteor.Error('not-allowed', `You are not allowed to leaveListenOnly`);
+    }
+  }
+
+  const Metting = Meetings.findOne({ meetingId });
+  if (!Metting) {
+    throw new Meteor.Error(
+      'metting-not-found', `You need a valid meeting to be able to toggle audio`);
+  }
+
+  check(Metting.voiceConf, String);
+
+  const User = Users.findOne({
+    meetingId,
+    userId: requesterUserId,
+  });
+  if (!User) {
+    throw new Meteor.Error(
+      'user-not-found', `You need a valid user to be able to toggle audio`);
+  }
+
+  check(User.user.name, String);
+
+  let payload = {
+    userid: requesterUserId,
+    meeting_id: meetingId,
+    voice_conf: Metting.voiceConf,
+    name: User.user.name,
+  };
+
+  Logger.verbose(`User '${requesterUserId}' ${isJoining ? 'joined' : 'left'} global audio from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/muteToggle.js b/bigbluebutton-html5/imports/api/users/server/methods/muteToggle.js
new file mode 100755
index 0000000000000000000000000000000000000000..03b3a1860c801da03fc46a0f94b1376ce0c25c96
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/muteToggle.js
@@ -0,0 +1,38 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+
+export default function muteToggle(credentials, userId, isMuted = true) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.users;
+  const EVENT_NAME = 'mute_user_request_message';
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(userId, String);
+
+  let action = userId === requesterUserId ? 'muteSelf' : 'muteOther';
+
+  if (!isMuted) {
+    action = `un${action}`;
+  }
+
+  if (!isAllowedTo(action, credentials)) {
+    throw new Meteor.Error('not-allowed', `You are not allowed to ${action}`);
+  }
+
+  let payload = {
+    user_id: userId,
+    meeting_id: meetingId,
+    mute: isMuted,
+    requester_id: requesterUserId,
+  };
+
+  Logger.verbose(`User '${userId}' was ${!isMuted ? 'un' : ''}muted by '${requesterUserId}' from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/muteUser.js b/bigbluebutton-html5/imports/api/users/server/methods/muteUser.js
deleted file mode 100755
index 72591a0b3b135f82e801ba7afbfdeec151de4ffa..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/methods/muteUser.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader } from '/imports/api/common/server/helpers';
-import { updateVoiceUser } from '/imports/api/users/server/modifiers/updateVoiceUser';
-import { logger } from '/imports/startup/server/logger';
-
-Meteor.methods({
-  // meetingId: the meetingId of the meeting the user[s] is in
-  // toMuteUserId: the userId of the user to be muted
-  // requesterUserId: the userId of the requester
-  // requesterToken: the authToken of the requester
-  muteUser(credentials, toMuteUserId) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    const action = function () {
-      if (toMuteUserId === requesterUserId) {
-        return 'muteSelf';
-      } else {
-        return 'muteOther';
-      }
-    };
-
-    if (isAllowedTo(action(), credentials)) {
-      let message = {
-        payload: {
-          user_id: toMuteUserId,
-          meeting_id: meetingId,
-          mute: true,
-          requester_id: requesterUserId,
-        },
-      };
-      message = appendMessageHeader('mute_user_request_message', message);
-      logger.info(`publishing a user mute request for ${toMuteUserId}`);
-      publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-      updateVoiceUser(meetingId, {
-        web_userid: toMuteUserId,
-        talking: false,
-        muted: true,
-      });
-    }
-  },
-});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/requestStunTurn.js b/bigbluebutton-html5/imports/api/users/server/methods/requestStunTurn.js
new file mode 100644
index 0000000000000000000000000000000000000000..6558d2692f927d12a9db4d100a2904990323ef8d
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/requestStunTurn.js
@@ -0,0 +1,22 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+
+export default function requestStunTurn(meetingId, requesterUserId) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.fromBBBUsers;
+  const EVENT_NAME = 'send_stun_turn_info_request_message';
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+
+  let payload = {
+    meeting_id: meetingId,
+    requester_id: requesterUserId,
+  };
+
+  Logger.verbose(`User '${requesterUserId}' requested stun/turn from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/setEmojiStatus.js b/bigbluebutton-html5/imports/api/users/server/methods/setEmojiStatus.js
new file mode 100755
index 0000000000000000000000000000000000000000..7bbb8e6516b037b42fd830136881b65cd767fd85
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/setEmojiStatus.js
@@ -0,0 +1,31 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+
+export default function setEmojiStatus(credentials, userId, status) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.users;
+  const EVENT_NAME = 'user_emoji_status_message';
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(userId, String);
+
+  if (!isAllowedTo('setEmojiStatus', credentials)) {
+    throw new Meteor.Error('not-allowed', `You are not allowed to setEmojiStatus`);
+  }
+
+  let payload = {
+    emoji_status: status,
+    userid: userId,
+    meeting_id: meetingId,
+  };
+
+  Logger.verbose(`User '${userId}' emoji status updated to '${status}' by '${requesterUserId}' from meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/setUserPresenter.js b/bigbluebutton-html5/imports/api/users/server/methods/setUserPresenter.js
deleted file mode 100755
index 220d542f60c585ea38ca6e605278de09626bbdb6..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/methods/setUserPresenter.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader } from '/imports/api/common/server/helpers';
-
-Meteor.methods({
-  //meetingId: the meeting where the user is
-  //newPresenterId: the userid of the new presenter
-  //requesterUserId: the userid of the user that wants to change the presenter
-  //newPresenterName: user name of the new presenter
-  //authToken: the authToken of the user that wants to kick
-  setUserPresenter(
-    credentials,
-    newPresenterId,
-    newPresenterName) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId } = credentials;
-    let message;
-    if (isAllowedTo('setPresenter', credentials)) {
-      message = {
-        payload: {
-          new_presenter_id: newPresenterId,
-          new_presenter_name: newPresenterName,
-          meeting_id: meetingId,
-          assigned_by: requesterUserId,
-        },
-      };
-
-      message = appendMessageHeader('assign_presenter_request_message', message);
-      return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-    }
-  },
-});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/unmuteUser.js b/bigbluebutton-html5/imports/api/users/server/methods/unmuteUser.js
deleted file mode 100755
index c9d8800bace6a6338d072a994b53910d823350fd..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/methods/unmuteUser.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader } from '/imports/api/common/server/helpers';
-import { updateVoiceUser } from '/imports/api/users/server/modifiers/updateVoiceUser';
-import { logger } from '/imports/startup/server/logger';
-
-Meteor.methods({
-  // meetingId: the meetingId of the meeting the user[s] is in
-  // toMuteUserId: the userId of the user to be unmuted
-  // requesterUserId: the userId of the requester
-  // requesterToken: the authToken of the requester
-  unmuteUser(credentials, toMuteUserId) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    const action = function () {
-      if (toMuteUserId === requesterUserId) {
-        return 'unmuteSelf';
-      } else {
-        return 'unmuteOther';
-      }
-    };
-
-    if (isAllowedTo(action(), credentials)) {
-      let message = {
-        payload: {
-          user_id: toMuteUserId,
-          meeting_id: meetingId,
-          mute: false,
-          requester_id: requesterUserId,
-        },
-      };
-      message = appendMessageHeader('mute_user_request_message', message);
-      logger.info(`publishing a user unmute request for ${toMuteUserId}`);
-      publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-      updateVoiceUser(meetingId, {
-        web_userid: toMuteUserId,
-        talking: false,
-        muted: false,
-      });
-    }
-  },
-});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js b/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca961ab9c96ff6392144bb65284c3a18b9309b40
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js
@@ -0,0 +1,48 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+import Users from '/imports/api/users';
+
+import setConnectionStatus from '../modifiers/setConnectionStatus';
+import listenOnlyToggle from './listenOnlyToggle';
+
+const OFFLINE_CONNECTION_STATUS = 'offline';
+
+export default function userLeaving(credentials, userId) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.users;
+  const EVENT_NAME = 'user_leaving_request';
+
+  const { meetingId, requesterUserId } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(userId, String);
+
+  const User = Users.findOne({
+    meetingId,
+    userId,
+  });
+  if (!User) {
+    throw new Meteor.Error(
+      'user-not-found', `You need a valid user to be able to toggle audio`);
+  }
+
+  if (User.user.connection_status === OFFLINE_CONNECTION_STATUS) {
+    return;
+  }
+
+  if (User.user.listenOnly) {
+    listenOnlyToggle(credentials, false);
+  }
+
+  let payload = {
+    meeting_id: meetingId,
+    userid: userId,
+  };
+
+  Logger.verbose(`User '${requesterUserId}' left meeting '${meetingId}'`);
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js b/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js
index da8d5378ef963be09991f450dd97d1b2a9fca75e..4aeb73bed100d2ab3158da7bc34618eab9d76ebc 100755
--- a/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js
+++ b/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js
@@ -1,13 +1,14 @@
+import { Meteor } from 'meteor/meteor';
 import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { requestUserLeaving } from '/imports/api/users/server/modifiers/requestUserLeaving';
-import { logger } from '/imports/startup/server/logger';
-
-Meteor.methods({
-  userLogout(credentials) {
-    if (isAllowedTo('logoutSelf', credentials)) {
-      const { meetingId, requesterUserId, requesterToken } = credentials;
-      logger.info(`a user is logging out from ${meetingId}:${requesterUserId}`);
-      return requestUserLeaving(meetingId, requesterUserId);
-    }
-  },
-});
+
+import userLeaving from './userLeaving';
+
+export default function userLogout(credentials) {
+  if (!isAllowedTo('logoutSelf', credentials)) {
+    throw new Meteor.Error('not-allowed', `You are not allowed to logoutSelf`);
+  }
+
+  const { requesterUserId } = credentials;
+
+  return userLeaving(credentials, requesterUserId);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/userSetEmoji.js b/bigbluebutton-html5/imports/api/users/server/methods/userSetEmoji.js
deleted file mode 100755
index 2a4f8778801a74815aaccaf9a737fc066844efd6..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/methods/userSetEmoji.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { appendMessageHeader } from '/imports/api/common/server/helpers';
-
-Meteor.methods({
-  userSetEmoji(credentials, toRaiseUserId, status) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    let message;
-    if (isAllowedTo('setEmojiStatus', credentials)) {
-      message = {
-        payload: {
-          emoji_status: status,
-          userid: toRaiseUserId,
-          meeting_id: meetingId,
-        },
-      };
-
-      message = appendMessageHeader('user_emoji_status_message', message);
-
-      // publish to pubsub
-      publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-    }
-  },
-});
diff --git a/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js b/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js
index 0ceda1f59dbed39220e80315b167eab1b7f27091..0e3146a91ebc00324fea0c7b4722998434629d0c 100755
--- a/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js
+++ b/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js
@@ -1,34 +1,48 @@
-import { logger } from '/imports/startup/server/logger';
-import { createDummyUser } from '/imports/api/users/server/modifiers/createDummyUser';
-import { publish } from '/imports/api/common/server/helpers';
-
-Meteor.methods({
-  // Construct and send a message to bbb-web to validate the user
-  validateAuthToken(credentials) {
-    const REDIS_CONFIG = Meteor.settings.redis;
-    const { meetingId, requesterUserId, requesterToken } = credentials;
-    logger.info('sending a validate_auth_token with', {
-      userid: requesterUserId,
-      authToken: requesterToken,
-      meetingid: meetingId,
-    });
-    let message = {
-      payload: {
-        auth_token: requesterToken,
-        userid: requesterUserId,
-        meeting_id: meetingId,
-      },
-      header: {
-        timestamp: new Date().getTime(),
-        reply_to: `${meetingId}/${requesterUserId}`,
-        name: 'validate_auth_token',
-      },
-    };
-    if ((requesterToken != null) && (requesterUserId != null) && (meetingId != null)) {
-      createDummyUser(meetingId, requesterUserId, requesterToken);
-      return publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
-    } else {
-      return logger.info('did not have enough information to send a validate_auth_token message');
-    }
-  },
-});
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+import Users from '/imports/api/users';
+
+import createDummyUser from '../modifiers/createDummyUser';
+import setConnectionStatus from '../modifiers/setConnectionStatus';
+
+const ONLINE_CONNECTION_STATUS = 'online';
+
+export default function validateAuthToken(credentials) {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.meeting;
+  const EVENT_NAME = 'validate_auth_token';
+
+  const { meetingId, requesterUserId, requesterToken } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(requesterToken, String);
+
+  const User = Users.findOne({
+    meetingId,
+    userId: requesterUserId,
+  });
+
+  if (!User) {
+    createDummyUser(meetingId, requesterUserId, requesterToken);
+  } else if (User.validated) {
+    setConnectionStatus(meetingId, requesterUserId, ONLINE_CONNECTION_STATUS);
+  }
+
+  let payload = {
+    auth_token: requesterToken,
+    userid: requesterUserId,
+    meeting_id: meetingId,
+  };
+
+  const header = {
+    reply_to: `${meetingId}/${requesterUserId}`,
+  };
+
+  Logger.verbose(`User '${requesterUserId}' is trying to validate auth token for meeting '${meetingId}'`);
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload, header);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js
new file mode 100644
index 0000000000000000000000000000000000000000..c26210ef85e09001e9ccadd90e28d5a653d6eb75
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js
@@ -0,0 +1,71 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+
+import Meetings from '/imports/api/meetings';
+import Users from '/imports/api/users';
+
+import requestStunTurn from '../methods/requestStunTurn';
+
+export default function addUser(meetingId, user) {
+  check(user, Object);
+  check(meetingId, String);
+
+  const userId = user.userid;
+  check(userId, String);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const modifier = {
+    $set: {
+      meetingId,
+      userId,
+      'user.connection_status': 'online',
+      'user.userid': userId,
+      'user.extern_userid': user.extern_userid,
+      'user.role': user.role,
+      'user.name': user.name,
+      'user._sort_name': user.name.trim().toLowerCase(),
+      'user.avatarURL': user.avatarURL,
+      'user.set_emoji_time': user.set_emoji_time || (new Date()).getTime(),
+      'user.time_of_joining': (new Date()).getTime(),
+      'user.emoji_status': user.emoji_status,
+      'user.webcam_stream': user.webcam_stream,
+      'user.presenter': user.presenter,
+      'user.locked': user.locked,
+      'user.phone_user': user.phone_user,
+      'user.listenOnly': user.listenOnly,
+      'user.has_stream': user.has_stream,
+      'user.voiceUser.web_userid': user.voiceUser.web_userid,
+      'user.voiceUser.callernum': user.voiceUser.callernum,
+      'user.voiceUser.userid': user.voiceUser.userid,
+      'user.voiceUser.talking': user.voiceUser.talking,
+      'user.voiceUser.joined': user.voiceUser.joined,
+      'user.voiceUser.callername': user.voiceUser.callername,
+      'user.voiceUser.locked': user.voiceUser.locked,
+      'user.voiceUser.muted': user.voiceUser.muted,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Adding user to collection: ${err}`);
+    }
+
+    // TODO: Do we really need to request the stun/turn everytime?
+    requestStunTurn(meetingId, userId);
+
+    const { insertedId } = numChanged;
+    if (insertedId) {
+      return Logger.info(`Added user id=${userId} meeting=${meetingId}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Upserted user id=${userId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.upsert(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsers.js b/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsers.js
new file mode 100755
index 0000000000000000000000000000000000000000..6a37f791d418e7cfb59df37c80ed25f8d71a0dad
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsers.js
@@ -0,0 +1,10 @@
+import Users from '/imports/api/users';
+import Logger from '/imports/startup/server/logger';
+
+export default function clearUsers(meetingId) {
+  if (meetingId) {
+    return Users.remove({ meetingId }, Logger.info(`Cleared Users (${meetingId})`));
+  }
+
+  return Users.remove({}, Logger.info('Cleared Users (all)'));
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsersCollection.js b/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsersCollection.js
deleted file mode 100755
index ba64b345bcd1b9a82b82d56cd0be6c0f9c25335b..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/clearUsersCollection.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
-
-// called on server start and on meeting end
-export function clearUsersCollection() {
-  const meetingId = arguments[0];
-  if (meetingId != null) {
-    return Users.remove({
-      meetingId: meetingId,
-    }, err => {
-      if (err != null) {
-        return logger.error(`_error ${JSON.stringify(err)} while removing users from ${meetingId}`);
-      } else {
-        return logger.info(`_cleared Users Collection (meetingId: ${meetingId})!`);
-      }
-    });
-  } else {
-    return Users.remove({}, err => {
-      if (err != null) {
-        return logger.error(`_error ${JSON.stringify(err)} while removing users from all meetings`);
-      } else {
-        return logger.info('_cleared Users Collection (all meetings)!');
-      }
-    });
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js
index e8b5d7cb1f1ec20fb13620e6d97f31b5943994ca..13aa0b1c5a1547f5b5a08ed550ca835ba65cd259 100755
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js
@@ -1,24 +1,33 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
 import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
 
-export function createDummyUser(meetingId, userId, authToken) {
-  if (Users.findOne({
-    userId: userId,
-    meetingId: meetingId,
-    authToken: authToken,
-  }) != null) {
-    const msg = `html5 user userId:[${userId}] from [${meetingId}] tried to revalidate token`;
-    return logger.info(msg);
-  } else {
-    return Users.insert({
-      meetingId: meetingId,
-      userId: userId,
-      authToken: authToken,
-      clientType: 'HTML5',
-      validated: false, //will be validated on validate_auth_token_reply
-    }, (err, id) => {
-      const res = Users.find({ meetingId: meetingId, }).count();
-      return logger.info(`_added a dummy html5 user userId=[${userId}] Users.size is now ${res}`);
-    });
+export default function createDummyUser(meetingId, userId, authToken) {
+  check(meetingId, String);
+  check(userId, String);
+  check(authToken, String);
+
+  const User = Users.findOne({ meetingId, userId });
+  if (User) {
+    throw new Meteor.Error('existing-user', `Tried to create a dummy user for an existing user`);
   }
+
+  const doc = {
+    meetingId,
+    userId,
+    authToken,
+    clientType: 'HTML5',
+    validated: false,
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Creating dummy user to collection: ${err}`);
+    }
+
+    return Logger.info(`Created dummy user id=${userId} token=${authToken} meeting=${meetingId}`);
+  };
+
+  return Users.insert(doc, cb);
 };
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/eventHandlers.js b/bigbluebutton-html5/imports/api/users/server/modifiers/eventHandlers.js
deleted file mode 100755
index b23227ffdf4e5bbbcff6775049fc07036f929197..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/eventHandlers.js
+++ /dev/null
@@ -1,212 +0,0 @@
-import { logger } from '/imports/startup/server/logger';
-import { eventEmitter } from '/imports/startup/server';
-import { userJoined } from './userJoined';
-import { setUserLockedStatus } from './setUserLockedStatus';
-import { markUserOffline } from './markUserOffline';
-import { inReplyToHTML5Client } from '/imports/api/common/server/helpers';
-import Users from '../..';
-
-eventEmitter.on('user_eject_from_meeting', function (arg) {
-  handleRemoveUserEvent(arg);
-});
-
-eventEmitter.on('disconnect_user_message', function (arg) {
-  handleRemoveUserEvent(arg);
-});
-
-eventEmitter.on('user_left_message', function (arg) {
-  handleRemoveUserEvent(arg);
-});
-
-eventEmitter.on('validate_auth_token_reply', function (arg) {
-  const meetingId = arg.payload.meeting_id;
-  const userId = arg.payload.userid;
-  const user = Users.findOne({
-    userId: userId,
-    meetingId: meetingId,
-  });
-  const validStatus = arg.payload.valid;
-
-  // if the user already exists in the db
-  if (user != null && user.clientType === 'HTML5') {
-    //if the html5 client user was validated successfully, add a flag
-    return Users.update({
-      userId: userId,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        validated: validStatus,
-      },
-    }, (err, numChanged) => {
-      if (numChanged.insertedId != null) {
-        let funct = function (cbk) {
-          let user = Users.findOne({
-            userId: userId,
-            meetingId: meetingId,
-          });
-          let val;
-          if (user != null) {
-            val = user.validated;
-          }
-
-          logger.info(`user.validated for ${userId} in meeting ${meetingId} just became ${val}`);
-          return cbk();
-        };
-
-        return funct(arg.callback);
-      } else {
-        return arg.callback();
-      }
-    });
-  } else {
-    logger.info('a non-html5 user got validate_auth_token_reply.');
-    return arg.callback();
-  }
-});
-
-eventEmitter.on('user_joined_message', function (arg) {
-  const meetingId = arg.payload.meeting_id;
-  const payload = arg.payload;
-  let userObj = payload.user;
-  let dbUser = Users.findOne({
-    userId: userObj.userid,
-    meetingId: meetingId,
-  });
-
-  // On attempting reconnection of Flash clients (in voiceBridge) we receive
-  // an extra user_joined_message. Ignore it as it will add an extra user
-  // in the user list, creating discrepancy with the list in the Flash client
-  if (dbUser != null && dbUser.user != null && dbUser.user.connection_status === 'offline') {
-    if (payload.user != null && payload.user.phone_user) {
-      logger.error('offline AND phone user');
-      return arg.callback(); //return without joining the user
-    }
-  } else {
-    if (dbUser != null && dbUser.clientType === 'HTML5') {
-      // typically html5 users will be in
-      // the db [as a dummy user] before the joining message
-      let status = dbUser.validated;
-      logger.info(`in user_joined_message the validStatus of the user was ${status}`);
-      userObj.timeOfJoining = arg.header.current_time;
-    }
-
-    return userJoined(meetingId, userObj, arg.callback);
-  }
-
-  return arg.callback();
-});
-
-eventEmitter.on('get_users_reply', function (arg) {
-  if (inReplyToHTML5Client(arg)) {
-    let users = arg.payload.users;
-    const meetingId = arg.payload.meeting_id;
-
-    //TODO make the serialization be split per meeting. This will allow us to
-    // use N threads vs 1 and we'll take advantage of Mongo's concurrency tricks
-
-    // Processing the users recursively with a callback to notify us,
-    // ensuring that we update the users collection serially
-    let processUser = function () {
-      let user = users.pop();
-      if (user != null) {
-        user.timeOfJoining = arg.header.current_time;
-        if (user.emoji_status !== 'none' && typeof user.emoji_status === 'string') {
-          user.set_emoji_time = new Date();
-          return userJoined(meetingId, user, processUser);
-        } else {
-          return userJoined(meetingId, user, processUser);
-        }
-      } else {
-        return arg.callback(); // all meeting arrays (if any) have been processed
-      }
-    };
-
-    return processUser();
-  } else {
-    arg.callback();
-  }
-});
-
-eventEmitter.on('user_emoji_status_message', function (arg) {
-  const userId = arg.payload.userid;
-  const meetingId = arg.payload.meeting_id;
-  const emojiStatus = arg.payload.emoji_status;
-  if (userId != null && meetingId != null) {
-    const setEmojiTime = new Date();
-    Users.update({
-      'user.userid': userId,
-    }, {
-      $set: {
-        'user.set_emoji_time': setEmojiTime,
-        'user.emoji_status': emojiStatus,
-      },
-    }, (err, numUpdated) => logger.info(`Updating emoji numUpdated=${numUpdated}, err=${err}`));
-  }
-
-  return arg.callback();
-});
-
-eventEmitter.on('user_locked_message', function (arg) {
-  handleLockEvent(arg);
-});
-
-eventEmitter.on('user_unlocked_message', function (arg) {
-  handleLockEvent(arg);
-});
-
-eventEmitter.on('presenter_assigned_message', function (arg) {
-  const meetingId = arg.payload.meeting_id;
-  const newPresenterId = arg.payload.new_presenter_id;
-  if (newPresenterId != null) {
-    // reset the previous presenter
-    Users.update({
-      'user.presenter': true,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        'user.presenter': false,
-      },
-    }, (err, numUpdated) => logger.info(
-      ` Updating old presenter numUpdated=${numUpdated}, ` +
-      ` err=${err}`
-      )
-    );
-
-    // set the new presenter
-    Users.update({
-      'user.userid': newPresenterId,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        'user.presenter': true,
-      },
-    }, (err, numUpdated) => logger.info(
-      ` Updating new presenter numUpdated=${numUpdated}, ` +
-      `err=${err}`
-      )
-    );
-  }
-
-  return arg.callback();
-});
-
-const handleRemoveUserEvent = function (arg) {
-  const { payload, callback } = arg;
-  if ((payload.userid || payload.user.userid) &&
-    payload.meeting_id) {
-    const meetingId = payload.meeting_id;
-    const userId = payload.userid || payload.user.userid;
-    return markUserOffline(meetingId, userId, callback);
-  } else {
-    logger.info('could not perform handleRemoveUserEvent');
-    return callback();
-  }
-};
-
-const handleLockEvent = function (arg) {
-  const userId = arg.payload.userid;
-  const isLocked = arg.payload.locked;
-  const meetingId = arg.payload.meeting_id;
-  setUserLockedStatus(meetingId, userId, isLocked);
-  return arg.callback();
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/handleLockingMic.js b/bigbluebutton-html5/imports/api/users/server/modifiers/handleLockingMic.js
deleted file mode 100755
index 2e211c8b6cc1814bf7b69904b6190d190c27ede4..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/handleLockingMic.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import Users from '/imports/api/users';
-
-// when new lock settings including disableMic are set,
-// all viewers that are in the audio bridge with a mic should be muted and locked
-export default function handleLockingMic(meetingId, newSettings) {
-  // send mute requests for the viewer users joined with mic
-  let userObject;
-  let results = [];
-  const userObjects = Users.find({
-    meetingId: meetingId,
-    'user.role': 'VIEWER',
-    'user.listenOnly': false,
-    'user.locked': true,
-    'user.voiceUser.joined': true,
-    'user.voiceUser.muted': false,
-  }).fetch();
-  const _userObjectsLength = userObjects.length;
-
-  for (let i = 0; i < _userObjectsLength; i++) {
-    userObject = userObjects[i];
-    results.push(Meteor.call('muteUser', meetingId, userObject.userId, userObject.userId,
-        userObject.authToken, true)); //true for muted
-  }
-
-  return results;
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/lockAllViewersMic.js b/bigbluebutton-html5/imports/api/users/server/modifiers/lockAllViewersMic.js
new file mode 100755
index 0000000000000000000000000000000000000000..6f441db686d026dc98c0741343a30fc4fb471043
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/lockAllViewersMic.js
@@ -0,0 +1,24 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+
+import Users from '/imports/api/users';
+
+export default function lockAllViewersMic(meetingId) {
+  const selector = {
+    meetingId,
+    'user.role': 'VIEWER',
+    'user.listenOnly': false,
+    'user.locked': true,
+    'user.voiceUser.joined': true,
+    'user.voiceUser.muted': false,
+  };
+
+  const usersToMute = Users.find(selector).fetch();
+
+  usersToMute.forEach(user =>
+    muteToggle({
+      meetingId,
+      requesterUserId: user.userId,
+    }, userId, true)
+  );
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/markUserOffline.js b/bigbluebutton-html5/imports/api/users/server/modifiers/markUserOffline.js
deleted file mode 100755
index ebce17cc7bfc06cbca57f331133a28f8b4b06181..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/markUserOffline.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
-
-// Only callable from server
-// Received information from BBB-Apps that a user left
-// Need to update the collection
-// params: meetingid,  userid as defined in BBB-Apps
-// callback
-export function markUserOffline(meetingId, userId, callback) {
-  // mark the user as offline. remove from the collection on meeting_end #TODO
-  let user = Users.findOne({
-    meetingId: meetingId,
-    userId: userId,
-  });
-
-  if (user != null && user.clientType === 'HTML5') {
-    logger.info(`marking html5 user [${userId}] as offline in meeting[${meetingId}]`);
-    return Users.update({
-      meetingId: meetingId,
-      userId: userId,
-    }, {
-      $set: {
-        'user.connection_status': 'offline',
-        'user.voiceUser.talking': false,
-        'user.voiceUser.joined': false,
-        'user.voiceUser.muted': false,
-        'user.time_of_joining': 0,
-        'user.listenOnly': false, //TODO make this user: {}
-      },
-    }, (err, numChanged) => {
-      let funct;
-      if (err != null) {
-        logger.error(
-          `_unsucc update (mark as offline) of user ${user.user.name} ` +
-          `${userId} err=${JSON.stringify(err)}`
-        );
-        return callback();
-      } else {
-        funct = function (cbk) {
-          logger.info(
-            `_marking as offline html5 user ${user.user.name} ` +
-            `${userId}  numChanged=${numChanged}`
-          );
-          return cbk();
-        };
-
-        return funct(callback);
-      }
-    });
-  } else {
-    return Users.remove({
-      meetingId: meetingId,
-      userId: userId,
-    }, (err, numDeletions) => {
-      let funct;
-      if (err != null) {
-        logger.error(
-          `_unsucc deletion of user ${user != null ? user.user.name : void 0} ` +
-          `${userId} err=${JSON.stringify(err)}`
-        );
-        return callback();
-      } else {
-        funct = function (cbk) {
-          logger.info(
-            `_deleting info for user ${user != null ? user.user.name : void 0} ` +
-            `${userId} numDeletions=${numDeletions}`
-          );
-          return cbk();
-        };
-
-        return funct(callback);
-      }
-    });
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0b5d2e941d7bdc420b98004ddf816955b7a4e16
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js
@@ -0,0 +1,56 @@
+import { check } from 'meteor/check';
+import Users from '/imports/api/users';
+import Logger from '/imports/startup/server/logger';
+
+import setConnectionStatus from './setConnectionStatus';
+
+const CLIENT_TYPE_HTML = 'HTML5';
+
+export default function removeUser(meetingId, userId) {
+  check(meetingId, String);
+  check(userId, String);
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const User = Users.findOne(selector);
+
+  if (User && User.clientType !== CLIENT_TYPE_HTML) {
+    const cb = (err, numChanged) => {
+      if (err) {
+        return Logger.error(`Removing user from collection: ${err}`);
+      }
+
+      if (numChanged) {
+        return Logger.info(`Removed user id=${userId} meeting=${meetingId}`);
+      }
+    };
+
+    return Users.remove(selector, cb);
+  }
+
+  const modifier = {
+    $set: {
+      'user.connection_status': 'offline',
+      'user.voiceUser.talking': false,
+      'user.voiceUser.joined': false,
+      'user.voiceUser.muted': false,
+      'user.time_of_joining': 0,
+      'user.listenOnly': false,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Removing user from collection: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Removed ${CLIENT_TYPE_HTML} user id=${userId} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js b/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js
deleted file mode 100755
index e9266dff0b034121d2926a644bcf80f0b7973a54..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { publish } from '/imports/api/common/server/helpers';
-import Meetings from '/imports/api/meetings';
-import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
-
-// 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
-export function requestUserLeaving(meetingId, userId) {
-  const REDIS_CONFIG = Meteor.settings.redis;
-  let voiceConf;
-  const userObject = Users.findOne({
-    meetingId: meetingId,
-    userId: userId,
-  });
-  const meetingObject = Meetings.findOne({
-    meetingId: meetingId,
-  });
-
-  if (meetingObject != null) {
-    voiceConf = meetingObject.voiceConf;
-  }
-
-  if ((userObject != null) && (voiceConf != null) && (userId != null) && (meetingId != null)) {
-    let lOnly = false;
-    if (userObject.hasOwnProperty('user') && userObject.user.hasOwnProperty('listenOnly')) {
-      lOnly = userObject.user.listenOnly;
-    }
-
-    // end listenOnly audio for the departing user
-    if (lOnly) {
-      const listenOnlyMessage = {
-        payload: {
-          userid: userId,
-          meeting_id: meetingId,
-          voice_conf: voiceConf,
-          name: userObject.user.name,
-        },
-        header: {
-          timestamp: new Date().getTime(),
-          name: 'user_disconnected_from_global_audio',
-        },
-      };
-      publish(REDIS_CONFIG.channels.toBBBApps.meeting, listenOnlyMessage);
-    }
-
-    // remove user from meeting
-    const message = {
-      payload: {
-        meeting_id: meetingId,
-        userid: userId,
-      },
-      header: {
-        timestamp: new Date().getTime(),
-        name: 'user_leaving_request',
-      },
-    };
-    logger.info(`sending a user_leaving_request for ${meetingId}:${userId}`);
-    return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
-  } else {
-    return logger.info('did not have enough information to send a user_leaving_request');
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js b/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js
new file mode 100644
index 0000000000000000000000000000000000000000..92770a166de88f7058483d1e86c259cd21222174
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js
@@ -0,0 +1,40 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import Users from '/imports/api/users';
+import Logger from '/imports/startup/server/logger';
+
+const VALID_CONNECTION_STATUS = ['online', 'offline'];
+
+export default function setConnectionStatus(meetingId, userId, status = 'online') {
+  check(meetingId, String);
+  check(userId, String);
+  check(status, String);
+
+  if (!VALID_CONNECTION_STATUS.includes(status)) {
+    throw new Meteor.Error('invalid-connection-status',
+      `Invalid connection status, received ${status} expecting ${VALID_CONNECTION_STATUS.join()}`);
+  }
+
+  const selector = {
+    meetingId,
+    userId,
+  };
+
+  const modifier = {
+    $set: {
+      'user.connection_status': status,
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Updating connection status user=${userId}: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Updated connection status user=${userId} status=${status} meeting=${meetingId}`);
+    }
+  };
+
+  return Users.update(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/setUserLockedStatus.js b/bigbluebutton-html5/imports/api/users/server/modifiers/setUserLockedStatus.js
deleted file mode 100755
index 7d37ef6f15b0acdcb6cbb5ba41cb37c5fa5c76c0..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/setUserLockedStatus.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import Users from '/imports/api/users';
-import { logger } from '/imports/startup/server/logger';
-
-// change the locked status of a user (lock settings)
-export function setUserLockedStatus(meetingId, userId, isLocked) {
-  let userObject;
-  userObject = Users.findOne({
-    meetingId: meetingId,
-    userId: userId,
-  });
-  if (userObject != null) {
-    Users.update({
-      userId: userId,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        'user.locked': isLocked,
-      },
-    }, (err, numChanged) => {
-      if (err != null) {
-        return logger.error(`_error ${err} while updating user ${userId} with lock settings`);
-      } else {
-        return logger.info(
-          `_setting user locked status for:[${userId}] ` +
-          `from [${meetingId}] locked=${isLocked}`
-        );
-      }
-    });
-
-    // if the user is sharing audio, he should be muted upon locking involving disableMic
-    if (userObject.user.role === 'VIEWER' && !userObject.user.listenOnly &&
-        userObject.user.voiceUser.joined && !userObject.user.voiceUser.muted && isLocked) {
-      // TODO why are we doing Meteor.call here?! Anton
-      return Meteor.call('muteUser', meetingId, userObject.userId, userObject.userId,
-          userObject.authToken, true); //true for muted
-    }
-  } else {
-    let tempMsg = '(unsuccessful-no such user) setting user locked status for userid:';
-    return logger.error(`${tempMsg}[${userId}] from [${meetingId}] locked=${isLocked}`);
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/updateVoiceUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/updateVoiceUser.js
index 25e267b5f0c12d62240050b79870ec3d603a523e..d94fa3a54e22fc71ebd95362ca1af2c0fdae1da3 100755
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/updateVoiceUser.js
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/updateVoiceUser.js
@@ -1,47 +1,35 @@
+import { check } from 'meteor/check';
 import Users from '/imports/api/users';
 import Logger from '/imports/startup/server/logger';
 
-//update a voiceUser - a helper method
-export function updateVoiceUser(meetingId, voiceUserObject, callback = () => {}) {
+export default function updateVoiceUser(meetingId, userId, voiceUser) {
   check(meetingId, String);
-  check(voiceUserObject, Object);
-
-  const webUserId = voiceUserObject.web_userid;
-
-  check(webUserId, String);
-
-  let userObject = Users.findOne({
-    userId: webUserId,
-  });
-
-  Logger.debug(`user ${userObject.userId} vu=${JSON.stringify(voiceUserObject)}`);
-
-  check(userObject, Object);
+  check(userId, String);
+  check(voiceUser, Object);
 
   const selector = {
     meetingId,
-    userId: webUserId,
+    userId,
   };
 
   const modifier = {
     $set: {
-      'user.voiceUser.talking': voiceUserObject.talking || false,
-      'user.voiceUser.joined': voiceUserObject.joined || false,
-      'user.voiceUser.locked': voiceUserObject.locked || false,
-      'user.voiceUser.muted': voiceUserObject.muted || false,
-      'user.listenOnly': voiceUserObject.listen_only || false,
+      'user.voiceUser.talking': voiceUser.talking,
+      'user.voiceUser.joined': voiceUser.joined,
+      'user.voiceUser.locked': voiceUser.locked,
+      'user.voiceUser.muted': voiceUser.muted,
     },
   };
 
   const cb = (err, numChanged) => {
     if (err) {
-      Logger.error(
-        `failed to update voiceUser ${JSON.stringify(voiceUserObject)} err=${JSON.stringify(err)}`
-      );
+      return Logger.error(`Updating voice user=${userId}: ${err}`);
     }
 
-    return callback();
+    if (numChanged) {
+      return Logger.verbose(`Updated voice user=${userId} meeting=${meetingId}`);
+    }
   };
 
-  Users.update(selector, modifier, cb);
+  return Users.update(selector, modifier, cb);
 };
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/userJoined.js b/bigbluebutton-html5/imports/api/users/server/modifiers/userJoined.js
deleted file mode 100755
index 7de5821313d2b4b6fa363a62e91beb2f9a758f6b..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/userJoined.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import Chat from '/imports/api/chat';
-import Users from '/imports/api/users';
-import Meetings from '/imports/api/meetings';
-import { logger } from '/imports/startup/server/logger';
-import { BREAK_LINE } from '/imports/utils/lineEndings.js';
-import getStun from '/imports/api/phone/server/getStun';
-
-const parseMessage = (message) => {
-  message = message || '';
-
-  // Replace \r and \n to <br/>
-  message = message.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + BREAK_LINE + '$2');
-
-  // Replace flash links to html valid ones
-  message = message.split(`<a href='event:`).join(`<a target="_blank" href='`);
-  message = message.split(`<a href="event:`).join(`<a target="_blank" href="`);
-
-  return message;
-};
-
-export function userJoined(meetingId, user, callback) {
-  const APP_CONFIG = Meteor.settings.public.app;
-  let welcomeMessage;
-  const userId = user.userid;
-  const userObject = Users.findOne({
-    userId: user.userid,
-    meetingId: meetingId,
-  });
-
-  // the collection already contains an entry for this user
-  // because the user is reconnecting OR
-  // in the case of an html5 client user we added a dummy user on
-  // register_user_message (to save authToken)
-  if (userObject != null && userObject.authToken != null) {
-    getStun({
-      meetingId: meetingId,
-      requesterUserId: userId,
-    });
-
-    Users.update({
-      userId: user.userid,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        user: {
-          userid: user.userid,
-          presenter: user.presenter,
-          name: user.name,
-          _sort_name: user.name.toLowerCase(),
-          phone_user: user.phone_user,
-          set_emoji_time: user.set_emoji_time,
-          emoji_status: user.emoji_status,
-          has_stream: user.has_stream,
-          role: user.role,
-          listenOnly: user.listenOnly,
-          extern_userid: user.extern_userid,
-          locked: user.locked,
-          time_of_joining: user.timeOfJoining,
-          connection_status: 'online', // TODO consider other default value
-          voiceUser: {
-            web_userid: user.voiceUser.web_userid,
-            callernum: user.voiceUser.callernum,
-            userid: user.voiceUser.userid,
-            talking: user.voiceUser.talking,
-            joined: user.voiceUser.joined,
-            callername: user.voiceUser.callername,
-            locked: user.voiceUser.locked,
-            muted: user.voiceUser.muted,
-          },
-          webcam_stream: user.webcam_stream,
-        },
-      },
-    }, err => {
-      let funct;
-      if (err != null) {
-        logger.error(`_error ${err} when trying to insert user ${userId}`);
-        return callback();
-      } else {
-        funct = function (cbk) {
-          logger.info(
-            `_(case1) UPDATING USER ${user.userid}, ` +
-            `authToken= ${userObject.authToken}, ` +
-            `locked=${user.locked}, username=${user.name}`
-          );
-          return cbk();
-        };
-
-        return funct(callback);
-      }
-    });
-    const meetingObject = Meetings.findOne({
-      meetingId: meetingId,
-    });
-    if (meetingObject != null) {
-      welcomeMessage = APP_CONFIG.defaultWelcomeMessage.replace(/%%CONFNAME%%/,
-          meetingObject.meetingName);
-    }
-
-    welcomeMessage = welcomeMessage + APP_CONFIG.defaultWelcomeMessageFooter;
-
-    // add the welcome message if it's not there already OR update time_of_joining
-    return Chat.upsert({
-      meetingId: meetingId,
-      userId: userId,
-      'message.chat_type': 'SYSTEM_MESSAGE',
-      'message.to_userid': userId,
-    }, {
-      meetingId: meetingId,
-      userId: userId,
-      message: {
-        chat_type: 'SYSTEM_MESSAGE',
-        message: parseMessage(welcomeMessage),
-        from_color: '0x3399FF',
-        to_userid: userId,
-        from_userid: 'SYSTEM_MESSAGE',
-        from_username: '',
-        from_time: (user != null && user.timeOfJoining != null) ? +(user.timeOfJoining) : 0,
-      },
-    }, err => {
-      if (err != null) {
-        return logger.error(`_error ${err} when trying to insert welcome message for ${userId}`);
-      } else {
-        return logger.info(`_added/updated a system message in chat for user ${userId}`);
-      }
-
-      // note that we already called callback() when updating the user. Adding
-      // the welcome message in the chat is not as vital and we can afford to
-      // complete it when possible, without blocking the serial event messages processing
-    });
-  } else {
-    // logger.info "NOTE: got user_joined_message #{user.name} #{user.userid}"
-    getStun({
-      meetingId: meetingId,
-      requesterUserId: userId,
-    });
-
-    return Users.upsert({
-      meetingId: meetingId,
-      userId: userId,
-    }, {
-      meetingId: meetingId,
-      userId: userId,
-      user: {
-        userid: user.userid,
-        presenter: user.presenter,
-        name: user.name,
-        _sort_name: user.name.toLowerCase(),
-        phone_user: user.phone_user,
-        emoji_status: user.emoji_status,
-        set_emoji_time: user.set_emoji_time,
-        has_stream: user.has_stream,
-        role: user.role,
-        listenOnly: user.listenOnly,
-        extern_userid: user.extern_userid,
-        locked: user.locked,
-        time_of_joining: user.timeOfJoining,
-        connection_status: '',
-        voiceUser: {
-          web_userid: user.voiceUser.web_userid,
-          callernum: user.voiceUser.callernum,
-          userid: user.voiceUser.userid,
-          talking: user.voiceUser.talking,
-          joined: user.voiceUser.joined,
-          callername: user.voiceUser.callername,
-          locked: user.voiceUser.locked,
-          muted: user.voiceUser.muted,
-        },
-        webcam_stream: user.webcam_stream,
-      },
-    }, (err, numChanged) => {
-      let funct;
-      if (numChanged.insertedId != null) {
-        funct = function (cbk) {
-          logger.info(
-            `_joining user (case2) userid=[${userId}]:${user.name}. Users.size is now ` +
-            `${Users.find({
-              meetingId: meetingId,
-            }).count()}`
-          );
-          return cbk();
-        };
-
-        return funct(callback);
-      } else {
-        return callback();
-      }
-    });
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/publications.js b/bigbluebutton-html5/imports/api/users/server/publications.js
deleted file mode 100755
index 1b7edc1300078ede14a69d2664fd209856f42ef6..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/api/users/server/publications.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import Users from '/imports/api/users';
-import { isAllowedTo } from '/imports/startup/server/userPermissions';
-import { logger } from '/imports/startup/server/logger';
-import { requestUserLeaving } from '/imports/api/users/server/modifiers/requestUserLeaving';
-
-// Publish only the online users that are in the particular meetingId
-// Also contains reconnection and connection_status info
-Meteor.publish('users', function (credentials) {
-  const meetingId = credentials.meetingId;
-  const userid = credentials.requesterUserId;
-  const authToken = credentials.requesterToken;
-
-  logger.info(`attempt publishing users for ${meetingId}, ${userid}, ${authToken}`);
-  const userObject = Users.findOne({
-    userId: userid,
-    meetingId: meetingId,
-  });
-
-  if (!!userObject && !!userObject.user) {
-    let username = 'UNKNOWN';
-    if (isAllowedTo('subscribeUsers', credentials)) {
-      logger.info(`${userid} was allowed to subscribe to 'users'`);
-      username = userObject.user.name;
-
-      // offline -> online
-      if (userObject.user.connection_status !== 'online') {
-        Meteor.call('validateAuthToken', credentials);
-        setConnectionStatus(meetingId, userid, 'online');
-      }
-
-      this._session.socket.on('close', Meteor.bindEnvironment((function (_this) {
-        return function () {
-          logger.info(`a user lost connection: session.id=${_this._session.id}` +
-              ` userId = ${userid}, username=${username}, meeting=${meetingId}`);
-          setConnectionStatus(meetingId, userid, 'offline');
-          return requestUserLeaving(meetingId, userid);
-        };
-      })(this)));
-
-      return getUsers(meetingId);
-    } else {
-      logger.warn('was not authorized to subscribe to users');
-      return this.error(new Meteor.Error(402, 'User was not authorized to subscribe to users'));
-    }
-  } else { //subscribing before the user was added to the collection
-    Meteor.call('validateAuthToken', credentials);
-    logger.info(`Sending validateAuthTokenthere for user ${userid} in ${meetingId}.`);
-    return getUsers(meetingId);
-  }
-});
-
-const getUsers = function (meetingId) {
-  //publish the users which are not offline
-  return Users.find({
-    meetingId: meetingId,
-    'user.connection_status': {
-      $in: ['online', ''],
-    },
-  }, {
-    fields: {
-      authToken: false,
-    },
-  });
-};
-
-const setConnectionStatus = function (meetingId, userId, statusStr) {
-  Users.update({
-    meetingId: meetingId,
-    userId: userId,
-  }, {
-    $set: {
-      'user.connection_status': statusStr,
-    },
-  }, (err, numChanged) => {
-    logger.info(`User ${userId} in ${meetingId} goes ${statusStr}`);
-  });
-};
diff --git a/bigbluebutton-html5/imports/api/users/server/publishers.js b/bigbluebutton-html5/imports/api/users/server/publishers.js
new file mode 100644
index 0000000000000000000000000000000000000000..489baf59ba70999d58891d92b48b5cd0503786b4
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users/server/publishers.js
@@ -0,0 +1,44 @@
+import Users from '/imports/api/users';
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+
+import userLeaving from './methods/userLeaving';
+import validateAuthToken from './methods/validateAuthToken';
+
+Meteor.publish('users', function (credentials) {
+  const { meetingId, requesterUserId, requesterToken } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(requesterToken, String);
+
+  validateAuthToken(credentials);
+
+  // TODO(auth): We need to fix the Authentication flow to enable ACL
+  // if (!isAllowedTo('subscribeUsers', credentials)) {
+  //   this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'Users'"));
+  // }
+
+  this.onStop(() => {
+    userLeaving(credentials, requesterUserId);
+  });
+
+  const selector = {
+    meetingId,
+    'user.connection_status': {
+      $in: ['online', ''],
+    },
+  };
+
+  const options = {
+    fields: {
+      authToken: false,
+    },
+  };
+
+  Logger.info(`Publishing Users for ${meetingId} ${requesterUserId} ${requesterToken}`);
+
+  return Users.find(selector, options);
+});
diff --git a/bigbluebutton-html5/imports/startup/server/userPermissions.js b/bigbluebutton-html5/imports/startup/server/userPermissions.js
index 19a32843f4c61bd1b24a7aad0f802d651b24dca2..ae200a86499fa5fedbf225461deff54306ab8b15 100755
--- a/bigbluebutton-html5/imports/startup/server/userPermissions.js
+++ b/bigbluebutton-html5/imports/startup/server/userPermissions.js
@@ -11,6 +11,8 @@ const presenter = {
 
   //whiteboard
   moveCursor: true,
+
+  setPresenter: true,
 };
 
 // holds the values for whether the moderator user is allowed to perform an action (true)
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx
index db6f116546bcd9134792f6229086070b86c40b6a..f818c41198f07262be119464303b508bec30af32 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx
@@ -56,7 +56,7 @@ class ActionsDropdown extends Component {
         <DropdownTrigger>
           <Button
             label={intl.formatMessage(intlMessages.actionsLabel)}
-            icon="circle-add"
+            icon="add"
             color="primary"
             size="lg"
             circle={true}
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/audio-menu/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/audio-menu/component.jsx
index 9ac48bbd61ca6df5f8b325f6f29e9de5f11465b0..dd92a29c64442bb68c9c9edfe3f97176a8fc2602 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/audio-menu/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/audio-menu/component.jsx
@@ -31,7 +31,7 @@ class JoinAudioOptions extends React.Component {
           onClick={close}
           label={intl.formatMessage(intlMessages.leaveAudio)}
           color={'danger'}
-          icon={'mute'}
+          icon={'audio_off'}
           size={'lg'}
           circle={true}
         />
@@ -43,7 +43,7 @@ class JoinAudioOptions extends React.Component {
         onClick={open}
         label={intl.formatMessage(intlMessages.joinAudio)}
         color={'primary'}
-        icon={'unmute'}
+        icon={'audio_on'}
         size={'lg'}
         circle={true}
       />
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/component.jsx
index 6013c30829c0a8f189b6e934beb82f2a1c89ce55..3af018f7cf0e95cae7e1620d65e90c7d7e3cf3a8 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/component.jsx
@@ -48,10 +48,10 @@ class EmojiMenu extends Component {
         <DropdownContent placement="top left">
           <DropdownList>
             <DropdownListItem
-              icon="raiseHand"
+              icon="hand"
               label={intl.formatMessage(intlMessages.raiseLabel)}
               description={intl.formatMessage(intlMessages.raiseDesc)}
-              onClick={() => actions.setEmojiHandler('raiseHand')}
+              onClick={() => actions.setEmojiHandler('hand')}
             />
             <DropdownListItem
               icon="happy"
@@ -60,10 +60,10 @@ class EmojiMenu extends Component {
               onClick={() => actions.setEmojiHandler('happy')}
             />
             <DropdownListItem
-              icon="neutral"
+              icon="undecided"
               label={intl.formatMessage(intlMessages.undecidedLabel)}
               description={intl.formatMessage(intlMessages.undecidedDesc)}
-              onClick={() => actions.setEmojiHandler('neutral')}
+              onClick={() => actions.setEmojiHandler('undecided')}
             />
             <DropdownListItem
               icon="sad"
@@ -78,22 +78,22 @@ class EmojiMenu extends Component {
               onClick={() => actions.setEmojiHandler('confused')}
             />
             <DropdownListItem
-              icon="away"
+              icon="time"
               label={intl.formatMessage(intlMessages.awayLabel)}
               description={intl.formatMessage(intlMessages.awayDesc)}
-              onClick={() => actions.setEmojiHandler('away')}
+              onClick={() => actions.setEmojiHandler('time')}
             />
             <DropdownListItem
-              icon="thumbsUp"
+              icon="thumbs_up"
               label={intl.formatMessage(intlMessages.thumbsupLabel)}
               description={intl.formatMessage(intlMessages.thumbsupDesc)}
-              onClick={() => actions.setEmojiHandler('thumbsUp')}
+              onClick={() => actions.setEmojiHandler('thumbs_up')}
             />
             <DropdownListItem
-              icon="thumbsDown"
+              icon="thumbs_down"
               label={intl.formatMessage(intlMessages.thumbsdownLabel)}
               description={intl.formatMessage(intlMessages.thumbsdownDesc)}
-              onClick={() => actions.setEmojiHandler('thumbsDown')}
+              onClick={() => actions.setEmojiHandler('thumbs_down')}
             />
             <DropdownListItem
               icon="applause"
@@ -103,7 +103,7 @@ class EmojiMenu extends Component {
             />
             <DropdownListSeparator/>
             <DropdownListItem
-              icon="clear-status"
+              icon="clear_status"
               label={intl.formatMessage(intlMessages.clearLabel)}
               description={intl.formatMessage(intlMessages.clearDesc)}
               onClick={() => actions.setEmojiHandler('none')}
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/service.js b/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/service.js
index 4be72b17bdeec09cb6d7b0d01770995e792a423e..36eb6458f02a5e5bc3faf59e726e457c53dba5bf 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/service.js
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/emoji-menu/service.js
@@ -22,7 +22,7 @@ let getEmojiData = () => {
 
 // Below doesn't even need to receieve credentials
 const setEmoji = (toRaiseUserId, status) => {
-  callServer('userSetEmoji', toRaiseUserId, status);
+  callServer('setEmojiStatus', toRaiseUserId, status);
 };
 
 export default {
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx
index b2a0e9bc378af93be62e0d24bcd64e0c0e4f92e9..1225ac0117459b157cfa8d8f4e9bfcd252f2af0f 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/mute-button/component.jsx
@@ -7,7 +7,7 @@ export default class MuteAudio extends React.Component {
   render() {
     const { isInAudio, isMuted, callback, isTalking} = this.props;
     let label = !isMuted ? 'Mute' : 'Unmute';
-    let icon = !isMuted ? 'audio' : 'audio-off';
+    let icon = !isMuted ? 'unmute' : 'mute';
     let className = !isInAudio ? styles.invisible : null;
     let tabIndex = !isInAudio ? -1 : 0;
 
diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/video-button/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/video-button/component.jsx
index 78736db4052e689f7abee1c784973057c93bbfc4..c01951a324aab1136541d89866006520dcd7dc3d 100755
--- a/bigbluebutton-html5/imports/ui/components/actions-bar/video-button/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/actions-bar/video-button/component.jsx
@@ -1,23 +1,23 @@
-import React from 'react';
-import Button from '/imports/ui/components/button/component';
-import styles from '../styles.scss';
-
-export default class JoinVideo extends React.Component {
-
-  handleClick() {
-  }
-
-  render() {
-    return (
-      <Button
-        onClick={this.handleClick}
-        label={'Cam Off'}
-        color={'primary'}
-        icon={'video-off'}
-        size={'lg'}
-        circle={true}
-        style={{visibility: 'hidden'}}
-      />
-    );
-  }
-}
+import React from 'react';
+import Button from '/imports/ui/components/button/component';
+import styles from '../styles.scss';
+
+export default class JoinVideo extends React.Component {
+
+  handleClick() {
+  }
+
+  render() {
+    return (
+      <Button
+        onClick={this.handleClick}
+        label={'Cam Off'}
+        color={'primary'}
+        icon={'video_off'}
+        size={'lg'}
+        circle={true}
+        style={{visibility: 'hidden'}}
+      />
+    );
+  }
+}
diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx
index 756a25b9cb2848be1c97b274dc9626e5559a2dd3..7694d0ee87c7854ccf857b0b9c75f858ee5951f6 100755
--- a/bigbluebutton-html5/imports/ui/components/app/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx
@@ -32,6 +32,17 @@ export default class App extends Component {
     this.state = {
       compactUserList: false, //TODO: Change this on userlist resize (?)
     };
+
+    this.setDefaultSettings = props.setDefaultSettings;
+  }
+
+  setHtmlFontSize(size) {
+    document.getElementsByTagName('html')[0].style.fontSize = size;
+  };
+
+  componentDidMount() {
+    this.setDefaultSettings();
+    this.setHtmlFontSize(this.props.fontSize);
   }
 
   renderNavBar() {
@@ -113,7 +124,6 @@ export default class App extends Component {
 
   renderClosedCaptions() {
     const { captions } = this.props;
-
     if (captions && this.props.getCaptionsStatus()) {
       return (
         <section className={styles.closedCaptions}>
@@ -170,7 +180,8 @@ export default class App extends Component {
 
       // compare openChats(chatID) to chatID of currently opened chat room
       if (openChats[i] !== openChat) {
-        let shouldPlaySound = LocalStorage.getItem('audioNotifChat') || Meteor.settings.public.app.audioChatNotification;
+        let shouldPlaySound = this.props.applicationSettings.chatAudioNotifications;
+
         if (shouldPlaySound && chat > prevProps.unreadMessageCount[i]) {
           this.playSoundForUnreadMessages();
         }
diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx
index 4ca5cf7fbe7d5e33b4013ca8edf5003f627aa194..03088f6a4bb9b6534894c971e5df4cf6430940e9 100755
--- a/bigbluebutton-html5/imports/ui/components/app/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx
@@ -7,7 +7,9 @@ import {
   redirectToLogoutUrl,
   getModal,
   getCaptionsStatus,
+  getFontSize,
 } from './service';
+import { setDefaultSettings, getSettingsFor } from '/imports/ui/components/settings/service';
 
 import NavBarContainer from '../nav-bar/container';
 import ActionsBarContainer from '../actions-bar/container';
@@ -78,6 +80,9 @@ export default createContainer(({ params }) => {
     openChat: params.chatID,
     getCaptionsStatus,
     redirectToLogoutUrl,
+    setDefaultSettings,
+    fontSize: getFontSize(),
+    applicationSettings: getSettingsFor('application'),
   };
 }, AppContainer);
 
diff --git a/bigbluebutton-html5/imports/ui/components/app/service.js b/bigbluebutton-html5/imports/ui/components/app/service.js
index f5c173415b204cc9574a062f464243f59172721e..77ea65d45f32b4465d690c0a1af470444b733840 100755
--- a/bigbluebutton-html5/imports/ui/components/app/service.js
+++ b/bigbluebutton-html5/imports/ui/components/app/service.js
@@ -3,6 +3,7 @@ import Auth from '/imports/ui/services/auth';
 import Users from '/imports/api/users';
 import Breakouts from '/imports/api/breakouts';
 import Storage from '/imports/ui/services/storage/session';
+import SettingsService from '/imports/ui/components/settings/service';
 
 function setCredentials(nextState, replace) {
   if (nextState && nextState.params.authToken) {
@@ -114,9 +115,14 @@ const clearModal = () => {
   showModal(null);
 };
 
-function getCaptionsStatus() {
-  var CCEnabled = Storage.getItem('closedCaptions');
-  return !!CCEnabled;
+const getCaptionsStatus = () => {
+  const settings = Storage.getItem('settings_cc');
+  return settings ? settings.closedCaptions : false;
+};
+
+const getFontSize = () => {
+  const settings = SettingsService.getSettingsFor('application');
+  return settings ? settings.fontSize : '14px';
 };
 
 export {
@@ -130,4 +136,5 @@ export {
   showModal,
   clearModal,
   getCaptionsStatus,
+  getFontSize,
 };
diff --git a/bigbluebutton-html5/imports/ui/components/audio-modal/audio-settings/component.jsx b/bigbluebutton-html5/imports/ui/components/audio-modal/audio-settings/component.jsx
index d61acaf092405f76014aed3af5c83c4fcff95540..d602083a6ca551cf9e6a4a730c9646c7b840ea3d 100755
--- a/bigbluebutton-html5/imports/ui/components/audio-modal/audio-settings/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio-modal/audio-settings/component.jsx
@@ -53,7 +53,7 @@ class AudioSettings extends React.Component {
         <div className={styles.center}>
           <Button className={styles.backBtn}
             label={intl.formatMessage(intlMessages.backLabel)}
-            icon={'left-arrow'}
+            icon={'left_arrow'}
             size={'md'}
             color={'primary'}
             ghost={true}
diff --git a/bigbluebutton-html5/imports/ui/components/audio-modal/join-audio/component.jsx b/bigbluebutton-html5/imports/ui/components/audio-modal/join-audio/component.jsx
index 3e15e4287d246988ac4d897221fa759554c15349..392a67799517eb22baa859d964cc2973eb039cd3 100755
--- a/bigbluebutton-html5/imports/ui/components/audio-modal/join-audio/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio-modal/join-audio/component.jsx
@@ -63,7 +63,7 @@ class JoinAudio extends React.Component {
         <div className={styles.center}>
           <Button className={styles.audioBtn}
             label={intl.formatMessage(intlMessages.microphoneLabel)}
-            icon={'audio'}
+            icon={'unmute'}
             circle={true}
             size={'jumbo'}
             onClick={this.openAudio}
diff --git a/bigbluebutton-html5/imports/ui/components/audio-modal/listen-only/component.jsx b/bigbluebutton-html5/imports/ui/components/audio-modal/listen-only/component.jsx
index 5815c54b598ac0a6c0148d7a786bd5c587a71877..1808373e68264c0e0337b92eeebd6d7eb62d38d3 100755
--- a/bigbluebutton-html5/imports/ui/components/audio-modal/listen-only/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio-modal/listen-only/component.jsx
@@ -53,7 +53,7 @@ class ListenOnly extends React.Component {
         <div className={styles.center}>
           <Button className={styles.backBtn}
             label={intl.formatMessage(intlMessages.backLabel)}
-            icon={'left-arrow'}
+            icon={'left_arrow'}
             size={'md'}
             color={'primary'}
             ghost={true}
diff --git a/bigbluebutton-html5/imports/ui/components/audio-test/component.jsx b/bigbluebutton-html5/imports/ui/components/audio-test/component.jsx
index 3accbb1fd257e5efbe472042453e71deff9fcb18..5ba9931610f0a124c95099e34d09f95dab060606 100755
--- a/bigbluebutton-html5/imports/ui/components/audio-test/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio-test/component.jsx
@@ -1,10 +1,10 @@
-import React from 'react';
-import Button from '/imports/ui/components/button/component';
-import styles from '../settings/styles.scss';
-import { defineMessages, injectIntl } from 'react-intl';
-
-class AudioTest extends React.Component {
-  constructor(props) {
+import React from 'react';
+import Button from '/imports/ui/components/button/component';
+import styles from '../settings/styles.scss';
+import { defineMessages, injectIntl } from 'react-intl';
+
+class AudioTest extends React.Component {
+  constructor(props) {
     super(props);
   }
 
@@ -14,14 +14,13 @@ class AudioTest extends React.Component {
     } = this.props;
 
     return (
-      <Button className={styles.testAudioBtn}
-        label={intl.formatMessage(intlMessages.playSoundLabel)}
-        icon={'audio'}
-        size={'md'}
-        color={'primary'}
-        ghost={true}
-        onClick={this.props.handlePlayAudioSample}
-      />
+        <Button className={styles.testAudioBtn}
+          label={intl.formatMessage(intlMessages.playSoundLabel)}
+          icon={'unmute'}
+          size={'md'}
+          color={'primary'}
+          onClick={this.props.handlePlayAudioSample}
+        />
     );
   }
 };
diff --git a/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx
index d1f85ef2674845925339877993de71c9302b569c..b5fae50cb6310416f3966e80bdd5f6044ea02e71 100755
--- a/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx
@@ -3,10 +3,12 @@ import React, { Component, PropTypes } from 'react';
 const propTypes = {
   kind: PropTypes.oneOf(['audioinput', 'audiooutput', 'videoinput']),
   onChange: PropTypes.func.isRequired,
+  value: PropTypes.string,
 };
 
 const defaultProps = {
   kind: 'audioinput',
+  value: undefined,
 };
 
 class DeviceSelector extends Component {
@@ -18,7 +20,7 @@ class DeviceSelector extends Component {
     this.handleSelectChange = this.handleSelectChange.bind(this);
 
     this.state = {
-      value: undefined,
+      value: props.value,
       devices: [],
       options: [],
     };
diff --git a/bigbluebutton-html5/imports/ui/components/chat/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
index f33916393ab9813364ca6d5271a75794642a571a..dd56c01987c9ae5a24c92406fd9d026ded836a9d 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
@@ -30,7 +30,7 @@ export default class Chat extends Component {
       <section className={styles.chat}>
         <header className={styles.header}>
           <Link className={styles.closeChat} to="/users">
-            <Icon iconName="left-arrow" /> {title}
+            <Icon iconName="left_arrow" /> {title}
           </Link>
         </header>
         <MessageList
diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/message-form-actions/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/message-form/message-form-actions/component.jsx
old mode 100644
new mode 100755
index 99957c16ec2b5de22fac9e9e17ad275252a2f64d..7ec85c71ac0637f1ce72058d9a54e5d1c1bd2cf2
--- a/bigbluebutton-html5/imports/ui/components/chat/message-form/message-form-actions/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/message-form-actions/component.jsx
@@ -20,7 +20,7 @@ export default class MessageFormActions extends BaseButton {
   render() {
     return (
       <BaseButton {...this.props}>
-        <Icon iconName={'circle-add'} />
+        <Icon iconName={'add'} />
       </BaseButton>
     );
   }
diff --git a/bigbluebutton-html5/imports/ui/components/chat/styles.scss b/bigbluebutton-html5/imports/ui/components/chat/styles.scss
index 439ba0f2d62a846f92d654c94a214f22b716c1aa..6a10743a98e0376565b89b86c8b347cf28c55da2 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/chat/styles.scss
@@ -23,6 +23,6 @@
   }
 }
 
-[class='icon-bbb-left-arrow'] {
+[class='icon-bbb-left_arrow'] {
     padding-bottom: 5px;
 }
diff --git a/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx b/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..d03094cf9db65ca58b2fbccf71bf16460228fbfe
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx
@@ -0,0 +1,36 @@
+import React, { Component, PropTypes } from 'react';
+
+import Icon from '../icon/component';
+import styles from './styles';
+import cx from 'classnames';
+
+export default class Checkbox extends Component {
+  constructor(props) {
+    super(props);
+
+    this.onChange = props.onChange;
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange() {
+    this.onChange();
+  }
+
+  render() {
+    return (
+      <div className={styles.container}>
+        <input
+          type='checkbox'
+          onChange={this.handleChange}
+          checked={this.props.checked}
+          className={styles.input}/>
+        <div onClick={this.handleChange}>
+          { this.props.checked ?
+            <Icon iconName='check' className={cx(styles.icon, styles.checked)}/> :
+            <Icon iconName='circle' className={styles.icon}/>
+          }
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss b/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss
new file mode 100644
index 0000000000000000000000000000000000000000..c1fe34b3151a2875b270e98cfd9218122fffbb4e
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss
@@ -0,0 +1,22 @@
+@import "../../stylesheets/variables/_all";
+
+.input {
+  border: 0;
+  clip: rect(0 0 0 0);
+  height: 1px;
+  margin: -1px;
+  overflow: hidden;
+  padding: 0;
+  position: absolute;
+  width: 1px;
+}
+
+.icon {
+  cursor: pointer;
+  font-size: 1.35rem;
+  color: $color-gray-light;
+}
+
+.checked {
+  color: $color-success;
+}
diff --git a/bigbluebutton-html5/imports/ui/components/closed-captions/component.jsx b/bigbluebutton-html5/imports/ui/components/closed-captions/component.jsx
index b4e8518a1974b2cdffe3ed2e01619dddb8e4f1e5..6dc5bb0ab6c0e4129efc3eacbce284b2dc2236b2 100755
--- a/bigbluebutton-html5/imports/ui/components/closed-captions/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/closed-captions/component.jsx
@@ -48,7 +48,7 @@ export default class ClosedCaptions extends React.Component {
     return (
       <div disabled className={styles.ccbox}>
         <div className={styles.title}>
-          <p> {this.props.locale ? this.props.locale : "Locale is not selected"} </p>
+          <p> {this.props.locale ? this.props.locale : 'Locale is not selected'} </p>
         </div>
         <div
           ref="ccScrollArea"
diff --git a/bigbluebutton-html5/imports/ui/components/closed-captions/service.js b/bigbluebutton-html5/imports/ui/components/closed-captions/service.js
index 3ea66e8d3db525e5459b99d943c7c9c996892092..2b3c443704347f215de630e7063470ce8f58412b 100755
--- a/bigbluebutton-html5/imports/ui/components/closed-captions/service.js
+++ b/bigbluebutton-html5/imports/ui/components/closed-captions/service.js
@@ -5,14 +5,15 @@ import Storage from '/imports/ui/services/storage/session';
 let getCCData = () => {
   const meetingID = Auth.meetingID;
 
+  const ccSettings = Storage.getItem('settings_cc');
 
-  let CCEnabled = Storage.getItem('closedCaptions');
+  let CCEnabled = ccSettings.closedCaptions;
 
   //associative array that keeps locales with arrays of string objects related to those locales
   let captions = [];
 
   //list of unique locales in the Captions Collection
-  if(CCEnabled) {
+  if (CCEnabled) {
     let locales = _.uniq(Captions.find({}, {
       sort: { locale: 1 },
       fields: { locale: true },
@@ -47,11 +48,11 @@ let getCCData = () => {
   }
 
   //fetching settings for the captions
-  let selectedLocale = Storage.getItem('ccLocale');
-  let ccFontFamily = Storage.getItem('ccFontFamily') ? Storage.getItem('ccFontFamily') : 'Arial';
-  let ccFontSize = Storage.getItem('ccFontSize') ? Storage.getItem('ccFontSize') : 18;
-  let ccBackgroundColor = Storage.getItem('ccBackgroundColor') ? Storage.getItem('ccBackgroundColor') : '#f3f6f9';
-  let ccFontColor = Storage.getItem('ccFontColor') ? Storage.getItem('ccFontColor') : '#000000';
+  let selectedLocale = ccSettings.locale;
+  let ccFontFamily = ccSettings.fontFamily ? ccSettings.fontFamily : 'Arial';
+  let ccFontSize = ccSettings.fontSize ? ccSettings.fontSize : 18;
+  let ccBackgroundColor = ccSettings.backgroundColor ? ccSettings.backgroundColor : '#f3f6f9';
+  let ccFontColor = ccSettings.fontColor ? ccSettings.fontColor : '#000000';
   return {
     locale: selectedLocale,
     fontFamily: ccFontFamily,
diff --git a/bigbluebutton-html5/imports/ui/components/modal/component.jsx b/bigbluebutton-html5/imports/ui/components/modal/component.jsx
index 2d36b93d9ef4e5cc84863cf61c65ad0c99b98ac8..ed28662331a6f347235361020d50225b3d5a3b6e 100755
--- a/bigbluebutton-html5/imports/ui/components/modal/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/modal/component.jsx
@@ -89,14 +89,14 @@ export default class Modal extends Component {
               label={dismiss.label}
               onClick={this.handleDismiss}
               aria-describedby={'modalDismissDescription'}
-              tabIndex={1} />
+              tabIndex={0} />
             <Button
               color={'primary'}
               className={styles.confirm}
               label={confirm.label}
               onClick={this.handleConfirm}
               aria-describedby={'modalConfirmDescription'}
-              tabIndex={2} />
+              tabIndex={0} />
           </div>
         </header>
         <div className={styles.content}>
diff --git a/bigbluebutton-html5/imports/ui/components/polling/component.jsx b/bigbluebutton-html5/imports/ui/components/polling/component.jsx
index 606ecd432b49bcf0e65d0361bfa9016e539cb9d2..210f03cf1561c11c66acba94831847b91137d4cd 100755
--- a/bigbluebutton-html5/imports/ui/components/polling/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/polling/component.jsx
@@ -31,13 +31,16 @@ export default class PollingComponent extends React.Component {
           </p>
         </div>
         {poll.answers.map((pollAnswer, index) =>
-          <div style={calculatedStyles} className={styles.pollButtonWrapper}>
+          <div
+            key={index}
+            style={calculatedStyles}
+            className={styles.pollButtonWrapper}
+          >
             <Button
               className={styles.pollingButton}
               label={pollAnswer.key}
               size="lg"
               color="primary"
-              key={index}
               onClick={() => this.props.handleVote(poll.pollId, pollAnswer)}
               aria-labelledby={`pollAnswerLabel${pollAnswer.key}`}
               aria-describedby={`pollAnswerDesc${pollAnswer.key}`}
diff --git a/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx
index 0a3d2877fdcf9e916e98c876cdcff00d418586e7..db94fdb95357c4fae75a0c6eb43249c3a9a88e45 100755
--- a/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx
@@ -106,20 +106,20 @@ export default class DefaultContent extends Component {
                 <Button
                   label={'With Icon'}
                   onClick={this.handleClick}
-                  icon={'circle-add'}
+                  icon={'add'}
                 />&nbsp;
                 <Button
                   label={'Ghost With Icon'}
                   onClick={this.handleClick}
                   color={'primary'}
-                  icon={'circle-add'}
+                  icon={'add'}
                   ghost={true}
                 />&nbsp;
                 <Button
                   label={'Icon Right'}
                   onClick={this.handleClick}
                   color={'danger'}
-                  icon={'circle-add'}
+                  icon={'add'}
                   ghost={true}
                   iconRight={true}
                 />&nbsp;
@@ -127,7 +127,7 @@ export default class DefaultContent extends Component {
                   label={'Icon Right'}
                   onClick={this.handleClick}
                   color={'success'}
-                  icon={'circle-add'}
+                  icon={'add'}
                   iconRight={true}
                 />
               </p>
@@ -136,7 +136,7 @@ export default class DefaultContent extends Component {
                   label={'Medium'}
                   onClick={this.handleClick}
                   color={'primary'}
-                  icon={'audio'}
+                  icon={'unmute'}
                   ghost={true}
                   circle={true}
                 />&nbsp;
@@ -144,7 +144,7 @@ export default class DefaultContent extends Component {
                   label={'Large'}
                   onClick={this.handleClick}
                   color={'danger'}
-                  icon={'audio'}
+                  icon={'unmute'}
                   size={'lg'}
                   ghost={true}
                   circle={true}
@@ -152,7 +152,7 @@ export default class DefaultContent extends Component {
                 <Button
                   label={'Small'}
                   onClick={this.handleClick}
-                  icon={'audio'}
+                  icon={'unmute'}
                   size={'sm'}
                   circle={true}
                 />&nbsp;
@@ -160,7 +160,7 @@ export default class DefaultContent extends Component {
                   label={'Icon Right'}
                   onClick={this.handleClick}
                   color={'success'}
-                  icon={'audio'}
+                  icon={'unmute'}
                   size={'sm'}
                   iconRight={true}
                   circle={true}
diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx
index d418b8e583c5646f51c3a0a0fa7b233ced343873..91569df6c4ffb0ff41e2a9d248cb657ca17765ca 100755
--- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx
@@ -72,27 +72,13 @@ class PresentationToolbar extends Component {
           aria-controls="skipSlide slideComponent"
           disabled={currentSlideNum > 1 ? false : true}
           color={'default'}
-          icon={'left-arrow'}
+          icon={'left_arrow'}
           size={'md'}
           onClick={actions.previousSlideHandler}
           label={intl.formatMessage(intlMessages.previousSlideLabel)}
           hideLabel={true}
           className={styles.prevSlide}
         />
-        {/*Next Slide button*/}
-        <Button
-          role="button"
-          aria-labelledby="nextSlideLabel"
-          aria-describedby="nextSlideDescrip"
-          aria-controls="skipSlide slideComponent"
-          disabled={currentSlideNum < numberOfSlides ? false : true}
-          color={'default'}
-          icon={'right-arrow'}
-          size={'md'}
-          onClick={actions.nextSlideHandler}
-          label={intl.formatMessage(intlMessages.nextSlideLabel)}
-          hideLabel={true}
-        />
         {/*Skip Slide drop down*/}
         <select
           id="skipSlide"
@@ -108,13 +94,28 @@ class PresentationToolbar extends Component {
         >
           {this.renderSkipSlideOpts(numberOfSlides)}
         </select>
+        {/*Next Slide button*/}
+        <Button
+          role="button"
+          aria-labelledby="nextSlideLabel"
+          aria-describedby="nextSlideDescrip"
+          aria-controls="skipSlide slideComponent"
+          disabled={currentSlideNum < numberOfSlides ? false : true}
+          color={'default'}
+          icon={'right_arrow'}
+          size={'md'}
+          onClick={actions.nextSlideHandler}
+          label={intl.formatMessage(intlMessages.nextSlideLabel)}
+          hideLabel={true}
+        />
+
         {/*Fit to width button
         <Button
           role="button"
           aria-labelledby="fitWidthLabel"
           aria-describedby="fitWidthDescrip"
           color={'default'}
-          icon={'fit-to-width'}
+          icon={'fit_to_width'}
           size={'md'}
           circle={false}
           onClick={this.fitToWidthClickHandler}
@@ -127,7 +128,7 @@ class PresentationToolbar extends Component {
           aria-labelledby="fitScreenLabel"
           aria-describedby="fitScreenDescrip"
           color={'default'}
-          icon={'fit-to-screen'}
+          icon={'fit_to_screen'}
           size={'md'}
           circle={false}
           onClick={this.fitToScreenClickHandler}
diff --git a/bigbluebutton-html5/imports/ui/components/settings/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/component.jsx
old mode 100755
new mode 100644
index 7b462ae3fe7840de0937ff68227fd292ce499642..f99b71b098dda9748a73f26767301cf661058843
--- a/bigbluebutton-html5/imports/ui/components/settings/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/component.jsx
@@ -1,221 +1,163 @@
-import React from 'react';
-import Icon from '/imports/ui/components/icon/component';
-import Button from '/imports/ui/components/button/component';
+import React, { Component, PropTypes } from 'react';
+import { FormattedMessage } from 'react-intl';
 import Modal from '/imports/ui/components/modal/component';
-import AudioMenu from './submenus/audio/component';
-import VideoMenu from './submenus/video/component';
-import ApplicationMenu from './submenus/application/component';
-import UsersMenu from './submenus/users/component';
-import ClosedCaptionsMenuContainer from './submenus/closed-captions/container';
-import classNames from 'classnames';
-import ReactDOM from 'react-dom';
-import styles from './styles.scss';
+import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
 
-export default class Settings extends React.Component {
-  constructor(props) {
-    super(props);
-    this.submenus = [];
-    this.state = { activeSubmenu: 0, focusSubmenu: 0 };
-  }
-
-  renderSettingOptions() {
-    const { isPresenter, role } = this.props;
-
-    this.submenus = [];
-    this.submenus.push(
-      { componentName: AudioMenu, tabIndex: 3,
-        props: { title: 'Audio', prependIconName: 'icon-', icon: 'bbb-audio', }, },
-      { componentName: VideoMenu, tabIndex: 4,
-        props: { title: 'Video', prependIconName: 'icon-', icon: 'bbb-video', }, },
-      { componentName: ApplicationMenu, tabIndex: 5,
-        props: { title: 'Application', prependIconName: 'icon-', icon: 'bbb-application', }, },
-      { componentName: ClosedCaptionsMenuContainer, tabIndex: 7,
-        props: { title: 'Closed Captions', prependIconName: 'icon-', icon: 'bbb-user', }, });
+import ClosedCaptions from '/imports/ui/components/settings/submenus/closed-captions/component';
+import Audio from '/imports/ui/components/settings/submenus/audio/component';
+import Application from '/imports/ui/components/settings/submenus/application/container';
+import Participants from '/imports/ui/components/settings/submenus/participants/component';
+import Video from '/imports/ui/components/settings/submenus/video/component';
 
-    if (isPresenter || role === 'MODERATOR') {
-      this.submenus.push(
-        { componentName: UsersMenu, tabIndex: 6,
-          props: { title: 'Participants', prependIconName: 'icon-', icon: 'bbb-user', }, });
-    }
+import Button from '../button/component';
+import Icon from '../icon/component';
+import styles from './styles';
+import cx from 'classnames';
 
-    return (
-      <div className={styles.full} role='presentation'>
-        <div className={styles.settingsMenuLeft}>
-          <ul className={styles.settingsSubmenu} role='menu'>
-            {this.submenus.map((value, index) => (
-              <li key={index} ref={'submenu' + index} role='menuitem' tabIndex={value.tabIndex}
-                onClick={this.handleClickSubmenu.bind(this, index)}
-                onKeyDown={this.handleKeyDown.bind(this)}
-                onFocus={this.handleFocus.bind(this, index)}
-                className={classNames(styles.settingsSubmenuItem,
-                  index == this.state.activeSubmenu ? styles.settingsSubmenuItemActive : null)}>
-                <Icon key={index} prependIconName={value.props.prependIconName}
-                  iconName={value.props.icon} title={value.props.title}/>
-                <span className={styles.settingsSubmenuItemText}>{value.props.title}</span>
-              </li>
-            ))}
-          </ul>
-        </div>
-        <div className={styles.settingsMenuRight} role='presentation'>
-          {this.renderMenu()}
-        </div>
-      </div>
-    );
-  }
-
-  renderMenu() {
-    let curr = this.state.activeSubmenu === undefined ? 0 : this.state.activeSubmenu;
+const propTypes = {
+};
 
-    if (!this.submenus[curr]) {
-      curr = (this.state.activeSubmenu - 1);
-    }
+export default class Settings extends Component {
+  constructor(props) {
+    super(props);
 
-    let props = {
-      title: this.submenus[curr].props.title,
-      prependIconName: this.submenus[curr].props.prependIconName,
-      icon: this.submenus[curr].props.icon,
-      handleIncreaseFontSize: this.props.handleIncreaseFontSize,
-      handleDecreaseFontSize: this.props.handleDecreaseFontSize,
-      handleGetFontSizeName: this.props.handleGetFontSizeName,
+    const audio = props.audio;
+    const video = props.video;
+    const application = props.application;
+    const cc = props.cc;
+    const participants = props.participants;
+
+    this.state = {
+      current: {
+        audio,
+        video,
+        application,
+        cc,
+        participants,
+      },
+      saved: {
+        audio: _.clone(audio),
+        video: _.clone(video),
+        application: _.clone(application),
+        cc: _.clone(cc),
+        participants: _.clone(participants),
+      },
+      selectedTab: 2,
     };
 
-    const Submenu = this.submenus[curr].componentName;
-    return <Submenu {...props}/>;
-  }
-
-  /* When an option in the menu is clicked, set the activeSubmenu and focusSubmenu
-   * to the value of index. If clicked out of bounds set to 0 or end of submenus array accordingly.
-   *
-   * activeSubmenu: the submenu to be displayed to the user
-   * focusSubmenu: the submenu to set focus to
-   */
-  handleClickSubmenu(i) {
-    if (i <= 0) {
-      this.setState({ activeSubmenu: 0, focusSubmenu: 0, });
-      return;
-    }
-
-    if (i >= this.submenus.length) {
-      this.setState({ activeSubmenu: this.submenus.length - 1,
-        focusSubmenu: this.submenus.length - 1, });
-      return;
-    } else {
-      this.setState({ activeSubmenu: i, focusSubmenu: i, });
-    }
-  }
-
-  /* calls the focus method on an object in the submenu */
-  setFocus() {
-    ReactDOM.findDOMNode(this.refs[`submenu${this.state.focusSubmenu}`]).focus();
-  }
-
-  /* Checks for key presses within the submenu list. Key behaviour varies.
-   *
-   * Tab: changes focus to next submenu or element outside of menu
-   * Shift+Tab: changes focus to previous submenu or element outside of menu
-   * Up Arrow: changes focus to previous submenu, can cycle through menu
-   * Down Arrow: changes focus to next submenu, can cycle through menu
-   * Spacebar: selects submenu in focus and sets as active
-   * Enter: selects submenu in focus and sets as active
-   */
-  handleKeyDown(event) {
-    // tab
-    if (event.keyCode === 9) {
-      let newIndex = 0;
-      if (this.state.focusSubmenu >= this.submenus.length - 1) {
-        newIndex = this.submenus.length - 1;
-      } else {
-        newIndex = this.state.focusSubmenu + 1;
-      }
-
-      this.setState({ focusSubmenu: newIndex });
-      return;
-    }
-
-    // shift+tab
-    if (event.shiftKey && event.keyCode === 9) {
-      let newIndex = 0;
-      if (this.state.focusSubmenu <= 0) {
-        newIndex = 0;
-      } else {
-        newIndex = this.state.focusSubmenu - 1;
-      }
-
-      this.setState({ focusSubmenu: newIndex });
-      return;
-    }
-
-    // up arrow
-    if (event.keyCode === 38) {
-      if (this.state.focusSubmenu <= 0) {
-        this.setState({ focusSubmenu: this.submenus.length - 1 }, function () {
-          this.setFocus();
-        });
-      } else {
-        this.setState({ focusSubmenu: this.state.focusSubmenu - 1 }, function () {
-          this.setFocus();
-        });
-      }
-
-      return;
-    }
-
-    // down arrow
-    if (event.keyCode === 40) {
-      if (this.state.focusSubmenu >= this.submenus.length - 1) {
-        this.setState({ focusSubmenu: 0 }, function () {
-          this.setFocus();
-        });
-      } else {
-        this.setState({ focusSubmenu: this.state.focusSubmenu + 1 }, function () {
-          this.setFocus();
-        });
-      }
-
-      return;
-    }
-
-    // spacebar or enter
-    if (event.keyCode === 32 || event.keyCode === 13) {
-      this.setState({ activeSubmenu: this.state.focusSubmenu });
-      return;
-    }
+    this.handleSettingsApply = props.updateSettings;
+    this.handleUpdateSettings = this.handleUpdateSettings.bind(this);
+    this.handleSelectTab = this.handleSelectTab.bind(this);
   }
 
-  /* Keeps the focusSubmenu variable at the correct value when
-   * tabbing or shift-tabbing out of the submenu array
-   */
-  handleFocus(index) {
-    this.setState({ focusSubmenu: index });
-  }
+  setHtmlFontSize(size) {
+    document.getElementsByTagName('html')[0].style.fontSize = size;
+  };
 
   render() {
-
     return (
       <Modal
         title="Settings"
         confirm={{
           callback: (() => {
-            this.setState({ activeSubmenu: 0, focusSubmenu: 0 });
-            console.log('SHOULD APPLY SETTINGS CHANGES');
-            this.props.handleSaveFontState();
+            this.handleSettingsApply(this.state.current);
           }),
           label: 'Save',
           description: 'Saves the changes and close the settings menu',
         }}
         dismiss={{
           callback: (() => {
-            this.setState({ activeSubmenu: 0, focusSubmenu: 0 });
-            console.log('SHOULD DISCART SETTINGS CHANGES');
-            this.props.handleRevertFontState();
+
+            this.setHtmlFontSize(this.state.saved.application.fontSize);
           }),
           label: 'Cancel',
           description: 'Discart the changes and close the settings menu',
         }}>
-          {this.renderSettingOptions()}
+          {this.renderModalContent()}
       </Modal>
     );
   }
-};
 
-Settings.defaultProps = { title: 'Settings' };
+  handleUpdateSettings(key, newSettings) {
+    let settings = this.state;
+    settings.current[key] = newSettings;
+    this.setState(settings);
+  }
+
+  handleSelectTab(tab) {
+    this.setState({
+      selectedTab: tab,
+    });
+  }
+
+  renderModalContent() {
+    const {
+      isModerator,
+    } = this.props;
+
+    return (
+      <Tabs
+        className={styles.tabs}
+        onSelect={this.handleSelectTab}
+        selectedIndex={this.state.selectedTab}
+      >
+        <TabList className={styles.tabList}>
+          <Tab className={styles.tabSelector}>
+            <Icon iconName='application' className={styles.icon}/>
+            Application
+          </Tab>
+          <Tab className={styles.tabSelector}>
+            <Icon iconName='unmute' className={styles.icon}/>
+            <span>Audio</span>
+          </Tab>
+          <Tab className={styles.tabSelector}>
+            <Icon iconName='video' className={styles.icon}/>
+            Video
+          </Tab>
+          <Tab className={styles.tabSelector}>
+            <Icon iconName='user' className={styles.icon}/>
+            Closed Captions
+          </Tab>
+          { isModerator ?
+            <Tab className={styles.tabSelector}>
+              <Icon iconName='user' className={styles.icon}/>
+              Participants
+            </Tab>
+            : null }
+        </TabList>
+        <TabPanel className={styles.tabPanel}>
+          <Application
+            handleUpdateSettings={this.handleUpdateSettings}
+            settings={this.state.current.application}
+            />
+        </TabPanel>
+        <TabPanel className={styles.tabPanel}>
+          <Audio
+            settings={this.state.current.audio}
+            handleUpdateSettings={this.handleUpdateSettings}/>
+        </TabPanel>
+        <TabPanel className={styles.tabPanel}>
+          <Video
+            handleUpdateSettings={this.handleUpdateSettings}
+            settings={this.state.current.video}
+            />
+        </TabPanel>
+        <TabPanel className={styles.tabPanel}>
+          <ClosedCaptions
+            settings={this.state.current.cc}
+            handleUpdateSettings={this.handleUpdateSettings}
+            locales={this.props.locales}/>
+        </TabPanel>
+        { isModerator ?
+          <TabPanel className={styles.tabPanel}>
+            <Participants
+              settings={this.state.current.participants}
+              handleUpdateSettings={this.handleUpdateSettings}/>
+          </TabPanel>
+          : null }
+      </Tabs>
+    );
+  }
+}
+
+Settings.propTypes = propTypes;
diff --git a/bigbluebutton-html5/imports/ui/components/settings/container.jsx b/bigbluebutton-html5/imports/ui/components/settings/container.jsx
old mode 100755
new mode 100644
index 4074e791fc9ab9514091cde9e9f1b83a14c1e04c..9655fca37b5b14faf19cd874f97c57b01db3ae08
--- a/bigbluebutton-html5/imports/ui/components/settings/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/container.jsx
@@ -1,103 +1,31 @@
-import React, { Component } from 'react';
+import React, { Component, PropTypes } from 'react';
 import { createContainer } from 'meteor/react-meteor-data';
-import Settings from './component';
-import Service from './service';
-import LocalStorage from '/imports/ui/services/storage/local.js';
-
-const DEFAULT_FONTSIZE = 3;
-const MAX_FONTSIZE = 5;
-const MIN_FONTSIZE = 1;
-
-class SettingsMenuContainer extends Component {
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      currentFontSize: LocalStorage.getItem('bbbSavedFontSize') || DEFAULT_FONTSIZE,
-    }
-
-    this.fontControl = {
-      properties: {
-        1: { size: '12px', name: 'Extra Small' },
-        2: { size: '14px', name: 'Small' },
-        3: { size: '16px', name: 'Medium' },
-        4: { size: '18px', name: 'Large' },
-        5: { size: '20px', name: 'Extra Large' },
-      },
-    };
-
-    this.handleGetFontSizeName = this.handleGetFontSizeName.bind(this);
-    this.handleApplyFontSize = this.handleApplyFontSize.bind(this);
-    this.handleIncreaseFontSize = this.handleIncreaseFontSize.bind(this);
-    this.handleDecreaseFontSize = this.handleDecreaseFontSize.bind(this);
-    this.handleSaveFontState = this.handleSaveFontState.bind(this);
-    this.handleRevertFontState = this.handleRevertFontState.bind(this);
-  }
-
-  handleGetFontSizeName() {
-    return this.fontControl.properties[this.state.currentFontSize].name;
-  };
-
-  handleApplyFontSize() {
-    const size = this.fontControl.properties[this.state.currentFontSize].size;
-    document.getElementsByTagName('html')[0].style.fontSize = size;
-  };
-
-  handleIncreaseFontSize() {
-    let fs = ( this.state.currentFontSize < MAX_FONTSIZE) ? ++this.state.currentFontSize : MAX_FONTSIZE;
-    LocalStorage.setItem('bbbFontSize', fs);
-    this.setState({ currentFontSize: fs }, function () {
-      this.handleApplyFontSize();
-    });
-  };
-
-  handleDecreaseFontSize() {
-    let fs = ( this.state.currentFontSize > MIN_FONTSIZE) ? --this.state.currentFontSize : MIN_FONTSIZE;
-    LocalStorage.setItem('bbbFontSize', fs);
-    this.setState({ currentFontSize: fs }, function () {
-      this.handleApplyFontSize();
-    });
-  };
-
-  handleSaveFontState() {
-    let fs = LocalStorage.getItem('bbbFontSize') || DEFAULT_FONTSIZE;
-    LocalStorage.setItem('bbbSavedFontSize', fs);
-    LocalStorage.setItem('bbbSavedFontSizePixels', this.fontControl.properties[fs].size);
-    this.setState({ currentFontSize: fs }, function () {
-      this.handleApplyFontSize();
-    });
-  };
-
-  handleRevertFontState(){
-    let fs = LocalStorage.getItem('bbbSavedFontSize') || DEFAULT_FONTSIZE;
-    this.setState({ currentFontSize: fs }, function () {
-      this.handleApplyFontSize();
-    });
-  };
-
+import _ from 'underscore';
+import Settings from './component.jsx';
+import {
+    getSettingsFor,
+    updateSettings,
+    getClosedCaptionLocales,
+    getUserRoles,
+  } from './service.js';
+
+class SettingsContainer extends Component {
   render() {
-
-    const handleGetFontSizeName = () => this.handleGetFontSizeName();
-    const handleIncreaseFontSize = () => this.handleIncreaseFontSize();
-    const handleDecreaseFontSize = () => this.handleDecreaseFontSize();
-    const handleSaveFontState = () => this.handleSaveFontState();
-    const handleRevertFontState = () => this.handleRevertFontState();
-
     return (
-      <Settings
-        handleGetFontSizeName={handleGetFontSizeName}
-        handleIncreaseFontSize={handleIncreaseFontSize}
-        handleDecreaseFontSize={handleDecreaseFontSize}
-        handleSaveFontState={handleSaveFontState}
-        handleRevertFontState={handleRevertFontState}
-        {...this.props}>
-        {this.props.children}
-      </Settings>
+      <Settings {...this.props}/>
     );
   }
 }
 
 export default createContainer(() => {
-  let data = Service.checkUserRoles();
-  return data;
-}, SettingsMenuContainer);
+  return {
+    audio: getSettingsFor('audio'),
+    video: getSettingsFor('video'),
+    application: getSettingsFor('application'),
+    cc: getSettingsFor('cc'),
+    participants: getSettingsFor('participants'),
+    updateSettings,
+    locales: getClosedCaptionLocales(),
+    isModerator: getUserRoles() === 'MODERATOR',
+  };
+}, SettingsContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/settings/service.js b/bigbluebutton-html5/imports/ui/components/settings/service.js
old mode 100755
new mode 100644
index 401c0464f6f105d86e3d68bfccd68a53f115f895..b008c31985cfcbb02722990d46cb98f5ba546c1e
--- a/bigbluebutton-html5/imports/ui/components/settings/service.js
+++ b/bigbluebutton-html5/imports/ui/components/settings/service.js
@@ -1,17 +1,94 @@
+import Storage from '/imports/ui/services/storage/session';
 import Users from '/imports/api/users';
-import AuthSingleton from '/imports/ui/services/auth/index.js';
+import Captions from '/imports/api/captions';
+import Auth from '/imports/ui/services/auth';
+import _ from 'underscore';
 
-checkUserRoles = () => {
+const updateSettings = (obj) => {
+  Object.keys(obj).forEach(k => Storage.setItem(`settings_${k}`, obj[k]));
+};
+
+const getSettingsFor = (key) => {
+  const setting = Storage.getItem(`settings_${key}`);
+
+  return setting;
+};
+
+const getClosedCaptionLocales = () => {
+  //list of unique locales in the Captions Collection
+  const locales = _.uniq(Captions.find({}, {
+    sort: { locale: 1 },
+    fields: { locale: true },
+  }).fetch().map(function (obj) {
+    return obj.locale;
+  }), true);
+
+  return locales;
+};
+
+const getUserRoles = () => {
   const user = Users.findOne({
-     userId: AuthSingleton.getCredentials().requesterUserId,
-   }).user;
+    userId: Auth.userID,
+  }).user;
 
-  return {
-    isPresenter: user.presenter,
-    role: user.role,
+  return user.role;
+};
+
+const setDefaultSettings = () => {
+  const defaultSettings = {
+    application: {
+      chatAudioNotifications: false,
+      chatPushNotifications: false,
+      fontSize: '14px',
+    },
+    audio: {
+      inputDeviceId: undefined,
+      outputDeviceId: undefined,
+    },
+    video: {
+      viewParticipantsWebcams: true,
+    },
+    cc: {
+      backgroundColor: '#FFFFFF',
+      fontColor: '#000000',
+      closedCaptions: false,
+      fontFamily: 'Calibri',
+      fontSize: -1,
+      locale: undefined,
+      takeOwnership: false,
+    },
+    participants: {
+      muteAll: false,
+      lockAll: false,
+      lockAll: false,
+      microphone: false,
+      publicChat: false,
+      privateChat: false,
+      layout: false,
+    },
+  };
+
+  const savedSettings = {
+    application: getSettingsFor('application'),
+    audio: getSettingsFor('audio'),
+    video: getSettingsFor('video'),
+    cc: getSettingsFor('cc'),
+    participants: getSettingsFor('participants'),
   };
+
+  let settings = {};
+
+  Object.keys(defaultSettings).forEach(key => {
+    settings[key] = _.extend(defaultSettings[key], savedSettings[key]);
+  });
+
+  updateSettings(settings);
 };
 
-export default {
-  checkUserRoles,
+export {
+  updateSettings,
+  getSettingsFor,
+  getClosedCaptionLocales,
+  getUserRoles,
+  setDefaultSettings,
 };
diff --git a/bigbluebutton-html5/imports/ui/components/settings/styles.scss b/bigbluebutton-html5/imports/ui/components/settings/styles.scss
old mode 100755
new mode 100644
index 8f9f3f0524227d9d6b85a705afc8f78355985bbc..27322cf43b2fb04d05e85208c1681eb3db0f974d
--- a/bigbluebutton-html5/imports/ui/components/settings/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/settings/styles.scss
@@ -1,107 +1,58 @@
 @import "../../stylesheets/variables/_all";
 
-.full {
-  clear: both;
-  height: 100%;
-  width: 100%;
-}
-
-.settingsMenuLeft {
-  border-right: 2px solid $color-gray-light;
-  border-top: 2px solid $color-gray-light;
-  float: left;
-  width: 30%;
-  height: 100%;
-  overflow: auto;
-}
-
-.settingsMenuRight {
-  border-top: 2px solid $color-gray-light;
-  float: right;
-  padding-left: 10px;
-  width: 70%;
-  height: 100%;
-  overflow: auto;
-  color: $color-heading;
-}
-
-.settingsSubmenu {
-  list-style-type: none;
-  padding-left: 0px;
-}
-
-.settingsSubmenuItem {
-  color: $color-heading;
-  padding-top: 5px;
-  padding-bottom: 5px;
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-
-.settingsSubmenuItemText {
-  padding-left: 10px;
-  vertical-align: middle;
-}
-
-.settingsSubmenuItemActive {
-  border-right: 4px solid $color-primary;
-  color: $color-primary;
-}
-
-
-
-.containerLeftHalf {
-  width: 50%;
-  float: left;
-}
-
-.containerRightHalf {
-  width: 50%;
-  float: right;
-}
-
-.containerFull{
-  width: 100%;
-  float: right;
-}
-
-.containerLeftHalfContent {
-  @extend .containerLeftHalf;
-  @extend .row;
-}
-
-.containerRightHalfContent {
-  @extend .containerRightHalf;
-  @extend .row;
-}
-
-div.containerLeftHalf label, div.containerRightHalf label {
-  font-size: 0.75em;
-  font-weight: 600;
-  color: $color-primary;
-  margin-bottom: 5px;
-}
-
-.row {
-  height: 42px;
-}
-
-//buttons
-.defaultBtn {
-  width: 90px;
-  border-radius: 18px;
-  border: none;
-  box-shadow: none;
-}
-
-.enterBtn {
-  position: relative;
-  margin-left: 10em;
-  margin-top: 2.5em;
-}
-
-.testAudioBtn {
-  @extend .defaultBtn;
-  width: 140px;
-  margin-top: 0px;
+.tabs {
+  display: flex;
+  flex-flow: row;
+  justify-content: flex-start;
+}
+
+.tabList {
+  display: flex;
+  flex-flow: column;
+  flex-grow: 0;
+  border: none !important;
+  flex-shrink: 0;
+  border-right: 0.2rem solid #d4d9df;
+}
+
+.icon {
+  margin-right: 0.7rem;
+  color: $color-gray-light;
+}
+
+.tabSelector {
+  font-size: 0.9rem;
+  padding: 0.1rem 0 !important;
+  padding-right: 1.2rem !important;
+  display: flex !important;
+  flex-flow: row;
+  justify-content: flex-start;
+  border: none !important;
+  border-radius: 0 !important;
+  bottom: 0 !important;
+  margin: 0.5rem 0;
+  margin-right: 0.5rem;
+  transition: 0.3s color;
+  color: $color-gray-dark;
+
+  &:first-child {
+    margin-top: 0;
+  }
+
+  &[aria-selected="true"] {
+    border-right: 0.2rem solid $color-primary !important;
+    padding-right: 1rem !important;
+    color: $color-link !important;
+
+    &>.icon {
+      color: $color-link !important;
+    }
+  }
+}
+
+.tabPanel {
+  flex-grow: 1;
+  padding: 1rem;
+  padding-top: 0;
+  padding-right: 0;
 }
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
old mode 100755
new mode 100644
index 86e545c7448be77318006c867c53c714208b0ba3..7a1146d62699cf24727f9f2758a81870011871e8
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
@@ -4,83 +4,149 @@ import Icon from '/imports/ui/components/icon/component';
 import Button from '/imports/ui/components/button/component';
 import BaseMenu from '../base/component';
 import ReactDOM from 'react-dom';
+import cx from 'classnames';
 import styles from '../styles.scss';
-import LocalStorage from '/imports/ui/services/storage/local.js';
+import Toggle from '/imports/ui/components/switch/component';
+
+const MIN_FONTSIZE = 0;
+const MAX_FONTSIZE = 4;
 
 export default class ApplicationMenu extends BaseMenu {
   constructor(props) {
     super(props);
+
     this.state = {
-      audioNotifChat: LocalStorage.getItem('audioNotifChat') || Meteor.settings.public.app.audioChatNotification,
-    }
+      settingsName: 'application',
+      settings: props.settings,
+    };
   }
 
-  checkBoxHandler(fieldname) {
-    let obj = {};
-    obj[fieldname] = !this.state[fieldname];
-    LocalStorage.setItem('audioNotifChat', obj[fieldname]);
-    this.setState(obj);
+  handleUpdateFontSize(size) {
+    let obj = this.state;
+    obj.settings.fontSize = size;
+    this.handleUpdateSettings(this.state.settingsName, obj.settings);
+  }
+
+  setHtmlFontSize(size) {
+    document.getElementsByTagName('html')[0].style.fontSize = size;
+  };
+
+  changeFontSize(size) {
+    let obj = this.state;
+    obj.settings.fontSize = size;
+    this.setState(obj, () => {
+      this.setHtmlFontSize(this.state.settings.fontSize);
+      this.handleUpdateFontSize(this.state.settings.fontSize);
+    });
   }
 
-  getContent() {
+  handleIncreaseFontSize() {
+    const currentFontSize = this.state.settings.fontSize;
+    const availableFontSizes = this.props.fontSizes;
+    const canIncreaseFontSize = availableFontSizes.indexOf(currentFontSize) < MAX_FONTSIZE;
+    let fs = (canIncreaseFontSize) ? availableFontSizes.indexOf(currentFontSize) + 1 : MAX_FONTSIZE;
+    this.changeFontSize(availableFontSizes[fs]);
+  };
+
+  handleDecreaseFontSize() {
+    const currentFontSize = this.state.settings.fontSize;
+    const availableFontSizes = this.props.fontSizes;
+    const canDecreaseFontSize = availableFontSizes.indexOf(currentFontSize) > MIN_FONTSIZE;
+    let fs = (canDecreaseFontSize) ? availableFontSizes.indexOf(currentFontSize) - 1 : MIN_FONTSIZE;
+    this.changeFontSize(availableFontSizes[fs]);
+  };
+
+  render() {
     return (
-      <div className={styles.full} role='presentation'>
-          <div className={styles.row} role='presentation'>
-            <label>
-              <input type='checkbox'
-                tabIndex='7'
-                onChange={this.checkBoxHandler.bind(this, "audioNotifChat")}
-                checked={this.state.audioNotifChat}
-                aria-labelledby='audioNotifLabel'
-                aria-describedby='audioNotifDesc'
-              />
-              Audio notifications for chat
-            </label>
-            <div id='audioNotifLabel' hidden>Audio notifications</div>
-            <div id='audioNotifDesc' hidden>
-              Toggles the audio notifications for chat.</div>
-          </div>
-          <div className={styles.row} role='presentation'>
-            <label><input type='checkbox' tabIndex='8' aria-labelledby='pushNotifLabel'
-              aria-describedby='pushNotifDesc' />Push notifications for chat</label>
-            <div id='pushNotifLabel' hidden>Push notifications</div>
-            <div id='pushNotifDesc' hidden>
-              Toggles the push notifications for chat.</div>
-          </div>
-        <div className={styles.applicationFontContainer} role='presentation'>
-          <div className={styles.fontBarLeft}>
-            <p>Font size</p>
+      <div className={styles.tabContent}>
+        <div className={styles.header}>
+          <h3 className={styles.title}>Application</h3>
+        </div>
+        <div className={styles.form}>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Audio notifications for chat
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.settings.chatAudioNotifications}
+                onChange={() => this.handleToggle('chatAudioNotifications')} />
+              </div>
+            </div>
           </div>
-          <div className={styles.fontBarMid}>
-            <p>{this.props.handleGetFontSizeName()}</p>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Push notifications for chat
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.settings.chatPushNotifications}
+                onChange={() => this.handleToggle('chatPushNotifications')} />
+              </div>
+            </div>
           </div>
-          <div className={styles.fontBarRight} role='presentation'>
-            <Button
-              onClick={this.props.handleIncreaseFontSize}
-              icon={'circle-add'}
-              circle={true}
-              tabIndex={9}
-              hideLabel={true}
-              label={'Increase Font'}
-              aria-labelledby={'sizeUpLabel'}
-              aria-describedby={'sizeUpDesc'}
-            />
-            <div id='sizeUpLabel' hidden>Font size up</div>
-            <div id='sizeUpDesc' hidden>
-              Increases the font size of the application.</div>
-            <Button
-              onClick={this.props.handleDecreaseFontSize}
-              icon={'circle-minus'}
-              circle={true}
-              tabIndex={10}
-              hideLabel={true}
-              label={'Decrease Font'}
-              aria-labelledby={'sizeDownLabel'}
-              aria-describedby={'sizeDownDesc'}
-            />
-          <div id='sizeDownLabel' hidden>Font size down</div>
-          <div id='sizeDownDesc' hidden>
-            Decreases the font size of the application.</div>
+          <hr className={styles.separator}/>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Font size
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentCenter)}>
+                <label className={cx(styles.label, styles.bold)}>
+                  {this.state.settings.fontSize}
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <div className={styles.pullContentRight}>
+                  <div className={styles.col}>
+                    <Button
+                      onClick={() => this.handleIncreaseFontSize()}
+                      color={'success'}
+                      icon={'add'}
+                      circle={true}
+                      tabIndex='0'
+                      hideLabel={true}
+                      label={'Increase Font'}
+                      aria-labelledby={'sizeUpLabel'}
+                      aria-describedby={'sizeUpDesc'}
+                    />
+                    <div id='sizeUpLabel' hidden>Font size up</div>
+                  </div>
+                  <div className={styles.col}>
+                    <Button
+                      onClick={() => this.handleDecreaseFontSize()}
+                      color={'success'}
+                      icon={'substract'}
+                      circle={true}
+                      tabIndex='0'
+                      hideLabel={true}
+                      label={'Decrease Font'}
+                      aria-labelledby={'sizeDownLabel'}
+                      aria-describedby={'sizeDownDesc'}
+                    />
+                    <div id='sizeUpDesc' hidden>Increases the font size of the application.</div>
+                  </div>
+                </div>
+              </div>
+            </div>
           </div>
         </div>
       </div>
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/container.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/container.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8147532e491581dd7b3ca92109bc54d4a9f237bb
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/container.jsx
@@ -0,0 +1,26 @@
+import React, { Component, PropTypes } from 'react';
+import { createContainer } from 'meteor/react-meteor-data';
+import Application from './component';
+
+// import Service from './service';
+
+class ApplicationContainer extends Component {
+  render() {
+    return (
+      <Application {...this.props}>
+        {this.props.children}
+      </Application>
+    );
+  }
+}
+export default createContainer(() => {
+  return {
+    fontSizes: [
+      '12px',
+      '14px',
+      '16px',
+      '18px',
+      '20px',
+    ],
+  };
+}, ApplicationContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/component.jsx
old mode 100755
new mode 100644
index a2edd817a3c31e5e50a28cffc4b462a4f58092c1..3bf6c28e11b5a9496aab4217faa0499c2dd03a82
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/component.jsx
@@ -1,10 +1,11 @@
-import React from 'react';
+import React, { Component } from 'react';
 import BaseMenu from '../base/component';
 import styles from '../styles.scss';
 
 import DeviceSelector from '/imports/ui/components/audio/device-selector/component';
 import AudioStreamVolume from '/imports/ui/components/audio/audio-stream-volume/component';
 import AudioTestContainer from '/imports/ui/components/audio-test/container';
+import cx from 'classnames';
 
 export default class AudioMenu extends BaseMenu {
   constructor(props) {
@@ -13,7 +14,8 @@ export default class AudioMenu extends BaseMenu {
     this.handleOutputChange = this.handleOutputChange.bind(this);
 
     this.state = {
-      inputDeviceId: undefined,
+      settingsName: 'audio',
+      settings: props.settings,
     };
   }
 
@@ -21,31 +23,77 @@ export default class AudioMenu extends BaseMenu {
     this.props.changeMenu(this.props.JOIN_AUDIO);
   }
 
+  handleSelectChange(fieldname, options, e) {
+    let obj = this.state;
+    obj.settings[fieldname] = options[e.target.value];
+    this.setState(obj);
+    this.handleUpdateSettings('audio', obj);
+  }
+
   handleInputChange(deviceId) {
-    console.log(`INPUT DEVICE CHANGED: ${deviceId}`);
-    this.setState({
-      inputDeviceId: deviceId,
-    });
+    let obj = this.state;
+    obj.settings.inputDeviceId = deviceId;
+    this.setState(obj);
+    this.handleUpdateSettings('audio', obj);
   }
 
   handleOutputChange(deviceId) {
-    console.log(`OUTPUT DEVICE CHANGED: ${deviceId}`);
+    let obj = this.state;
+    obj.settings.outputDeviceId = deviceId;
+    this.setState(obj);
+    this.handleUpdateSettings('audio', obj);
   }
 
-  getContent() {
+  render() {
     return (
-      <div className={styles.full} role='presentation'>
-        <div className={styles.containerLeftHalf}>
-          <DeviceSelector
-            kind="audioinput"
-            onChange={this.handleInputChange} />
-          <DeviceSelector
-            kind="audiooutput"
-            onChange={this.handleOutputChange} />
+      <div className={styles.tabContent}>
+        <div className={styles.header}>
+          <h3 className={styles.title}>Audio</h3>
         </div>
-        <div className={styles.containerRightHalf}>
-          <AudioStreamVolume deviceId={this.state.inputDeviceId}/>
-          <AudioTestContainer  />
+
+        <div className={styles.form}>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={cx(styles.label, styles.labelSmall)}>
+                  Microphone source
+                </label>
+                <DeviceSelector
+                  value={this.state.inputDeviceId}
+                  className={styles.select}
+                  kind="audioinput"
+                  onChange={this.handleInputChange} />
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={cx(styles.label, styles.labelSmall)}>
+                  Your audio stream volume
+                </label>
+                <AudioStreamVolume
+                  deviceId={this.state.inputDeviceId}
+                  className={styles.audioMeter} />
+              </div>
+            </div>
+          </div>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={cx(styles.label, styles.labelSmall)}>
+                  Speaker source
+                </label>
+                <DeviceSelector
+                  value={this.state.outputDeviceId}
+                  className={styles.select}
+                  kind="audiooutput"
+                  onChange={this.handleOutputChange} />
+                </div>
+            </div>
+            <div className={styles.col}>
+              <label className={styles.label}>&nbsp;</label>
+              <AudioTestContainer/>
+            </div>
+          </div>
         </div>
       </div>
     );
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/container.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/container.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..af91c3b19c089f17793bb8986efeda8dc7f1ada0
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/audio/container.jsx
@@ -0,0 +1,17 @@
+import React, { Component, PropTypes } from 'react';
+import { createContainer } from 'meteor/react-meteor-data';
+import Audio from './component';
+
+class AudioContainer extends Component {
+  render() {
+    return (
+      <Audio {...this.props}>
+        {this.props.children}
+      </Audio>
+    );
+  }
+}
+
+export default createContainer(() => {
+  return {};
+}, AudioContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/base/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/base/component.jsx
index e57e02c9d395f51dfa33bd640cbac31465b9b339..fb105ff8b903b51d23aed7cf873984099c47d551 100644
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/base/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/base/component.jsx
@@ -7,20 +7,16 @@ import styles from '../styles.scss';
 export default class BaseMenu extends React.Component {
   constructor(props) {
     super(props);
-  }
 
-  getContent() {
-    return (<div>parent content</div>);
+    this.handleUpdateSettings = props.handleUpdateSettings;
   }
 
-  render() {
-    return (
-      <div className={styles.full} role='presentation'>
-        <h3 className={styles.submenuTitle}>{this.props.title}</h3>
-        <div className={styles.submenuContent} role='presentation'>
-          {this.getContent()}
-        </div>
-      </div>
-    );
+  handleToggle(key) {
+    let obj = this.state;
+    obj.settings[key] = !this.state.settings[key];
+
+    this.setState(obj, () => {
+      this.handleUpdateSettings(this.state.settingsName, this.state.settings);
+    });
   }
 };
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/component.jsx
old mode 100755
new mode 100644
index 9289eb241247e19bedcbe609cb93c6281ef5e6cc..01675fbbf395d6a7b81b9f8251ac9609b1603d98
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/component.jsx
@@ -1,59 +1,48 @@
 import React from 'react';
 import Modal from 'react-modal';
-import Icon from '/imports/ui/components/icon/component';
-import Button from '/imports/ui/components/button/component';
-import BaseMenu from '../base/component';
 import styles from '../styles';
-import Storage from '/imports/ui/services/storage/session';
+import cx from 'classnames';
+import BaseMenu from '../base/component';
+import Toggle from '/imports/ui/components/switch/component';
+import Checkbox from '/imports/ui/components/checkbox/component';
 import { GithubPicker } from 'react-color';
 
 //an array of font-families
-const fonts = ["Arial", "Calibri", "Time New Roman", "Sans-serif"];
+const FONT_FAMILIES = ['Arial', 'Calibri', 'Time New Roman', 'Sans-serif'];
+
 //an array of different font-sizes
-const fontSizes = [12, 14, 18, 24, 32, 42];
+const FONT_SIZES = ['12px', '14px', '18px', '24px', '32px', '42px'];
+
 //an array of colors for both background and text
-const colors = ['#000000', '#7A7A7A' ,'#FF0000', '#FF8800', '#88FF00', '#FFFFFF', '#00FFFF', '#0000FF', '#8800FF', '#FF00FF'];
+const COLORS =  [
+                  '#000000', '#7A7A7A', '#FF0000', '#FF8800',
+                  '#88FF00', '#FFFFFF', '#00FFFF', '#0000FF',
+                  '#8800FF', '#FF00FF',
+                ];
 
 export default class ClosedCaptionsMenu extends BaseMenu {
   constructor(props) {
     super(props);
     this.state = {
-      closedCaptions: this.props.ccEnabled ? true : false,
-      locales: this.props.locales,
-
-      //default values for the input select fields (to display "Choose ..")
-      ccLocale: -1,
-      ccFontFamily: -1,
-      ccFontSize: -1,
-
-      //actual default values for the previewing the text in the box
-      ccFontSizeValue: Storage.getItem('ccFontSize') ? Storage.getItem('ccFontSize') : 18,
-      ccFontFamilyValue: Storage.getItem('ccFontFamily') ? Storage.getItem('ccFontFamily') : 'Arial',
-
-      //background defaults to white (well, almost white, light grey looks better)
-      ccBackgroundColor: Storage.getItem('ccBackgroundColor') ? Storage.getItem('ccBackgroundColor') : '#f3f6f9',
-
-      //font color defaults to black
-      ccFontColor: Storage.getItem('ccFontColor') ? Storage.getItem('ccFontColor') : '#000000',
-      displayBackgroundColorPicker: false,
-      displayFontColorPicker: false,
-    }
+      settingsName: 'cc',
+      settings: {
+        backgroundColor: props.settings ? props.settings.backgroundColor : '#f3f6f9',
+        fontColor: props.settings ? props.settings.fontColor : '#000000',
+        closedCaptions: props.settings ? props.settings.closedCaptions : false,
+        fontFamily: props.settings ? props.settings.fontFamily : 'Calibri',
+        fontSize: props.settings ? props.settings.fontSize : -1,
+        locale: props.settings ? props.settings.locale : -1,
+        takeOwnership: props.settings ? props.settings.takeOwnership : false,
+      },
+    };
   }
 
-  checkBoxHandler(fieldname) {
-    var obj = {};
-    obj[fieldname] = !this.state[fieldname];
-    Storage.setItem('closedCaptions', obj[fieldname]);
-    this.setState(obj);
-  }
-
-  //select handler for the locale, font-size and font-family
-  selectHandler(fieldname, collectionName, event) {
-    Storage.setItem(fieldname, this.props[collectionName][event.target.value]);
-    var obj ={};
-    obj[fieldname] = event.target.value;
-    obj[fieldname + "Value"] = this.props[collectionName][event.target.value];
-    this.setState(obj);
+  getPreviewStyle() {
+    return {
+      fontFamily: this.state.settings.fontFamily,
+      fontSize: this.state.settings.fontSize,
+      color: this.state.settings.fontColor,
+    };
   }
 
   //clickhandler, opens a selected color picker (supports both of them)
@@ -65,171 +54,247 @@ export default class ClosedCaptionsMenu extends BaseMenu {
 
   //closes color pickers
   handleCloseColorPicker() {
-    this.setState({ displayBackgroundColorPicker: false, displayFontColorPicker:false })
+    this.setState({
+      displayBackgroundColorPicker: false,
+      displayFontColorPicker:false,
+    });
+  }
+
+  handleSelectChange(fieldname, options, e) {
+    let obj = this.state;
+    obj.settings[fieldname] = options[e.target.value];
+    this.setState(obj);
+    this.handleUpdateSettings('cc', obj.settings);
   }
 
-  //change handler for both color pickers
   handleColorChange(fieldname, color) {
-    var obj = {};
-    obj[fieldname] = color.hex;
-    Storage.setItem(fieldname, color.hex);
+    let obj = this.state;
+    obj.settings[fieldname] = color.hex;
+
     this.setState(obj);
+    this.handleUpdateSettings('cc', obj.settings);
+    this.handleCloseColorPicker();
   }
 
-  getContent() {
+  render() {
+    const {
+      locales,
+    } = this.props;
+
     return (
-      <div className={styles.full} role='presentation'>
-        <div className={styles.row} role='presentation'>
-          <label>
-            <input
-              className={styles.checkboxOffset}
-              type='checkbox'
-              tabIndex='7'
-              aria-labelledby='closedCaptionsLabel'
-              aria-describedby='closedCaptionsDesc'
-              onChange={this.checkBoxHandler.bind(this, "closedCaptions")}
-              checked={this.state.closedCaptions}
-            />
-            Closed captions
-          </label>
+      <div className={styles.tabContent}>
+        <div className={styles.header}>
+          <h3 className={styles.title}>Closed Captions</h3>
         </div>
-        <div id='closedCaptionsLabel' hidden>Closed-captions button</div>
-        <div id='closedCaptionsDesc' hidden>Toggles closed-captioning module</div>
-
-        <div className={styles.indentedRow} role='presentation'>
-          <label>
-            <input
-              className={styles.checkboxOffset}
-              type='checkbox'
-              tabIndex='8'
-              aria-labelledby='takeOwnershipLabel'
-              aria-describedby='takeOwnershipDesc'
-            />
-            Take ownership
-          </label>
-        </div>
-        <div id='takeOwnershipLabel' hidden>Closed-captions take ownership</div>
-        <div id='takeOwnershipDesc' hidden>Take ownership of closed-captions</div>
-
-        <div className={styles.indentedRow} role='presentation'>
-          <div className={styles.containerLeftHalf}>Language</div>
-          <div className={styles.containerRightHalfContent} role='presentation'>
-              <select defaultValue={this.state.ccLocale} tabIndex='9'
-                aria-labelledby='ccLanguageLabel' aria-describedby='ccLanguageDesc'
-                onChange={this.selectHandler.bind(this, "ccLocale", "locales")}>
-                <option value='-1' disabled>{this.props.locales && this.props.locales.length > 0 ? "Choose language" : "No active locales" }</option>
+        <div className={styles.form}>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Closed captions
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.settings.closedCaptions}
+                onChange={() => this.handleToggle('closedCaptions')} />
+              </div>
+            </div>
+          </div>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Take ownership
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <Checkbox
+                  onChange={() => this.handleToggle('takeOwnership')}
+                  checked={this.state.settings.takeOwnership}/>
+              </div>
+            </div>
+          </div>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Language
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <select
+                  defaultValue={locales ? locales.indexOf(this.state.settings.locale) : -1}
+                  className={styles.select}
+                  onChange={this.handleSelectChange.bind(this, 'locale', this.props.locales)}>
+                <option>
+                  { this.props.locales &&
+                    this.props.locales.length ?
+                    'Choose language' :
+                    'No active locales' }
+                </option>
                 {this.props.locales ? this.props.locales.map((locale, index) =>
-                  <option key={index} value={index}>{locale}</option>
-                )
-                : null }
-              </select>
-            <div id='ccLanguageLabel' hidden>Language</div>
-            <div id='ccLanguageDesc' hidden>Chooses the language from currently active locales.</div>
+                  <option key={index} value={index}>
+                    {locale}
+                  </option>
+                ) : null }
+                </select>
+              </div>
+            </div>
           </div>
-        </div>
 
-        <div className={styles.indentedRow} role='presentation'>
-          <div className={styles.containerLeftHalf}>Font-Family</div>
-          <div className={styles.containerRightHalfContent} role='presentation'>
-              <select defaultValue={this.state.ccFontFamily} tabIndex='10'
-                aria-labelledby='ccFontFamilyLabel' aria-describedby='ccFontfamilyDesc'
-                onChange={this.selectHandler.bind(this, "ccFontFamily", "fonts")}>
-                <option value='-1' disabled>Choose font-family</option>
-                {this.props.fonts ? this.props.fonts.map((font, index) =>
-                  <option key={index} value={index}>{font}</option>
-                )
-                : null }
-              </select>
-            <div id='ccFontFamilyLabel' hidden>Font-Family</div>
-            <div id='ccFontfamilyDesc' hidden>Chooses the Font-Family from the dropdown menu.</div>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Font family
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <select
+                  defaultValue={FONT_FAMILIES.indexOf(this.state.settings.fontFamily)}
+                  onChange={this.handleSelectChange.bind(this, 'fontFamily', FONT_FAMILIES)}
+                  className={styles.select}>
+                  <option value='-1' disabled>Choose Font-family</option>
+                  {
+                    FONT_FAMILIES.map((family, index) =>
+                      <option key={index} value={index}>
+                        {family}
+                      </option>
+                    )
+                  }
+                </select>
+              </div>
+            </div>
           </div>
-        </div>
 
-        <div className={styles.indentedRow} role='presentation'>
-          <div className={styles.containerLeftHalf}>Font-Size</div>
-          <div className={styles.containerRightHalfContent} role='presentation'>
-              <select defaultValue={this.state.ccFontSize} tabIndex='11'
-                aria-labelledby='ccFontSizeLabel' aria-describedby='ccFontSizeDesc'
-                onChange={this.selectHandler.bind(this, "ccFontSize", "fontSizes")}>
-                <option value='-1' disabled>Choose Font-size</option>
-                {this.props.fontSizes ? this.props.fontSizes.map((size, index) =>
-                  <option key={index} value={index}>{size + 'px'}</option>
-                )
-                : null }
-              </select>
-            <div id='ccFontSizeLabel' hidden>Font-Size</div>
-            <div id='ccFontSizeDesc' hidden>Chooses the Font-Size from the dropdown menu.</div>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Font size
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <select
+                  defaultValue={FONT_SIZES.indexOf(this.state.settings.fontSize)}
+                  onChange={this.handleSelectChange.bind(this, 'fontSize', FONT_SIZES)}
+                  className={styles.select}>
+                  <option value='-1' disabled>Choose Font-size</option>
+                  {
+                    FONT_SIZES.map((size, index) =>
+                      <option key={index} value={index}>
+                        {size}
+                      </option>
+                    )
+                  }
+                </select>
+              </div>
+            </div>
           </div>
-        </div>
 
-        <div className={styles.indentedRow} role='presentation'>
-          <div className={styles.containerLeftHalf}>Background Color</div>
-          <div className={styles.containerRightHalfContent} role='presentation'>
-            <div
-              tabIndex='12'
-              className={ styles.swatch }
-              onClick={ this.handleColorPickerClick.bind(this, "displayBackgroundColorPicker") }>
-              <div
-                className={styles.swatchInner}
-                style={{'background': this.state.ccBackgroundColor}}/>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Background color
+                </label>
+              </div>
             </div>
-            { this.state.displayBackgroundColorPicker ?
-              <div className={styles.colorPickerPopover}>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
               <div
-                className={styles.colorPickerOverlay}
-                onClick={ this.handleCloseColorPicker.bind(this) }
-              />
-                <GithubPicker
-                  color={this.state.ccBackgroundColor}
-                  onChange={this.handleColorChange.bind(this, "ccBackgroundColor")}
-                  colors={this.props.colors}
-                  width={'140px'}
-                  triangle={'top-right'}
-                />
-              </div>
-            : null }
+                tabIndex='12'
+                className={ styles.swatch }
+                onClick={ this.handleColorPickerClick.bind(this, 'displayBackgroundColorPicker') }>
+                <div
+                  className={styles.swatchInner}
+                  style={ { background: this.state.settings.backgroundColor } }>
+                </div>
+
+              </div>
+                { this.state.displayBackgroundColorPicker ?
+                  <div className={styles.colorPickerPopover}>
+                    <div
+                      className={styles.colorPickerOverlay}
+                      onClick={ this.handleCloseColorPicker.bind(this) }
+                    >
+                    </div>
+                    <GithubPicker
+                      onChange={this.handleColorChange.bind(this, 'backgroundColor')}
+                      color={this.state.settings.backgroundColor}
+                      colors={COLORS}
+                      width={'140px'}
+                      triangle={'top-right'}
+                    />
+                  </div>
+                : null }
+              </div>
+            </div>
           </div>
-        </div>
 
-        <div className={styles.indentedRow} role='presentation'>
-          <div className={styles.containerLeftHalf}>Text Color</div>
-          <div className={styles.containerRightHalfContent} role='presentation'>
-            <div
-              tabIndex='12'
-              className={ styles.swatch }
-              onClick={ this.handleColorPickerClick.bind(this, "displayFontColorPicker") }>
-              <div
-                className={styles.swatchInner}
-                style={{'background': this.state.ccFontColor}}/>
+          <div className={cx(styles.row, styles.spacedLeft)}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Font color
+                </label>
+              </div>
             </div>
-            { this.state.displayFontColorPicker ?
-              <div className={styles.colorPickerPopover}>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
               <div
-                className={styles.colorPickerOverlay}
-                onClick={ this.handleCloseColorPicker.bind(this) }
-              />
-                <GithubPicker
-                  color={this.state.ccFontColor}
-                  onChange={this.handleColorChange.bind(this, "ccFontColor")}
-                  colors={this.props.colors}
-                  width={'140px'}
-                  triangle={'top-right'}
-                />
-              </div>
-            : null }
+                tabIndex='12'
+                className={ styles.swatch }
+                onClick={ this.handleColorPickerClick.bind(this, 'displayFontColorPicker') }>
+                <div
+                  className={styles.swatchInner}
+                  style={ { background: this.state.settings.fontColor } }>
+                </div>
+
+              </div>
+                { this.state.displayFontColorPicker ?
+                  <div className={styles.colorPickerPopover}>
+                    <div
+                      className={styles.colorPickerOverlay}
+                      onClick={ this.handleCloseColorPicker.bind(this) }
+                    >
+                    </div>
+                    <GithubPicker
+                      onChange={this.handleColorChange.bind(this, 'fontColor')}
+                      color={this.state.settings.fontColor}
+                      colors={COLORS}
+                      width={'140px'}
+                      triangle={'top-right'}
+                    />
+                  </div>
+                : null }
+              </div>
+            </div>
           </div>
-        </div>
 
-        <div className={styles.ccPreviewBox} role='presentation' style={{background: this.state.ccBackgroundColor}}>
-          <span style={{fontFamily: this.state.ccFontFamilyValue, fontSize: this.state.ccFontSizeValue+'px', color: this.state.ccFontColor}}>Etiam porta sem malesuada magna mollis euis-mod. Donec ullamcorper nulla non metus auctor fringilla.</span>
+          <div
+            className={cx(styles.ccPreviewBox, styles.spacedLeft)}
+            role='presentation'
+            style={ { background: this.state.settings.backgroundColor } }>
+            <span style={this.getPreviewStyle()}>
+              Etiam porta sem malesuada magna mollis euis-mod.
+              Donec ullamcorper nulla non metus auctor fringilla.
+            </span>
+          </div>
         </div>
       </div>
     );
   }
 };
-
-ClosedCaptionsMenu.defaultProps = {
-  fonts: fonts,
-  fontSizes: fontSizes,
-  colors: colors
-};
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/container.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/container.jsx
old mode 100755
new mode 100644
index 5d488fe8e39a379bba5df9af41d69f09be3da84a..03fdd866f89611f104694ea2a71f9a24422fe043
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/container.jsx
@@ -4,10 +4,6 @@ import ClosedCaptionsMenu from './component';
 import Service from './service';
 
 class ClosedCaptionsMenuContainer extends Component {
-  constructor(props) {
-    super(props);
-  }
-
   render() {
     return (
       <ClosedCaptionsMenu {...this.props}>
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/service.js b/bigbluebutton-html5/imports/ui/components/settings/submenus/closed-captions/service.js
old mode 100755
new mode 100644
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/participants/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/participants/component.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..428e0def6a63dfb2638a9f5d32e488c7299f9f17
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/participants/component.jsx
@@ -0,0 +1,141 @@
+import React from 'react';
+import Modal from 'react-modal';
+import Icon from '/imports/ui/components/icon/component';
+import Button from '/imports/ui/components/button/component';
+import BaseMenu from '../base/component';
+import ReactDOM from 'react-dom';
+import cx from 'classnames';
+import styles from '../styles.scss';
+import Toggle from '/imports/ui/components/switch/component';
+import Checkbox from '/imports/ui/components/checkbox/component';
+
+export default class ApplicationMenu extends BaseMenu {
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      settings: props.settings,
+    };
+
+    this.handleUpdateSettings = props.handleUpdateSettings;
+  }
+
+  getLockItems() {
+    return [
+      {
+        key: 'webcam',
+        label: 'Webcam',
+        ariaLabelledBy: 'webcamLabel',
+        ariaDescribedBy: 'webcamDesc',
+        ariaLabel: 'Webcam lock',
+        ariaDesc: 'Disables the webcam for all locked participants.',
+      },
+      {
+        key: 'microphone',
+        label: 'Microphone',
+        ariaLabelledBy: 'micLabel',
+        ariaDescribedBy: 'micDesc',
+        ariaLabel: 'Microphone lock',
+        ariaDesc: 'Disables the microphone for all locked participants.',
+      },
+      {
+        key: 'publicChat',
+        ariaLabelledBy: 'pubChatLabel',
+        ariaDescribedBy: 'pubChatDesc',
+        ariaLabel: 'Public chat lock',
+        ariaDesc: 'Disables public chat for all locked participants.',
+        label: 'Public Chat',
+      },
+      {
+        key: 'privateChat',
+        label: 'Private Chat',
+        ariaLabelledBy: 'privChatLabel',
+        ariaDescribedBy: 'privChatDesc',
+        ariaLabel: 'Private chat lock',
+        ariaDesc: 'Disables private chat for all locked participants.',
+      },
+      {
+        key: 'layout',
+        ariaLabelledBy: 'layoutLabel',
+        ariaDescribedBy: 'layoutDesc',
+        ariaLabel: 'Layout lock',
+        ariaDesc: 'Locks layout for all locked participants.',
+        label: 'Layout',
+      },
+    ];
+  }
+
+  render() {
+    return (
+      <div className={styles.tabContent}>
+        <div className={styles.header}>
+          <h3 className={styles.title}>Participants</h3>
+        </div>
+        <div className={styles.form}>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Mute all except the presenter
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.settings.muteAll}
+                onChange={() => this.handleToggle('muteAll')} />
+              </div>
+            </div>
+          </div>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Lock all participants
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.settings.lockAll}
+                onChange={() => this.handleToggle('lockAll')}
+                 />
+              </div>
+            </div>
+          </div>
+          {this.getLockItems().map((item, i)  => this.renderLockItem(item, i))}
+        </div>
+      </div>
+    );
+  }
+
+  renderLockItem({ label, key, ariaLabel, ariaLabelledBy, ariaDesc, ariaDescribedBy }, i) {
+    return (
+      <div key={i} className={cx(styles.row, styles.spacedLeft)}>
+        <div className={styles.col}>
+          <div className={styles.formElement}>
+            <label className={styles.label}>
+              {label}
+            </label>
+          </div>
+        </div>
+        <div className={styles.col}>
+          <div className={cx(styles.formElement, styles.pullContentRight)}>
+            <Checkbox
+              onChange={() => this.handleToggle(key)}
+              checked={this.state.settings[key]}
+              ariaLabel={ariaLabel}
+              ariaLabelledBy={ariaLabelledBy}
+              ariaDesc={ariaDesc}
+              ariaDescribedBy={ariaDescribedBy}
+              />
+          </div>
+        </div>
+      </div>
+    );
+  }
+};
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/styles.scss b/bigbluebutton-html5/imports/ui/components/settings/submenus/styles.scss
old mode 100755
new mode 100644
index 1602a66fed46b09d0a37b9aea3996d9248df39c7..ded881407806b567426813e6e1672b56c9b9b585
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/styles.scss
@@ -1,173 +1,111 @@
 @import "../../../stylesheets/variables/_all";
 
-/* General Submenu */
-.submenuTitle {
-  height: 45px;
-  margin: 0px;
-  padding-top: 12px;
-  font-size: $font-size-large;
-  font-weight: $headings-font-weight;
-}
-
-.submenuContent {
-  height: 85%;
-  margin: 0px;
-  padding-top: 12px;
-  font-size: $font-size-base;
-  color: $color-gray-light;
-}
-
-div.submenuContent select {
-  width: 90%;
-  padding-top: 5px;
-  border-top: none;
-  border-left: none;
-  border-right: none;
-  /*outline: none;*/
-  color: $color-gray-light;
-}
-
-.containerLeftHalf {
-  width: 50%;
-  float: left;
-}
-
-.containerRightHalf {
-  width: 50%;
-  float: right;
-}
-
-.containerFull{
-  width: 100%;
-  float: right;
-}
-
-.containerLeftHalfContent {
-  @extend .containerLeftHalf;
-  @extend .row;
-}
-
-.containerRightHalfContent {
-  @extend .containerRightHalf;
-  @extend .row;
+.title {
+  color: $color-gray-dark;
+  font-weight: 400;
+  font-size: 1.3rem;
+  margin: 0;
+  margin-bottom: 1.5rem;
 }
 
-div.containerLeftHalf label, div.containerRightHalf label {
-  font-size: 0.75em;
-  font-weight: 600;
-  color: $color-primary;
-  margin-bottom: 5px;
+.form {
+  display: flex;
+  flex-flow: column;
 }
 
-input[type=checkbox] {
-    float: right;
+.row {
+  display: flex;
+  flex-flow: row;
+  flex-grow: 1;
+  justify-content: space-between;
+  margin-bottom: 0.7rem;
 }
 
-ul {
-  list-style-type: none;
-  margin: 0px;
-}
+.col {
+  display: flex;
+  flex-grow: 1;
+  flex-basis: 0;
+  margin-right: 1rem;
 
-ul li {
-  padding-bottom: 9%;
+  &:last-child {
+    margin-right: 0;
+    padding-right: 0.1rem;
+  }
 }
 
-/* Application Submenu */
-.applicationFontContainer {
-  border-top: solid 1px $color-gray-light;
-  margin-top: 10%;
-  padding-top: 10%;
-}
-
-.fontBarLeft {
-  float: left;
-  margin: 0px;
-  height: 100%;
-  width: 25%;
-  text-align: left;
-}
-
-.fontBarMid {
-  float: left;
-  margin: 0px;
-  height: 100%;
-  width: 50%;
-  text-align: center;
-  font-weight: 600;
+.label {
+  color: $color-gray-light;
+  font-size: 0.9rem;
+  margin-bottom: 0.5rem;
 }
 
-.fontBarRight {
-  float: left;
-  margin: 0px;
-  height: 100%;
-  width: 25%;
-  text-align: right;
+.labelSmall {
+  color: $color-link;
+  font-size: 0.7rem;
+  margin-bottom: 0.3rem;
 }
 
-.fontBarLeft p, .fontBarMid p {
-  margin: 0px;
+.formElement {
+  position: relative;
+  display: flex;
+  flex-flow: column;
+  flex-grow: 1;
 }
 
-/* Users Submenu */
-.checkboxOffset {
-  margin-right: 5%;
+.select {
+  background-color: #fff;
+  border: 0;
+  border-bottom: 0.1rem solid $color-gray-lighter;
+  color: $color-gray-light;
+  width: 100%;
+  // appearance: none;
+  height: 1.75rem;
 }
 
-
-/* Buttons */
-.defaultBtn {
-  width: 90px;
-  border-radius: 18px;
-  border: none;
-  box-shadow: none;
+.audioMeter {
+  width: 100%;
 }
 
-.testAudioBtn {
-  @extend .defaultBtn;
-  width: 140px;
-  float: left;
+.pullContentRight {
+  display: flex;
+  justify-content: flex-end;
+  flex-flow: row;
 }
 
-/* Submenu containers */
-.full {
-  clear: both;
-  height: 100%;
-  width: 100%;
+.pullContentCenter {
+  display: flex;
+  justify-content: center;
+  flex-flow: row;
 }
 
-.row {
-  height: 42px;
+.separator {
+  margin: 2.5rem 0;
+  border: 1px solid $color-gray-lighter;
+  opacity: 0.25;
 }
 
-.indentedRow {
-  @extend .row;
-  padding-left: 10%;
+.bold {
+  font-weight: bold;
 }
 
-.ccPreviewBox {
-  height: 100px;
-  margin-left: 10%;
-  margin-right: 5%;
-  padding: 5px;
-  border: 1px solid #f1f1f1;
-  overflow: auto;
+.spacedLeft {
+  margin-left: 1rem;
 }
 
 .swatch {
+  position: absolute;
   float: right;
-  margin-right: 10%;
-  padding: 5px;
   background: #fff;
-  border-radius: 1px;
-  box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
+  border-radius: 5px;
+  border: 2px solid $color-gray-light;
   display: inline-block;
   cursor: pointer;
 }
 
 .swatchInner {
-  width: 36px;
-  height: 14px;
-  border-radius: 2px;
+  width: 3rem;
+  height: 1.1rem;
+  border-radius: 3px;
 }
 
 .colorPickerOverlay {
@@ -179,6 +117,14 @@ ul li {
 }
 
 .colorPickerPopover {
-  //it has to be bigger than the overlay of the settings modal
+  position: absolute;
+  top: 2rem;
   z-index: 1001;
 }
+
+.ccPreviewBox {
+  height: 100px;
+  padding: 5px;
+  border: 1px solid #f1f1f1;
+  overflow: auto;
+}
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/users/component.jsx
deleted file mode 100755
index 6bcaaa9e89ee2bf346956d53210cd66e4412157b..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/component.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import BaseMenu from '../base/component';
-import ParticipantsMenuContainer from './participants/container';
-
-export default class UsersMenu extends BaseMenu {
-  constructor(props) {
-    super(props);
-  }
-
-  render() {
-    return (
-      <ParticipantsMenuContainer />
-    );
-  }
-};
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/component.jsx
deleted file mode 100755
index 1832fcd112f74bb21e4a22cc1ed9ced4f92d2a8c..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/component.jsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import React from 'react';
-import Modal from 'react-modal';
-import Icon from '/imports/ui/components/icon/component';
-import Button from '/imports/ui/components/button/component';
-import styles from '../../styles.scss';
-import Service from './service';
-
-const ROLE_MODERATOR = 'moderator';
-
-const LOCK_OPTIONS = {
-  MUTE_ALL: {
-    label: 'Mute all except the presenter',
-    ariaLabelledBy: 'muteALlLabel',
-    ariaDescribedBy: 'muteAllDesc',
-    ariaLabel: 'Mute all',
-    ariaDesc: 'Mutes all participants except the presenter.',
-    tabIndex: 7,
-  },
-  LOCK_ALL: {
-    label: 'Lock all participants',
-    ariaLabelledBy: 'lockAllLabel',
-    ariaDescribedBy: 'lockAllDesc',
-    ariaLabel: 'Lock all',
-    ariaDesc: 'Toggles locked status for all participants.',
-    tabIndex: 8,
-  },
-  WEBCAM_LOCK: {
-    label: 'Webcam',
-    ariaLabelledBy: 'webcamLabel',
-    ariaDescribedBy: 'webcamDesc',
-    ariaLabel: 'Webcam lock',
-    ariaDesc: 'Disables the webcam for all locked participants.',
-    tabIndex: 9,
-  },
-  MIC_LOCK: {
-    label: 'Microphone',
-    ariaLabelledBy: 'micLabel',
-    ariaDescribedBy: 'micDesc',
-    ariaLabel: 'Microphone lock',
-    ariaDesc: 'Disables the microphone for all locked participants.',
-    tabIndex: 10,
-  },
-  PUBLIC_CHAT_LOCK: {
-    label: 'Public chat',
-    ariaLabelledBy: 'pubChatLabel',
-    ariaDescribedBy: 'pubChatDesc',
-    ariaLabel: 'Public chat lock',
-    ariaDesc: 'Disables public chat for all locked participants.',
-    tabIndex: 11,
-  },
-  PRIVATE_CHAT_LOCK: {
-    label: 'Private chat',
-    ariaLabelledBy: 'privChatLabel',
-    ariaDescribedBy: 'privChatDesc',
-    ariaLabel: 'Private chat lock',
-    ariaDesc: 'Disables private chat for all locked participants.',
-    tabIndex: 12,
-  },
-};
-
-export default class ParticipantsMenu extends React.Component {
-  constructor(props) {
-    super(props);
-  }
-
-  renderLockItem(lockOption) {
-    return (
-      <div className={styles.row} role='presentation' key={lockOption.label} >
-        <label>
-          <input
-            className={styles.checkboxOffset}
-            type="checkbox"
-            tabIndex={lockOption.tabIndex}
-            aria-labelledby={lockOption.ariaLabelledBy}
-            aria-describedby={lockOption.ariaDescribedBy} />
-          {lockOption.label}
-        </label>
-        <div id={lockOption.ariaLabelledBy} hidden>{lockOption.ariaLabel}</div>
-        <div id={lockOption.ariaDescribedBy} hidden>{lockOption.ariaDesc}</div>
-      </div>
-    );
-  }
-
-  renderLockOptions () {
-
-    const { isPresenter, role } = this.props;
-
-    let roleBasedOptions = [];
-
-    if (isPresenter || role === ROLE_MODERATOR) {
-      roleBasedOptions.push(
-         this.renderLockItem(LOCK_OPTIONS.LOCK_ALL),
-         this.renderLockItem(LOCK_OPTIONS.WEBCAM_LOCK),
-         this.renderLockItem(LOCK_OPTIONS.MIC_LOCK),
-         this.renderLockItem(LOCK_OPTIONS.PUBLIC_CHAT_LOCK),
-         this.renderLockItem(LOCK_OPTIONS.PRIVATE_CHAT_LOCK),
-       );
-    }
-
-    return _.compact([
-      this.renderLockItem(LOCK_OPTIONS.MUTE_ALL),
-      ...roleBasedOptions,
-    ]);
-  }
-
-  render () {
-
-    return (
-      <div>
-        {this.renderLockOptions()}
-      </div>
-    );
-  }
-
-};
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/container.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/container.jsx
deleted file mode 100755
index 665b3bab0f7808bc095286a726d9b1519545368f..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/container.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import React, { Component, PropTypes } from 'react';
-import { createContainer } from 'meteor/react-meteor-data';
-
-import ParticipantsMenu from './component';
-import Service from './service';
-
-class ParticipantsMenuContainer extends Component {
-  constructor(props) {
-    super(props);
-  }
-
-  render() {
-    return (
-      <ParticipantsMenu {...this.props}>
-        {this.props.children}
-      </ParticipantsMenu>
-    );
-  }
-}
-
-export default createContainer(() => {
-  let data = Service.checkUserRoles();
-  return data;
-}, ParticipantsMenuContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/service.js b/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/service.js
deleted file mode 100755
index 401c0464f6f105d86e3d68bfccd68a53f115f895..0000000000000000000000000000000000000000
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/users/participants/service.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Users from '/imports/api/users';
-import AuthSingleton from '/imports/ui/services/auth/index.js';
-
-checkUserRoles = () => {
-  const user = Users.findOne({
-     userId: AuthSingleton.getCredentials().requesterUserId,
-   }).user;
-
-  return {
-    isPresenter: user.presenter,
-    role: user.role,
-  };
-};
-
-export default {
-  checkUserRoles,
-};
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/video/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/video/component.jsx
index a966d19058484c1e2fd7cb36e779cf3e9dbd012b..63e818506db0fd8c370a26738cd3054ed687fe45 100644
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/video/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/video/component.jsx
@@ -1,50 +1,71 @@
-import React from 'react';
-import Modal from 'react-modal';
-import Icon from '/imports/ui/components/icon/component';
-import Button from '/imports/ui/components/button/component';
+import React, { Component } from 'react';
 import BaseMenu from '../base/component';
 import styles from '../styles.scss';
 
-export default class VideoMenu extends BaseMenu {
+import Toggle from '/imports/ui/components/switch/component';
+import cx from 'classnames';
+
+export default class AudioMenu extends BaseMenu {
   constructor(props) {
     super(props);
+
+    this.state = {
+      settingsName: 'video',
+      settings: props.settings,
+    };
   }
 
-  getContent() {
+  render() {
     return (
-      <div className={styles.full} role='presentation'>
-        <div className={styles.containerLeftHalf}>
-          <label htmlFor='camera'>Select camera</label>
-        </div>
-        <div className={styles.containerRightHalf}>
-          <label htmlFor='quality'  >Video quality</label>
+      <div className={styles.tabContent}>
+        <div className={styles.header}>
+          <h3 className={styles.title}>Video</h3>
         </div>
-        <div className={styles.containerLeftHalfContent} role='presentation'>
-          <select id='camera' defaultValue='0' tabIndex='7'
-            aria-labelledby='camLabel' aria-describedby='camDesc'>
-            <option value='0' disabled>Select camera</option>
-            <option value='1'>Camera 1</option>
-            <option value='2'>Camera 2</option>
-            <option value='3'>Camera 3</option>
-          </select>
-          <div id='camLabel' hidden>Camera source</div>
-          <div id='camDesc' hidden>
-            Chooses a camera source from the dropdown menu.</div>
-        </div>
-        <div className={styles.containerRightHalfContent} role='presentation'>
-          <select id='quality' defaultValue='0' tabIndex='8'
-            aria-labelledby='vidLabel' aria-describedby='vidDesc'>
-            <option value='0' disabled>Select quality</option>
-            <option value='1'>Low</option>
-            <option value='2'>Medium</option>
-            <option value='3'>High</option>
-          </select>
-          <div id='vidLabel' hidden>Video quality</div>
-          <div id='vidDesc' hidden>
-            Chooses the video quality level from the dropdown menu.</div>
-        </div>
-        <div className={styles.row}>
-          <div>Viewing participants webcams</div>
+
+        <div className={styles.form}>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={cx(styles.label, styles.labelSmall)}>
+                  View source
+                </label>
+                <select
+                  defaultValue='-1'
+                  className={styles.select}>
+                  <option value='-1' disabled>Choose view source</option>
+                </select>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={cx(styles.label, styles.labelSmall)}>
+                  Video Quality
+                </label>
+                <select
+                  defaultValue='-1'
+                  className={styles.select}>
+                  <option value='-1' disabled>Choose the video quality</option>
+                </select>
+              </div>
+            </div>
+          </div>
+          <div className={styles.row}>
+            <div className={styles.col}>
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  Viewing participants webcams
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+              <Toggle
+                icons={false}
+                defaultChecked={this.state.viewParticipantsWebcams}
+                onChange={() => this.handleToggle('viewParticipantsWebcams')} />
+              </div>
+            </div>
+          </div>
         </div>
       </div>
     );
diff --git a/bigbluebutton-html5/imports/ui/components/switch/component.jsx b/bigbluebutton-html5/imports/ui/components/switch/component.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c7a1b900ac7e804e038f9fe93b83c7e173571b16
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/switch/component.jsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import Toggle from 'react-toggle';
+import classNames from 'classnames';
+
+export default class Switch extends Toggle {
+  render() {
+    const {
+      className,
+      icons: _icons,
+      ariaLabelledBy,
+      ariaDescribedBy,
+      ariaLabel,
+      ariaDesc,
+      ...inputProps,
+    } = this.props;
+
+    const classes = classNames('react-toggle', {
+      'react-toggle--checked': this.state.checked,
+      'react-toggle--focus': this.state.hasFocus,
+      'react-toggle--disabled': this.props.disabled,
+    }, className);
+
+    return (
+      <div className={classes}
+        onClick={this.handleClick}
+        onTouchStart={this.handleTouchStart}
+        onTouchMove={this.handleTouchMove}
+        onTouchEnd={this.handleTouchEnd}>
+        <div className='react-toggle-track'>
+          <div className='react-toggle-track-check'>
+            ON
+          </div>
+          <div className='react-toggle-track-x'>
+            OFF
+          </div>
+        </div>
+        <div className='react-toggle-thumb' />
+
+        <input
+          {...inputProps}
+          ref={ref => { this.input = ref }}
+          onFocus={this.handleFocus}
+          onBlur={this.handleBlur}
+          className='react-toggle-screenreader-only'
+          type='checkbox'
+          tabIndex='0'
+          aria-labelledby={ariaLabelledBy}
+          aria-describedby={ariaDescribedBy}/>
+          <div id={ariaLabelledBy} hidden>{ariaLabel}</div>
+          <div id={ariaDescribedBy} hidden>{ariaDesc}</div>
+      </div>
+    );
+  }
+};
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js
index b892909c031bf2832255beb85927803922f4b331..e92c5b00ee998fda5dae54d0c88a828f615156c3 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/service.js
+++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js
@@ -196,7 +196,7 @@ const getOpenChats = chatID => {
   openChats.push({
     id: 'public',
     name: 'Public Chat',
-    icon: 'group-chat',
+    icon: 'group_chat',
     unreadCounter: UnreadMessages.count('public_chat_userid'),
   });
 
@@ -219,28 +219,28 @@ const userActions = {
   },
   clearStatus: {
     label: 'Clear Status',
-    handler: user => callServer('userSetEmoji', user.id, 'none'),
-    icon: 'clear-status',
+    handler: user => callServer('setEmojiStatus', user.id, 'none'),
+    icon: 'clear_status',
   },
   setPresenter: {
     label: 'Make Presenter',
-    handler: user => callServer('setUserPresenter', user.id, user.name),
+    handler: user => callServer('assignPresenter', user.id),
     icon: 'presentation',
   },
   kick: {
     label: 'Kick User',
     handler: user => callServer('kickUser', user.id),
-    icon: 'kick-user',
+    icon: 'circle_close',
   },
   mute: {
     label: 'Mute Audio',
     handler: user=> callServer('muteUser', user.id),
-    icon: 'mute',
+    icon: 'audio_off',
   },
   unmute: {
     label: 'Unmute Audio',
     handler: user=> callServer('unmuteUser', user.id),
-    icon: 'unmute',
+    icon: 'audio_on',
   },
 };
 
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx
index 1ba73e661be503cc74016a0d5998b146368e39bd..250973821cd9c69bb40f1d5430bca54d862d0ab7 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx
@@ -275,7 +275,7 @@ class UserListItem extends Component {
     }
 
     if (user.isVoiceUser) {
-      audioChatIcon = !user.isMuted ? 'audio' : 'audio-off';
+      audioChatIcon = !user.isMuted ? 'unmute' : 'mute';
     }
 
     let audioIconClassnames = {};
diff --git a/bigbluebutton-html5/imports/utils/statuses.js b/bigbluebutton-html5/imports/utils/statuses.js
index a62ca1f0eecae0a098b4f85390b81dba87d9b3b3..ab074110dcda41d65a4fbb1ecd12d84bc734de5f 100755
--- a/bigbluebutton-html5/imports/utils/statuses.js
+++ b/bigbluebutton-html5/imports/utils/statuses.js
@@ -1,4 +1,4 @@
-const EMOJI_STATUSES = ['away', 'raiseHand', 'neutral', 'confused', 'sad',
-                          'happy', 'applause', 'thumbsUp', 'thumbsDown'];
+const EMOJI_STATUSES = ['time', 'hand', 'undecided', 'confused', 'sad',
+                          'happy', 'applause', 'thumbs_up', 'thumbs_down'];
 
 export { EMOJI_STATUSES };
diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json
old mode 100644
new mode 100755
index f37c7a6e1f43d2db57e98f207f91755e7eb4c6e0..3b3d2fcf916b7ac51ff3ecb6860554b997e3bc5e
--- a/bigbluebutton-html5/package.json
+++ b/bigbluebutton-html5/package.json
@@ -10,27 +10,30 @@
   },
   "dependencies": {
     "babel-runtime": "^6.18.0",
-    "classnames": "^2.2.3",
+    "classnames": "^2.2.5",
     "eventemitter2": "^2.1.3",
     "grunt-cli": "~1.2.0",
     "hiredis": "^0.5.0",
-    "history": "^2.1.2",
+    "history": "~3.3.0",
     "image-size": "~0.5.0",
     "meteor-node-stubs": "^0.2.3",
     "node-sass": "~3.8.0",
     "probe-image-size": "~2.1.1",
-    "react": "~15.3.1",
-    "react-addons-css-transition-group": "~15.3.1",
-    "react-addons-pure-render-mixin": "~15.3.1",
+    "react-addons-shallow-compare": "^15.4.2",
+    "react": "~15.4.2",
+    "react-addons-css-transition-group": "~15.4.2",
+    "react-addons-pure-render-mixin": "~15.4.2",
     "react-autosize-textarea": "~0.3.2",
-    "react-color": "^2.10.0",
-    "react-dom": "~15.3.1",
+    "react-color": "^2.11.1",
+    "react-dom": "~15.4.2",
     "react-intl": "~2.1.3",
-    "react-modal": "~1.4.0",
-    "react-router": "~2.7.0",
+    "react-modal": "~1.7.1",
+    "react-router": "~3.0.2",
+    "react-tabs": "^0.8.2",
+    "react-toggle": "^2.2.0",
     "redis": "^2.6.2",
     "underscore": "~1.8.3",
-    "winston": "^2.2.0",
+    "winston": "^2.3.1",
     "xml2js": "^0.4.17",
     "xmlhttprequest": "^1.8.0"
   },
diff --git a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.eot b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.eot
index 44480da85e01558c8e3f5d89cdf4f2e23344b170..a6d5937d785f0e2b99b60fcd739f6fdbbb9a3858 100755
Binary files a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.eot and b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.eot differ
diff --git a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.svg b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.svg
index 9dd6173baaaccc76f583311196afaf13b6e9b21e..a0dffe9a5eae12ea3393fb0a37beb2e8f502f71c 100755
--- a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.svg
+++ b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.svg
@@ -1,62 +1,222 @@
 <?xml version="1.0" standalone="no"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>Generated by IcoMoon</metadata>
+<!--
+2016-12-26: Created with FontForge (http://fontforge.org)
+-->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
+<metadata>
+Created by FontForge 20161004 at Fri Dec 30 11:22:51 2016
+ By Ghazi
+Copyright (c) 2016, BlindSide Networks Inc.
+</metadata>
 <defs>
-<font id="bbb-icons" horiz-adv-x="1024">
-<font-face units-per-em="1024" ascent="960" descent="-64" />
-<missing-glyph horiz-adv-x="1024" />
-<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
-<glyph unicode="&#xe900;" glyph-name="bbb-logout" d="M243.712-0.171h-80.555c-48.936 0.193-88.554 39.811-88.747 88.728v684.733c0.193 48.936 39.811 88.554 88.728 88.747h80.573c0.991-0.109 2.141-0.171 3.305-0.171 17.72 0 32.085 14.365 32.085 32.085s-14.365 32.085-32.085 32.085c-1.164 0-2.314-0.062-3.446-0.183l-80.414 0.012c-84.187-0.194-152.382-68.389-152.576-152.557v-684.733c0.194-84.187 68.389-152.382 152.557-152.576h80.573c0.991-0.109 2.141-0.171 3.305-0.171 17.72 0 32.085 14.365 32.085 32.085s-14.365 32.085-32.085 32.085c-1.164 0-2.314-0.062-3.446-0.183zM989.867 408.405l22.528 22.528-22.528 22.528-293.547 294.571c-5.403 4.282-12.32 6.87-19.84 6.87-17.72 0-32.085-14.365-32.085-32.085 0-7.521 2.587-14.437 6.921-19.907l238.882-238.867h-642.048c-0.991 0.109-2.141 0.171-3.305 0.171-17.72 0-32.085-14.365-32.085-32.085s14.365-32.085 32.085-32.085c1.164 0 2.314 0.062 3.446 0.183l642.931-0.012-238.933-238.933c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l292.574 292.248z" />
-<glyph unicode="&#xe901;" glyph-name="bbb_audio_close" d="M567.979 350.037c17.146 27.308 27.316 60.504 27.316 96.075 0 0.664-0.004 1.326-0.011 1.988l0.001 304.368c0.012 0.775 0.019 1.689 0.019 2.605 0 51.755-21.45 98.5-55.945 131.83-33.433 34.598-80.178 56.048-131.933 56.048-0.916 0-1.83-0.007-2.743-0.020-0.637 0.013-1.551 0.020-2.467 0.020-51.755 0-98.5-21.45-131.83-55.945-34.598-33.433-56.048-80.178-56.048-131.933 0-0.916 0.007-1.83 0.020-2.743l-0.002-304.331c-0.037-1.374-0.058-2.992-0.058-4.615 0-51.774 21.466-98.535 55.983-131.867 33.434-34.599 80.179-56.048 131.934-56.048 0.916 0 1.83 0.007 2.743 0.020 0.414-0.008 1.065-0.011 1.717-0.011 47.667 0 91.060 18.297 123.54 48.252 11.096 17.429 23.601 32.646 37.687 46.235zM533.845 448c0.018-0.776 0.028-1.69 0.028-2.607 0-34.696-14.542-65.996-37.863-88.138-22.245-23.429-53.548-37.974-88.248-37.974-1.034 0-2.065 0.013-3.093 0.039-0.719-0.025-1.744-0.038-2.773-0.038-34.534 0-65.704 14.406-87.827 37.537-23.422 22.237-37.967 53.54-37.967 88.24 0 1.034 0.013 2.065 0.039 3.093l-0.003 304.317c-0.018 0.776-0.028 1.69-0.028 2.607 0 34.696 14.542 65.996 37.863 88.138 22.244 23.424 53.544 37.966 88.241 37.966 0.917 0 1.831-0.010 2.743-0.030 0.74 0.025 1.771 0.038 2.805 0.038 34.7 0 66.003-14.545 88.145-37.87 23.424-22.245 37.966-53.545 37.966-88.241 0-0.917-0.010-1.831-0.030-2.743l0.002-304.334zM567.979 350.037c-13.978-13.117-26.351-27.658-36.975-43.471 2.501 1.828 5.573 3.876 8.645 6.948 10.558 10.737 19.921 22.705 27.837 35.655zM435.541 80.043v34.133c20.978 1.693 40.29 5.080 58.943 10.078-4.612 12.172-5.975 26.808-6.036 41.752 0 6.88 0 13.707 0 20.192-23.244-7.363-49.976-11.606-77.699-11.606-0.164 0-0.328 0-0.491 0h-11.921c-147.151 0.194-266.387 119.431-266.581 266.563 0 17.079-13.83 30.909-30.891 30.909s-30.891-13.83-30.891-30.891c1.035-172.561 134.878-313.533 304.421-325.91l1.073-34.196h-193.877c-17.060 0-30.891-13.83-30.891-30.891s13.83-30.891 30.891-30.891h356.011c-13.546 17.785-25.047 38.183-33.551 60.078l-68.849 1.703zM739.669 442.539c0 17.060-13.83 30.891-30.891 30.891s-30.891-13.83-30.891-30.891c-0.072-12.105-0.938-23.939-2.549-35.534 18.949 6.642 40.554 9.744 62.854 9.933 1.134 9.217 1.476 17.067 1.476 25.601zM891.221 318.635c-38.61 37.766-91.503 61.068-149.838 61.068-118.386 0-214.357-95.971-214.357-214.357s95.971-214.357 214.357-214.357c118.386 0 214.357 95.971 214.357 214.357 0 0.611-0.003 1.221-0.008 1.83-0.496 59.323-25.090 112.9-64.472 151.42zM847.531 59.221c-27.613-27.626-65.768-44.715-107.914-44.715-84.265 0-152.576 68.311-152.576 152.576s68.311 152.576 152.576 152.576c42.146 0 80.3-17.088 107.913-44.714 27.514-27.646 44.522-65.768 44.522-107.862s-17.008-80.216-44.528-107.867zM778.581 169.472l38.571 39.595c5.591 5.591 9.049 13.314 9.049 21.845 0 17.062-13.832 30.894-30.894 30.894-8.531 0-16.255-3.458-21.845-9.049l-38.229-38.229-34.133 34.133c-5.591 5.591-13.314 9.049-21.845 9.049-17.062 0-30.894-13.832-30.894-30.894 0-8.531 3.458-16.255 9.049-21.845l34.133-34.133-35.84-35.84c-5.591-5.591-9.049-13.314-9.049-21.845 0-17.062 13.832-30.894 30.894-30.894 8.531 0 16.255 3.458 21.845 9.049l35.84 35.84 40.619-40.619c5.008-3.689 11.299-5.904 18.108-5.904 16.966 0 30.72 13.754 30.72 30.72 0 6.55-2.050 12.622-5.544 17.608z" />
-<glyph unicode="&#xe902;" glyph-name="bbb-more" d="M237.568 448c0-60.89-49.361-110.251-110.251-110.251s-110.251 49.361-110.251 110.251c0 60.89 49.361 110.251 110.251 110.251s110.251-49.361 110.251-110.251zM622.251 448c0-60.89-49.361-110.251-110.251-110.251s-110.251 49.361-110.251 110.251c0 60.89 49.361 110.251 110.251 110.251s110.251-49.361 110.251-110.251zM1006.933 448c0-60.89-49.361-110.251-110.251-110.251s-110.251 49.361-110.251 110.251c0 60.89 49.361 110.251 110.251 110.251s110.251-49.361 110.251-110.251z" />
-<glyph unicode="&#xe903;" glyph-name="bbb-promote" d="M994.645 740.523c-5.371 4.196-12.219 6.728-19.658 6.728-2.715 0-5.352-0.337-7.87-0.972l-887.245-216.699v15.701c-1.731 16.241-15.358 28.78-31.915 28.78s-30.184-12.54-31.902-28.64l-0.012-185.485c1.731-16.241 15.358-28.78 31.915-28.78s30.184 12.54 31.902 28.64l0.012 6.285 129.707-31.744v-45.056c0-66.545 53.946-120.491 120.491-120.491s120.491 53.946 120.491 120.491c0 66.545-53.946 120.491-120.491 120.491s-120.491-53.946-120.491-120.491c0-66.545 53.946-120.491 120.491-120.491 1.659-0.087 3.602-0.136 5.556-0.136 60.954 0 110.667 48.124 113.22 108.449l518.834-126.404h7.509c0 0 0 0 0 0 17.72 0 32.085 14.365 32.085 32.085 0 0 0 0 0 0v532.821c-0.142 10.159-5.034 19.147-12.551 24.86zM330.752 232.96c-0.305-0.006-0.664-0.009-1.024-0.009-31.293 0-56.661 25.368-56.661 56.661 0 0.003 0 0.007 0 0.010v29.354l111.957-27.307c-4.096-51.883-32.427-58.709-54.272-58.709zM942.763 221.013l-861.867 210.944v32.085l862.208 210.944v-453.973z" />
-<glyph unicode="&#xe904;" glyph-name="bbb-application" d="M950.613 821.077h-877.227c-31.105 0-56.32-25.215-56.32-56.32v-633.515c0-31.105 25.215-56.32 56.32-56.32h877.227c31.105 0 56.32 25.215 56.32 56.32v633.515c0 31.105-25.215 56.32-56.32 56.32zM943.104 757.248v-82.261h-862.208v82.261h862.208zM80.896 138.752v472.405h862.208v-472.405h-862.208zM170.667 740.523c-13.384 0-24.235-10.85-24.235-24.235s10.85-24.235 24.235-24.235c13.384 0 24.235 10.85 24.235 24.235s-10.85 24.235-24.235 24.235v0zM268.288 740.523c-13.384 0-24.235-10.85-24.235-24.235s10.85-24.235 24.235-24.235c13.384 0 24.235 10.85 24.235 24.235s-10.85 24.235-24.235 24.235v0zM365.909 740.523c0 0 0 0 0 0-13.384 0-24.235-10.85-24.235-24.235s10.85-24.235 24.235-24.235c13.384 0 24.235 10.85 24.235 24.235 0 0 0 0 0 0 0 13.384-10.85 24.235-24.235 24.235 0 0 0 0 0 0v0z" />
-<glyph unicode="&#xe905;" glyph-name="bbb-video-off" d="M992.256 652.8c-4.915 3.216-10.936 5.13-17.403 5.13-4.697 0-9.157-1.009-13.178-2.822l-236.683-104.708c-11.343-5.009-19.116-16.159-19.116-29.124 0-0.081 0-0.162 0.001-0.243v-168.265c-0.001-0.069-0.001-0.15-0.001-0.231 0-12.965 7.773-24.115 18.913-29.044l237.088-105.211c3.817-1.73 8.276-2.739 12.971-2.739 17.72 0 32.085 14.365 32.085 32.085 0 0.003 0 0.006 0 0.008v379.221c-0.357 10.864-6.061 20.322-14.554 25.866zM943.104 297.131l-173.056 76.8v126.976l173.056 76.8v-280.576zM913.408 804.352c4.282 5.403 6.87 12.32 6.87 19.84 0 17.72-14.365 32.085-32.085 32.085-7.521 0-14.437-2.587-19.907-6.921l-162.749-162.424v24.235c0.001 0.102 0.002 0.223 0.002 0.343 0 17.532-14.212 31.744-31.744 31.744-0.121 0-0.241-0.001-0.362-0.002h-624.28c-0.102 0.001-0.223 0.002-0.343 0.002-17.532 0-31.744-14.212-31.744-31.744 0-0.121 0.001-0.241 0.002-0.362v-526.318c-0.001-0.102-0.002-0.223-0.002-0.343 0-17.532 14.212-31.744 31.744-31.744 0.121 0 0.241 0.001 0.362 0.002h121.496l-60.075-61.099c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l106.547 106.563h411.307c0.102-0.001 0.223-0.002 0.343-0.002 17.532 0 31.744 14.212 31.744 31.744 0 0.121-0.001 0.241-0.002 0.362v411.288zM80.896 216.917v462.165h560.811v-56.32l-405.845-405.845h-154.965zM641.707 216.917h-315.733l315.733 315.733v-315.733z" />
-<glyph unicode="&#xe906;" glyph-name="bbb-user" d="M859.477 225.792c-86.016 57.344-196.267 85.675-347.477 85.675s-262.827-25.941-347.819-84.651v0c-75.521-53.261-124.246-140.134-124.246-238.387 0-0.192 0-0.384 0.001-0.576-0.001-0.072-0.002-0.193-0.002-0.313 0-17.532 14.212-31.744 31.744-31.744 0.121 0 0.241 0.001 0.362 0.002h879.939c0.102-0.001 0.223-0.002 0.343-0.002 17.532 0 31.744 14.212 31.744 31.744 0 0.121-0.001 0.241-0.002 0.362 0.001 0.3 0.002 0.677 0.002 1.054 0 97.871-48.92 184.315-123.642 236.215zM106.155 16.896c8.453 64.83 43.433 120.142 93.502 155.516 74.434 51.332 171.373 73.86 312.343 73.86s236.885-23.552 311.979-73.728c51.14-35.367 86.281-90.753 94.102-154.584l-811.926-1.064zM512 379.733c144.043 0 254.976 114.688 263.509 273.067 0.309 4.898 0.485 10.622 0.485 16.386 0 74.016-29.049 141.248-76.368 190.915-46.957 50.275-113.508 81.946-187.466 82.83-73.282-0.508-139.042-31.594-185.372-81.093-48.694-51.204-78.567-120.434-78.567-196.641 0-4.36 0.098-8.698 0.291-13.011 6.463-157.425 117.397-272.454 263.487-272.454zM372.736 817.664c34.865 37.433 84.271 60.926 139.17 61.439 55.928-0.808 106.011-24.767 141.295-62.685 36.493-38.31 58.878-90.12 58.878-147.159 0-4.59-0.145-9.146-0.431-13.664-6.795-124.652-88.715-212.033-199.649-212.033s-194.56 87.381-199.68 212.309c-0.134 2.883-0.211 6.263-0.211 9.661 0 58.983 23.088 112.574 60.719 152.228z" />
-<glyph unicode="&#xe907;" glyph-name="bbb-up-arrow" horiz-adv-x="683" d="M657.067 643.584l-288.085 287.744c-7.11 7.141-16.948 11.56-27.819 11.56s-20.709-4.419-27.817-11.558l-287.745-287.745c-7.119-7.119-11.523-16.955-11.523-27.819 0-21.728 17.614-39.342 39.342-39.342 10.864 0 20.699 4.403 27.819 11.523l220.843 220.843v-816.469c0-21.679 17.574-39.253 39.253-39.253s39.253 17.574 39.253 39.253v816.469l220.843-220.843c7.119-7.119 16.955-11.523 27.819-11.523 21.728 0 39.342 17.614 39.342 39.342 0 10.864-4.403 20.699-11.523 27.819z" />
-<glyph unicode="&#xe908;" glyph-name="bbb-undecided" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 17.92c-237.527 0-430.080 192.553-430.080 430.080s192.553 430.080 430.080 430.080c237.527 0 430.080-192.553 430.080-430.080-0.194-237.448-192.632-429.886-430.061-430.080zM422.229 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM721.237 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM750.933 295.083h-477.867c-3.182 1.082-6.847 1.707-10.658 1.707-18.851 0-34.133-15.282-34.133-34.133s15.282-34.133 34.133-34.133c3.811 0 7.476 0.625 10.899 1.777l477.626-0.070c13.748 4.618 23.475 17.386 23.475 32.427s-9.728 27.808-23.235 32.356z" />
-<glyph unicode="&#xe909;" glyph-name="bbb-time" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933s-221.589 494.933-494.933 494.933zM512 21.333c-235.641 0-426.667 191.025-426.667 426.667s191.025 426.667 426.667 426.667c235.641 0 426.667-191.025 426.667-426.667-0.194-235.563-191.103-426.472-426.648-426.667zM512 721.067c-18.851 0-34.133-15.282-34.133-34.133v-222.549l-199.68-196.608c-6.231-6.189-10.089-14.761-10.089-24.235 0-18.862 15.291-34.153 34.153-34.153 9.389 0 17.892 3.788 24.066 9.92l208.553 204.798c6.289 6.168 10.199 14.741 10.24 24.227v238.6c0 0.005 0 0.010 0 0.015 0 18.491-14.704 33.548-33.057 34.117z" />
-<glyph unicode="&#xe90a;" glyph-name="bbb-sad" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 17.92c-237.527 0-430.080 192.553-430.080 430.080s192.553 430.080 430.080 430.080c237.527 0 430.080-192.553 430.080-430.080-0.194-237.448-192.632-429.886-430.061-430.080zM422.229 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM721.237 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM507.221 368.811c-117.448-1.498-219.251-67.034-272.245-163.236-1.096-3.254-1.253-5.127-1.253-7.037 0-18.851 15.282-34.133 34.133-34.133 9.52 0 18.129 3.897 24.32 10.183 42.958 76.808 123.419 128.095 215.938 129.027 93.501-3.269 174.198-54.572 218.595-129.84 4.601-16.064 17.904-26.819 33.718-26.819 18.851 0 34.133 15.282 34.133 34.133 0 10.171-4.449 19.303-11.507 25.557-56.922 95.631-158.634 159.359-275.437 162.157z" />
-<glyph unicode="&#xe90b;" glyph-name="bbb-right-arrow" horiz-adv-x="546" d="M56.661-64c-0.186-0.003-0.406-0.005-0.626-0.005-22.433 0-40.619 18.186-40.619 40.619 0 10.694 4.133 20.424 10.889 27.677l394.9 448.488-394.581 438.955c-6.591 7.226-10.627 16.88-10.627 27.477 0 22.553 18.283 40.835 40.835 40.835 11.956 0 22.711-5.138 30.179-13.326l443.762-492.917-443.392-504.149c-7.475-8.394-18.312-13.655-30.378-13.655-0.12 0-0.24 0.001-0.36 0.002z" />
-<glyph unicode="&#xe90c;" glyph-name="bbb-presentation" d="M973.824 942.933h-923.648c-18.851 0-34.133-15.282-34.133-34.133v-665.6c0-18.851 15.282-34.133 34.133-34.133h375.467l-223.232-198.315c-11.144-5.772-18.628-17.216-18.628-30.408 0-18.851 15.282-34.133 34.133-34.133 11.875 0 22.333 6.064 28.448 15.264l231.503 208.68v-183.979c-0.759-2.684-1.195-5.767-1.195-8.951 0-18.851 15.282-34.133 34.133-34.133s34.133 15.282 34.133 34.133c0 3.185-0.436 6.267-1.252 9.192l0.057 183.739 232.789-208.555c6.193-9.326 16.652-15.39 28.526-15.39 18.851 0 34.133 15.282 34.133 34.133 0 13.192-7.484 24.636-18.438 30.319l-223.763 200.452h375.467c18.851 0 34.133 15.282 34.133 34.133v664.576c-0.541 17.946-14.854 32.378-32.701 33.107zM941.056 277.333h-858.112v427.691h858.112v-427.691zM82.944 770.901v106.155h858.112v-105.813h-858.112z" />
-<glyph unicode="&#xe90d;" glyph-name="bbb-listen" horiz-adv-x="1195" d="M1078.955 453.12s0 0 0 2.048c0.002 0.51 0.003 1.114 0.003 1.719 0 267.244-215.676 484.114-482.465 486.046-263.656-1.857-477.155-213.204-482.48-475.659-69.471-51.137-114.097-132.227-114.097-223.741 0-151.32 122.015-274.141 273.027-275.446 0.226-0.002 0.346-0.003 0.467-0.003 17.532 0 31.744 14.212 31.744 31.744 0 0.121-0.001 0.241-0.002 0.362v486.382c0 0.001 0 0.001 0 0.002 0 17.532-14.212 31.744-31.744 31.744-0.12 0-0.24-0.001-0.36-0.002-33.066-0.020-64.742-6.026-93.993-16.992 24.089 212.757 201.987 376.688 418.172 376.688 221.365 0 402.585-171.879 417.485-389.461-27.118 8.87-58.536 14.753-91.328 14.753-0.628 0-1.255-0.002-1.882-0.006-0.006 0.002-0.126 0.002-0.247 0.002-17.532 0-31.744-14.212-31.744-31.744 0-0.121 0.001-0.241 0.002-0.362v-486.040c-0.001-0.102-0.002-0.223-0.002-0.343 0-17.532 14.212-31.744 31.744-31.744 0.121 0 0.241 0.001 0.362 0.002 151.202 1.194 273.329 124.059 273.329 275.448 0 92.337-45.433 174.062-115.165 224.041zM238.933 34.645c-100.899 17.344-176.704 104.182-176.704 208.725s75.805 191.381 175.446 208.546l1.258-417.271zM955.733 19.285v417.451c100.899-17.344 176.704-104.182 176.704-208.725s-75.805-191.381-175.446-208.546z" />
-<glyph unicode="&#xe90e;" glyph-name="bbb-left-arrow" horiz-adv-x="546" d="M482.304-46.933c-11.676 0.032-22.149 5.157-29.318 13.27l-428.41 487.125 428.373 477.867c7.338 8.014 17.847 13.021 29.525 13.021 22.084 0 39.986-17.902 39.986-39.986 0-10.405-3.974-19.882-10.488-26.995l-382.266-424.589 382.293-434.517c6.081-6.88 9.794-15.978 9.794-25.942 0-21.679-17.574-39.253-39.253-39.253-0.083 0-0.167 0-0.25 0.001z" />
-<glyph unicode="&#xe90f;" glyph-name="bbb-happy" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 17.92c-237.527 0-430.080 192.553-430.080 430.080s192.553 430.080 430.080 430.080c237.527 0 430.080-192.553 430.080-430.080-0.194-237.448-192.632-429.886-430.061-430.080zM422.229 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM721.237 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM772.096 364.032c-4.747 2.98-10.516 4.747-16.699 4.747-2.799 0-5.513-0.362-8.098-1.042-8.285-2.228-15.311-7.478-19.836-14.493-45.281-76.955-126.454-128.374-219.847-131.197-92.688 1.162-172.752 52.402-214.787 127.751-6.837 7.516-15.421 11.388-24.909 11.388-18.851 0-34.133-15.282-34.133-34.133 0-1.766 0.134-3.5 0.393-5.194 53.739-97.689 155.574-163.253 272.846-164.672l2.586-0.002c116.357 3.318 217.102 67.117 272.235 160.944 3.439 6.239 4.973 11.854 4.973 17.827 0 11.592-5.778 21.834-14.612 28.004z" />
-<glyph unicode="&#xe910;" glyph-name="bbb-hand" d="M828.075 731.307c-13.97-0.064-27.22-3.074-39.184-8.438l0.614 29.259c-1.48 55.948-46.452 100.92-102.261 102.397-14.109-0.062-27.359-3.071-39.324-8.435-3.856 53.71-47.737 95.578-101.662 96.841-54.281-1.28-98.223-43.326-102.5-96.566l-0.024 0.653c-10.969 4.82-23.756 7.625-37.197 7.625-26.649 0-50.723-11.025-67.909-28.762-21.15-21.759-34.177-51.463-34.177-84.21 0-0.764 0.007-1.526 0.021-2.287l-0.002-321.422-47.445 68.267c-14.651 26.922-40.889 45.947-71.835 50.454-2.57 0.24-4.946 0.342-7.347 0.342-24.267 0-46.121-10.337-61.397-26.847-20.872-20.877-38.621-59.447-5.171-126.69 0-1.707 102.4-175.104 177.152-294.571 41.643-65.536 120.149-136.533 214.699-136.533h191.488c129.619 0.194 234.643 105.218 234.837 234.819v441.704c-1.454 55.604-45.866 100.373-101.188 102.395zM866.645 187.904c0-94.257-76.41-170.667-170.667-170.667h-191.829c-68.267 0-129.707 57.003-160.768 106.155-75.435 119.808-174.763 290.475-174.763 290.475-12.629 25.259-14.677 42.667-6.144 51.2 3.779 4.653 9.341 7.731 15.629 8.188 10.396-3.97 18.635-11.435 23.509-20.913l96.029-140.875c6.881-9.705 18.071-15.962 30.722-15.962 20.588 0 37.306 16.571 37.544 37.102v406.892c-0.018 0.536-0.029 1.166-0.029 1.798 0 15.037 5.857 28.706 15.415 38.849 5.65 7.117 14.338 11.658 24.086 11.658 4.361 0 8.509-0.909 12.267-2.547 14.773-6.152 25.273-20.32 26.081-37.031l0.004-242.444c1.731-16.241 15.358-28.78 31.915-28.78s30.184 12.54 31.902 28.64l0.012 330.893c1.665 20.598 17.973 36.906 38.422 38.561 20.602-1.817 36.736-18.069 38.369-38.413l0.010-330.9c1.731-16.241 15.358-28.78 31.915-28.78s30.184 12.54 31.902 28.64l0.012 242.487c0 0 0 0 0 0 0 21.302 17.269 38.571 38.571 38.571s38.571-17.269 38.571-38.571c0 0 0 0 0 0v-301.739c-0.109-0.991-0.171-2.141-0.171-3.305 0-17.72 14.365-32.085 32.085-32.085s32.085 14.365 32.085 32.085c0 1.164-0.062 2.314-0.183 3.446l0.012 178.377c0 21.302 17.269 38.571 38.571 38.571s38.571-17.269 38.571-38.571v-441.003z" />
-<glyph unicode="&#xe911;" glyph-name="bbb-group-chat" d="M955.733 4.267l-4.096 11.947-22.187 70.997c46.126 31.591 76.37 83.454 77.82 142.459 0.004 87.941-72.017 163.717-174.758 184.88l-3.072-0.683-37.888-49.835 20.821-2.731c80.896-13.312 139.605-68.267 139.605-132.437-2.116-44.837-27.306-83.348-63.887-104.121-10.893-6.865-17.623-18.162-17.692-31.037l10.923-38.24-45.739 34.133c-6.247 5.281-14.392 8.491-23.287 8.491-3.873 0-7.604-0.609-11.102-1.735-7.394-1.45-16.19-2.321-25.189-2.321-0.295 0-0.589 0.001-0.883 0.003-97.576 0-176.765 62.464-176.765 136.533 0 2.048 0 4.096 0 6.144s0 5.12 0 7.509v6.144l-52.224-15.36v-5.803c0-104.789 102.4-188.416 230.741-190.464 12.064 0.017 23.883 1.009 35.399 2.902l82.702-61.953 9.899-9.557c7.072-7.798 16.82-13.055 27.784-14.317 5.99 0.057 11.313 1.966 15.639 5.152 6.868 6.221 11.211 15.256 11.211 25.306 0 5.697-1.396 11.069-3.864 15.791zM415.403 942.592c-220.16 0-398.336-142.677-398.336-318.805 3.882-106.759 62.973-198.895 149.433-249.086 6.318-3.923 9.528-9.3 9.628-15.432l-53.248-170.681c0-9.803 7.947-17.749 17.749-17.749 4.973 0.010 9.455 2.103 12.622 5.453l182.28 135.176c0.578 0.381 1.286 0.608 2.048 0.608s1.47-0.227 2.062-0.616c20.828-4.034 45.373-6.848 70.392-7.813l5.37-0.029c219.819 3.413 398.336 142.677 398.336 318.464s-178.517 320.512-398.336 320.512zM409.6 373.248c-15.932 0.85-30.883 3.167-45.296 6.831-2.334 0.044-6.909 0.266-11.536 0.266s-9.202-0.222-13.715-0.657c0.318 0.048 0.015 0.050-0.288 0.050-18.25 0-34.929-6.724-47.695-17.83l-54.866-38.837 5.12 16.043 3.072 20.48c-0.007 30.149-15.648 56.643-39.256 71.817-69.183 38.921-115.85 109.954-119.785 192.187-0.020 137.062 148.119 251.067 330.049 251.067s330.069-112.299 330.069-250.539-148.48-247.808-331.435-250.539h-4.437z" />
-<glyph unicode="&#xe912;" glyph-name="bbb-confused" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 21.333c-235.264 0-425.983 190.72-425.983 425.984s190.72 425.984 425.984 425.984c235.024 0 425.595-190.331 425.983-425.264-0.388-235.146-190.876-425.633-425.947-426.021zM422.229 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM721.237 570.539c0-35.629-28.883-64.512-64.512-64.512s-64.512 28.883-64.512 64.512c0 35.629 28.883 64.512 64.512 64.512s64.512-28.883 64.512-64.512zM740.011 305.664c-8.755-1.027-16.317-5.444-21.454-11.882-21.085-25.061-52.157-41.028-86.975-41.706-28.917 3.362-55.035 12.321-78.221 25.774-40.008 30.784-91.171 50.705-146.831 53.726-58.067-3.465-109.434-26.709-148.643-62.923-2.451-4.565-3.989-10.186-3.989-16.166 0-18.851 15.282-34.133 34.133-34.133 5.356 0 10.423 1.234 14.934 3.432 27.058 24.82 62.42 41.277 101.503 44.915 28.365-1.058 54.063-8.511 76.689-20.879l-0.902 0.451c41.494-30.106 91.421-51.237 145.581-59.498l8.36-0.235c54.011 2.127 101.743 27.312 133.904 65.923 4.6 5.769 7.236 12.784 7.236 20.415 0 10.192-4.702 19.285-12.055 25.23-5.864 4.755-13.339 7.604-21.48 7.604-0.63 0-1.257-0.017-1.879-0.051z" />
-<glyph unicode="&#xe913;" glyph-name="bbb-close" d="M572.416 448l396.288 396.629c7.731 7.731 12.513 18.411 12.513 30.208 0 23.594-19.127 42.721-42.721 42.721-11.797 0-22.477-4.782-30.208-12.513l-396.288-396.629-396.629 396.288c-7.327 6.101-16.837 9.804-27.212 9.804-23.564 0-42.667-19.103-42.667-42.667 0-10.375 3.703-19.886 9.86-27.281l396.232-396.56-396.288-396.629c-7.731-7.731-12.513-18.411-12.513-30.208 0-23.594 19.127-42.721 42.721-42.721 11.797 0 22.477 4.782 30.208 12.513l396.288 396.629 396.629-396.288c7.731-7.731 18.411-12.513 30.208-12.513 23.594 0 42.721 19.127 42.721 42.721 0 11.797-4.782 22.477-12.513 30.208z" />
-<glyph unicode="&#xe914;" glyph-name="bbb-clear-status" d="M93.525 82.091c9.004 56.784 40.246 104.939 84.349 136.103 68.909 47.193 157.656 68.697 289.069 68.697 22.187 0 43.691 0 64.171-2.048h36.181l43.008 60.757-23.552 3.755c-11.654 1.964-25.643 3.429-39.847 4.068l-9.988 0.028c-21.504 0-44.715 2.048-68.267 2.048-146.432 0-247.467-24.576-328.021-79.872-71.795-50.707-118.108-133.347-118.108-226.804 0-0.664 0.002-1.328 0.007-1.991-0.001-18.749 15.281-34.031 34.133-34.031h533.845l-37.205 68.267h-459.776zM466.603 415.573c136.533 0 238.933 107.52 246.784 255.659 0.285 4.552 0.448 9.873 0.448 15.231 0 69.308-27.216 132.259-71.543 178.75-43.94 47.149-106.262 76.864-175.533 77.719-68.592-0.435-130.138-29.577-173.423-75.975-45.704-47.983-73.745-112.888-73.745-184.342 0-3.883 0.083-7.747 0.247-11.59 6.125-147.59 109.891-255.451 246.765-255.451zM337.237 823.467c32.449 34.919 78.469 56.845 129.616 57.343 51.858-0.513 98.413-22.407 131.426-57.26 33.904-35.635 54.713-83.843 54.713-136.912 0-4.219-0.132-8.408-0.391-12.562-6.116-115.826-82.574-197.405-185.998-197.405s-180.907 81.237-185.685 197.632c-0.098 2.37-0.154 5.151-0.154 7.945 0 54.787 21.513 104.549 56.552 141.3zM941.056 315.221c-38.355 38.336-91.331 62.045-149.845 62.045-117.067 0-211.968-94.901-211.968-211.968s94.901-211.968 211.968-211.968c117.067 0 211.968 94.901 211.968 211.968 0 0.027 0 0.054 0 0.082-0.062 58.513-23.789 111.477-62.124 149.842zM898.048 58.539c-27.286-27.208-64.94-44.032-106.524-44.032-83.323 0-150.869 67.547-150.869 150.869s67.547 150.869 150.869 150.869c41.583 0 79.238-16.824 106.527-44.036 27.412-27.369 44.371-65.206 44.371-107.004s-16.959-79.636-44.373-107.006zM829.781 167.424l37.888 37.888c5.503 5.503 8.907 13.106 8.907 21.504 0 16.796-13.616 30.411-30.411 30.411-8.398 0-16.001-3.404-21.504-8.907l-39.595-39.253-34.133 34.133c-5.503 5.503-13.106 8.907-21.504 8.907-16.796 0-30.411-13.616-30.411-30.411 0-8.398 3.404-16.001 8.907-21.504l34.133-34.133-34.133-34.133c-5.576-5.534-9.028-13.201-9.028-21.675 0-16.862 13.67-30.532 30.532-30.532 8.389 0 15.987 3.383 21.506 8.859l34.131 34.131 40.277-40.277c5.503-5.503 13.106-8.907 21.504-8.907 16.796 0 30.411 13.616 30.411 30.411 0 8.398-3.404 16.001-8.907 21.504z" />
-<glyph unicode="&#xe915;" glyph-name="bbb-circle" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 16.896c-238.092 0-431.104 193.012-431.104 431.104s193.012 431.104 431.104 431.104c238.092 0 431.104-193.012 431.104-431.104-0.194-238.014-193.090-430.91-431.085-431.104z" />
-<glyph unicode="&#xe916;" glyph-name="bbb-circle-minus" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 16.896c-238.092 0-431.104 193.012-431.104 431.104s193.012 431.104 431.104 431.104c238.092 0 431.104-193.012 431.104-431.104-0.194-238.014-193.090-430.91-431.085-431.104zM722.603 475.648h-421.205c-0.991 0.109-2.141 0.171-3.305 0.171-17.72 0-32.085-14.365-32.085-32.085s14.365-32.085 32.085-32.085c1.164 0 2.314 0.062 3.446 0.183l421.065-0.012c16.241 1.731 28.78 15.358 28.78 31.915s-12.54 30.184-28.64 31.902z" />
-<glyph unicode="&#xe917;" glyph-name="bbb-circle-close" d="M862.208 798.208c-89.559 89.526-213.265 144.896-349.904 144.896-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c136.639 0 260.345 55.37 349.906 144.897 89.439 89.646 144.745 213.382 144.745 350.036s-55.306 260.39-144.756 350.047zM817.152 143.189c-78.017-78.030-185.803-126.293-304.862-126.293-238.092 0-431.104 193.012-431.104 431.104s193.012 431.104 431.104 431.104c119.059 0 226.845-48.263 304.862-126.293 78.665-77.706 127.385-185.569 127.385-304.811s-48.721-227.105-127.341-304.768zM546.133 453.803l128.683 130.731c4.282 5.403 6.87 12.32 6.87 19.84 0 17.72-14.365 32.085-32.085 32.085-7.521 0-14.437-2.587-19.907-6.921l-129.299-129.314-117.76 117.76c-5.403 4.282-12.32 6.87-19.84 6.87-17.72 0-32.085-14.365-32.085-32.085 0-7.521 2.587-14.437 6.921-19.907l117.709-117.693-123.221-124.587c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l123.272 123.288 136.533-136.533c5.403-4.282 12.32-6.87 19.84-6.87 17.72 0 32.085 14.365 32.085 32.085 0 7.521-2.587 14.437-6.921 19.907z" />
-<glyph unicode="&#xe918;" glyph-name="bbb-circle-add" d="M512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 16.896c-238.092 0-431.104 193.012-431.104 431.104s193.012 431.104 431.104 431.104c238.092 0 431.104-193.012 431.104-431.104-0.194-238.014-193.090-430.91-431.085-431.104zM722.603 475.648h-190.805v182.955c0.109 0.991 0.171 2.141 0.171 3.305 0 17.72-14.365 32.085-32.085 32.085s-32.085-14.365-32.085-32.085c0-1.164 0.062-2.314 0.183-3.446l-0.012-182.814h-166.571c-0.991 0.109-2.141 0.171-3.305 0.171-17.72 0-32.085-14.365-32.085-32.085s14.365-32.085 32.085-32.085c1.164 0 2.314 0.062 3.446 0.183l166.089-0.012v-174.080c-0.109-0.991-0.171-2.141-0.171-3.305 0-17.72 14.365-32.085 32.085-32.085s32.085 14.365 32.085 32.085c0 1.164-0.062 2.314-0.183 3.446l0.012 173.939h190.805c16.322 1.647 28.956 15.314 28.956 31.932 0 16.497-12.451 30.087-28.468 31.884z" />
-<glyph unicode="&#xe919;" glyph-name="bbb-check" d="M689.152 610.133l-243.371-277.504-114.005 99.328c-5.864 6.208-14.152 10.072-23.342 10.072-17.72 0-32.085-14.365-32.085-32.085 0-10.726 5.264-20.224 13.349-26.049l136.628-120.214c5.568-4.935 12.937-7.948 21.010-7.948 9.592 0 18.191 4.255 24.012 10.98l264.567 301.437c2.746 4.631 4.368 10.207 4.368 16.163 0 17.72-14.365 32.085-32.085 32.085-7.169 0-13.789-2.351-19.131-6.325zM512 942.933c-273.344 0-494.933-221.589-494.933-494.933s221.589-494.933 494.933-494.933c273.344 0 494.933 221.589 494.933 494.933-0.388 273.188-221.745 494.545-494.896 494.933zM512 16.896c-238.092 0-431.104 193.012-431.104 431.104s193.012 431.104 431.104 431.104c238.092 0 431.104-193.012 431.104-431.104-0.194-238.014-193.090-430.91-431.085-431.104z" />
-<glyph unicode="&#xe91a;" glyph-name="bbb-chat" d="M512 874.667c244.395 0 443.733-152.917 443.733-341.333s-199.339-337.237-443.733-341.333h-5.461c-22.355 0.21-44.013 2.686-64.908 7.208-6.886 1.685-17.326 3.036-28.024 3.367-0.592 0.012-0.993 0.015-1.395 0.015-18.822 0-36.012-6.989-49.117-18.512l-116.994-87.31 23.893 76.459 3.072 20.139c0 0.063 0 0.138 0 0.213 0 32.113-16.735 60.318-41.959 76.369-103.449 65.754-162.841 161.669-162.841 263.728 0 187.392 199.339 340.992 443.733 340.992zM512 942.933c-282.624 0-512-183.296-512-409.6 0-130.048 75.776-246.101 194.219-320.853 6.396-4.048 10.581-11.085 10.581-19.099 0-0.005 0-0.011 0-0.016l-68.267-217.428c0-12.63 10.239-22.869 22.869-22.869 0 0 0 0 0 0 0.016 0 0.035 0 0.053 0 6.453 0 12.262 2.755 16.317 7.153l233.827 170.682c0.94 1.301 2.454 2.138 4.162 2.138 0.339 0 0.67-0.033 0.99-0.096 26.773-5.241 58.356-8.91 90.552-10.196l6.696-0.039c282.624 4.437 512 183.296 512 409.6s-229.035 409.6-512 409.6v0z" />
-<glyph unicode="&#xe91b;" glyph-name="bbb-audio" d="M512 891.733c1.402 0.052 3.048 0.082 4.701 0.082 38.45 0 73.131-16.136 97.641-42.005 25.988-24.629 42.124-59.31 42.124-97.76 0-1.653-0.030-3.3-0.089-4.939l0.007-337.341c0.001-0.202 0.002-0.442 0.002-0.682 0-38.411-16.103-73.061-41.927-97.567-24.627-25.986-59.308-42.122-97.758-42.122-1.653 0-3.3 0.030-4.939 0.089-1.165-0.059-2.811-0.089-4.464-0.089-38.45 0-73.131 16.136-97.641 42.005-25.988 24.629-42.124 59.31-42.124 97.76 0 1.653 0.030 3.3 0.089 4.939l-0.007 334.952c-0.052 1.402-0.082 3.048-0.082 4.701 0 38.45 16.136 73.131 42.005 97.641 24.496 25.011 58.531 40.481 96.18 40.481 2.209 0 4.406-0.053 6.589-0.159zM512 960c-0.662 0.008-1.445 0.012-2.228 0.012-57.615 0-109.674-23.792-146.887-62.086-38.187-37.28-61.84-89.203-61.84-146.651 0-0.78 0.004-1.56 0.013-2.338l-0.001-337.46c0.193-116.492 94.479-210.898 210.907-211.285 116.382 0.387 210.594 94.599 210.981 210.907v337.957c0.008 0.662 0.012 1.445 0.012 2.228 0 57.615-23.792 109.674-62.086 146.887-37.28 38.187-89.203 61.84-146.651 61.84-0.78 0-1.56-0.004-2.338-0.013l0.119 0.001zM759.125 4.267h-212.992v38.912c188.886 14.46 336.698 171.185 336.896 362.476 0 18.871-15.282 34.153-34.133 34.153s-34.133-15.282-34.133-34.133c-0.194-163.174-132.42-295.401-295.576-295.595h-14.355c-163.174 0.194-295.401 132.42-295.595 295.576 0 18.87-15.282 34.152-34.133 34.152s-34.133-15.282-34.133-34.133c0.198-191.311 148.010-348.036 335.66-362.42l1.236-38.988h-212.992c-18.851 0-34.133-15.282-34.133-34.133s15.282-34.133 34.133-34.133h494.251c18.851 0 34.133 15.282 34.133 34.133s-15.282 34.133-34.133 34.133z" />
-<glyph unicode="&#xe91c;" glyph-name="bbb-audio-off" d="M362.99 262.268c36.958-38.143 88.654-61.817 145.879-61.817 1.101 0 2.199 0.009 3.296 0.026 116.843-0.002 211.697 94.852 211.697 211.86v215.393l226.692 226.339c9.817 6.38 16.219 17.295 16.219 29.704 0 19.501-15.809 35.31-35.31 35.31-12.141 0-22.85-6.127-29.205-15.458l-179.102-179.146v23.658c0.012 0.831 0.019 1.812 0.019 2.794 0 57.396-23.816 109.229-62.104 146.157-37.103 38.823-89.21 62.922-146.946 62.922-0.747 0-1.493-0.004-2.239-0.012-0.717 0.013-1.698 0.020-2.681 0.020-57.396 0-109.229-23.816-146.157-62.104-38.415-37.049-62.235-88.886-62.235-146.287 0-1.227 0.011-2.452 0.033-3.674l-0.003-337.383c-0.003-0.384-0.004-0.837-0.004-1.291 0-31.987 7.295-62.27 20.313-89.276l-69.037-66.211c-26.719 43.263-42.599 95.681-42.725 151.8-4.211 15.166-17.868 26.085-34.075 26.085s-29.864-10.919-34.015-25.802c-0.059-0.341-0.059-0.451-0.059-0.56 0-75.096 22.961-144.83 62.245-202.563l-130.040-127.983c-10.439-6.262-17.317-17.519-17.317-30.382 0-19.501 15.809-35.31 35.31-35.31 12.863 0 24.12 6.878 30.293 17.157l125.441 124.452c59.943-60.164 140.843-99.412 230.822-105.864l1.167-38.909h-211.862c-17.897-1.881-31.724-16.89-31.724-35.128 0-17.361 12.529-31.795 29.038-34.755l494.559-0.032c15.131 4.211 26.050 17.867 26.050 34.074s-10.919 29.864-25.802 34.015l-212.11 0.059v37.782c188.37 15.291 335.449 171.932 335.449 362.924 0 0.271 0 0.543-0.001 0.814 0.785 2.735 1.236 5.924 1.236 9.218 0 19.501-15.809 35.31-35.31 35.31s-35.31-15.809-35.31-35.31c0-3.294 0.451-6.483 1.295-9.509-0.26-162.897-132.461-295.098-295.587-295.299h-14.497c-0.379-0.002-0.827-0.003-1.276-0.003-82.497 0-157.070 33.922-210.534 88.578l66.331 66.437zM654.654 411.277c0.020-0.872 0.032-1.9 0.032-2.93 0-38.449-16.129-73.131-41.991-97.648-24.634-25.979-59.316-42.108-97.765-42.108-1.030 0-2.058 0.012-3.082 0.035-0.72-0.023-1.747-0.035-2.777-0.035-38.449 0-73.131 16.129-97.648 41.991l-2.528 2.885 247.172 247.172v-148.303zM368.993 411.277v336.861c-0.020 0.872-0.032 1.9-0.032 2.93 0 38.449 16.129 73.131 41.991 97.648 24.706 26.6 59.792 43.155 98.746 43.155 0.81 0 1.617-0.007 2.424-0.021 0.751 0.022 1.778 0.034 2.809 0.034 38.449 0 73.131-16.129 97.648-41.991 25.994-24.636 42.134-59.328 42.134-97.79 0-1.394-0.021-2.783-0.063-4.167l0.005-91.957-282.483-282.483c-1.932 8.968-3.039 19.27-3.039 29.831 0 2.797 0.078 5.576 0.231 8.334z" />
-<glyph unicode="&#xe91d;" glyph-name="bbb-line-tool" d="M344.129 183.397l268.25 536.385 57.088-28.55-268.25-536.385-57.088 28.55zM704.853 942.933c0 0 0 0 0 0-60.324 0-109.227-48.902-109.227-109.227s48.902-109.227 109.227-109.227c60.324 0 109.227 48.902 109.227 109.227s-48.902 109.227-109.227 109.227zM704.853 788.651c-24.776 0.385-44.713 20.56-44.713 45.392 0 25.072 20.325 45.397 45.397 45.397s45.397-20.325 45.397-45.397c0-0.118 0-0.236-0.001-0.354-0.57-24.612-20.672-44.361-45.386-44.361-0.244 0-0.488 0.002-0.731 0.006zM319.147 171.179c-60.324 0-109.227-48.902-109.227-109.227s48.902-109.227 109.227-109.227c60.324 0 109.227 48.902 109.227 109.227s-48.902 109.227-109.227 109.227zM319.147 16.896c-25.072 0.001-45.396 20.326-45.396 45.397s20.325 45.397 45.397 45.397c25.072 0 45.397-20.325 45.397-45.397 0-0.12 0-0.24-0.001-0.36-0.193-24.907-20.444-45.038-45.396-45.038 0 0-0.001 0-0.001 0z" />
-<glyph unicode="&#xe91e;" glyph-name="bbb-circle-tool" d="M629.077 112.469l21.163-60.075c116.7 42.061 207.583 131.048 251.269 243.584l-58.757 25.728c-37.752-97.924-114.752-173.474-211.202-208.454zM114.005 584.533l60.416-21.163c35.32 99.441 110.833 176.962 206.478 214.211l-20.451 62.269c-115.99-45.265-205.167-137.343-245.545-252.382zM847.189 562.005l60.416 20.48c-42.572 121.976-135.946 216.692-254.091 260.175l-24.095-59.471c102.569-37.641 181.677-117.866 217.004-218.672zM177.493 322.048l-59.733-22.528c43.382-112.292 130.29-199.535 239.492-242.384l25.724 58.747c-94.973 37.137-168.648 111.035-204.652 203.735zM505.856 942.933c-58.603-0.77-105.813-48.457-105.813-107.17 0-59.193 47.986-107.179 107.179-107.179 59.19 0 107.174 47.981 107.179 107.169-0.191 59.237-48.256 107.184-107.519 107.184-0.36 0-0.72-0.002-1.079-0.005zM505.856 792.064c-23.941 0-43.349 19.408-43.349 43.349s19.408 43.349 43.349 43.349c23.941 0 43.349-19.408 43.349-43.349s-19.408-43.349-43.349-43.349zM505.856 167.765c-58.603-0.771-105.813-48.457-105.813-107.17 0-59.193 47.986-107.179 107.179-107.179 59.070 0 106.979 47.786 107.178 106.81 0 0.020 0 0.022 0 0.024 0 59.382-48.138 107.52-107.52 107.52-0.36 0-0.72-0.002-1.079-0.005zM505.856 16.896c-23.941 0-43.349 19.408-43.349 43.349s19.408 43.349 43.349 43.349c23.941 0 43.349-19.408 43.349-43.349s-19.408-43.349-43.349-43.349zM897.707 550.4c-59.193 0-107.179-47.986-107.179-107.179s47.986-107.179 107.179-107.179c59.193 0 107.179 47.986 107.179 107.179-0.193 59.115-48.063 106.985-107.16 107.179zM897.707 399.531c-23.941 0-43.349 19.408-43.349 43.349s19.408 43.349 43.349 43.349c23.941 0 43.349-19.408 43.349-43.349 0.001-0.101 0.001-0.221 0.001-0.341 0-23.941-19.408-43.349-43.349-43.349 0 0-0.001 0-0.001 0zM233.472 442.539c0 59.193-47.986 107.179-107.179 107.179s-107.179-47.986-107.179-107.179c0-59.193 47.986-107.179 107.179-107.179 59.115 0.193 106.985 48.063 107.179 107.16zM82.603 442.539c0.001 23.941 19.409 43.348 43.349 43.348s43.349-19.408 43.349-43.349c0-23.821-19.214-43.155-42.99-43.348-0.12-0.001-0.24-0.001-0.36-0.001-23.941 0-43.349 19.408-43.349 43.349 0 0 0 0.001 0 0.001z" />
-<glyph unicode="&#xe91f;" glyph-name="bbb-triangle-tool" d="M150.818 194.314l268.25 536.385 57.088-28.55-268.25-536.385-57.088 28.55zM246.101 94.037h529.408v-63.829h-529.408v63.829zM547.426 702.18l57.088 28.55 265.655-531.195-57.088-28.55-265.655 531.195zM512 724.821c60.324 0 109.227 48.902 109.227 109.227s-48.902 109.227-109.227 109.227c-60.324 0-109.227-48.902-109.227-109.227s48.902-109.227 109.227-109.227zM512 879.104c25.072 0 45.397-20.325 45.397-45.397s-20.325-45.397-45.397-45.397c-25.072 0-45.397 20.325-45.397 45.397s20.325 45.397 45.397 45.397zM897.707 171.179c0 0 0 0 0 0-60.324 0-109.227-48.902-109.227-109.227s48.902-109.227 109.227-109.227c60.324 0 109.227 48.902 109.227 109.227s-48.902 109.227-109.227 109.227zM897.707 16.896c-25.072 0-45.397 20.325-45.397 45.397s20.325 45.397 45.397 45.397c25.072 0 45.397-20.325 45.397-45.397s-20.325-45.397-45.397-45.397c0 0 0 0 0 0zM126.293 171.179c-60.324 0-109.227-48.902-109.227-109.227s48.902-109.227 109.227-109.227c60.324 0 109.227 48.902 109.227 109.227s-48.902 109.227-109.227 109.227zM126.293 16.896c-0.305-0.007-0.664-0.012-1.024-0.012-25.072 0-45.397 20.325-45.397 45.397s20.325 45.397 45.397 45.397c25.068 0 45.391-20.318 45.397-45.385 0-0.004 0-0.008 0-0.012 0-24.712-19.745-44.813-44.32-45.385z" />
-<glyph unicode="&#xe920;" glyph-name="bbb-square-tool" d="M862.549 689.664h63.829v-482.987h-63.829v482.987zM290.475 862.379h442.709v-63.829h-442.709v63.829zM97.621 689.664h63.829v-482.987h-63.829v482.987zM290.475 97.451h442.709v-63.829h-442.709v63.829zM129.365 942.933c-61.874-0.194-111.957-50.397-111.957-112.298 0-62.021 50.278-112.299 112.299-112.299s112.298 50.278 112.299 112.298c-0.194 62.062-50.55 112.299-112.639 112.299 0 0 0 0-0.001 0zM129.365 781.824c-26.621 0.194-48.127 21.82-48.127 48.468 0 26.769 21.7 48.469 48.469 48.469 26.648 0 48.274-21.506 48.468-48.108 0-26.976-21.853-48.829-48.811-48.829zM894.635 178.005c-62.021 0-112.298-50.278-112.298-112.299s50.278-112.299 112.299-112.299c61.901 0 112.104 50.083 112.298 111.939 0 0.019 0 0.019 0 0.019 0 62.089-50.236 112.445-112.28 112.639zM894.635 16.896c-26.769 0-48.469 21.7-48.469 48.469s21.7 48.469 48.469 48.469c26.769 0 48.469-21.7 48.469-48.469 0 0 0 0 0 0-0.192-26.691-21.778-48.277-48.451-48.469zM129.365 178.005c-61.874-0.194-111.957-50.397-111.957-112.298 0-62.021 50.278-112.299 112.299-112.299 61.901 0 112.104 50.083 112.298 111.938 0 62.228-50.431 112.659-112.64 112.659 0 0 0 0 0 0zM129.365 16.896c-26.769 0-48.469 21.7-48.469 48.469s21.7 48.469 48.469 48.469c26.769 0 48.469-21.7 48.469-48.469 0 0 0 0 0 0-0.192-26.691-21.778-48.277-48.451-48.469zM894.293 942.933c-61.874-0.194-111.957-50.397-111.957-112.298 0-62.021 50.278-112.299 112.299-112.299s112.298 50.278 112.299 112.298c-0.194 62.062-50.55 112.299-112.639 112.299 0 0 0 0-0.001 0zM894.293 781.824c0 0 0 0 0 0-26.769 0-48.469 21.7-48.469 48.469s21.7 48.469 48.469 48.469c26.769 0 48.469-21.7 48.469-48.469 0 0 0 0 0 0-0.192-26.691-21.778-48.277-48.451-48.469z" />
-<glyph unicode="&#xe921;" glyph-name="bbb-text-tool" d="M935.253 942.933h-845.824l-8.875-254.293h36.523q22.528 120.491 68.267 156.331t170.667 34.133h83.968v-746.496q0-96.597-23.211-120.491t-118.443-31.403v-27.648h433.835v27.648c-1.445-0.030-3.148-0.047-4.855-0.047-41.463 0-80.565 10.114-114.972 28.009q-25.582 19.825-25.582 106.524v765.611h83.285q130.048 0 170.667-36.181t68.267-155.989h34.133z" />
-<glyph unicode="&#xe922;" glyph-name="bbb-plus" d="M968.021 486.229h-421.888v414.037c0 21.585-17.498 39.083-39.083 39.083s-39.083-17.498-39.083-39.083v-413.696h-411.989c-21.585 0-39.083-17.498-39.083-39.083s17.498-39.083 39.083-39.083h413.355v-413.013c0-21.585 17.498-39.083 39.083-39.083s39.083 17.498 39.083 39.083v413.013h420.523c21.491 0 38.912 17.421 38.912 38.912s-17.421 38.912-38.912 38.912z" />
-<glyph unicode="&#xe923;" glyph-name="bbb-fit-to-width" d="M1004.544 443.904c0.059 0.715 0.092 1.548 0.092 2.389s-0.033 1.674-0.099 2.498c0.154 1.019 0.237 2.323 0.237 3.646s-0.084 2.627-0.246 3.907l0.016-0.152c0.051 0.664 0.080 1.438 0.080 2.219s-0.029 1.555-0.086 2.321c-0.288 2.678-0.89 5.222-1.772 7.63-2.492 3.683-4.962 7.021-7.598 10.218l0.16-0.2-127.659 111.616c-5.177 3.733-11.648 5.971-18.642 5.971-17.72 0-32.085-14.365-32.085-32.085 0-8.53 3.328-16.282 8.757-22.029l63.815-55.622h-755.371l63.488 57.344c8.18 5.891 13.444 15.388 13.444 26.114 0 17.72-14.365 32.085-32.085 32.085-9.191 0-17.479-3.864-23.328-10.056l-127.673-111.631c-1.798-1.798-3.379-3.813-4.7-6.003-1.024-1.25-1.924-2.476-2.733-3.765-0.888-2.317-1.489-4.86-1.771-7.5-0.063-0.805-0.092-1.579-0.092-2.359s0.029-1.555 0.085-2.321l-0.006 0.102c-0.134-1.076-0.21-2.321-0.21-3.584s0.076-2.508 0.224-3.731c-0.072-0.568-0.105-1.401-0.105-2.242s0.033-1.674 0.097-2.499c1.63-4.004 3.942-7.522 6.826-10.479l127.652-127.652c5.928-7.486 15.016-12.245 25.216-12.245 17.72 0 32.085 14.365 32.085 32.085 0 10.2-4.759 19.288-12.178 25.165l-72.429 71.048h772.096l-73.387-73.387c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l127.71 127.725c3.008 2.935 5.431 6.453 7.090 10.373z" />
-<glyph unicode="&#xe924;" glyph-name="bbb_applause" d="M1002.496 509.781c2.672 7.958 4.213 17.122 4.213 26.645 0 47.694-38.663 86.357-86.357 86.357-11.862 0-23.165-2.392-33.454-6.719-1.693 33.296-23.787 60.679-53.823 70.705-9.667 3.101-20.14 4.794-31.009 4.794-17.454 0-33.887-4.367-48.268-12.067l-127.451-64.926c4.078 2.361 7.411 5.585 9.83 9.441l24.303 41.418c7.038 12.456 11.184 27.352 11.184 43.217 0 31.719-16.576 59.566-41.538 75.351-8.72 5.242-18.401 9.237-28.683 11.682 3.846 10.476 6.49 22.525 6.49 35.192 0 31.475-16.323 59.138-40.966 74.986-12.726 7.173-27.513 11.273-43.258 11.273-28.995 0-54.742-13.905-70.937-35.41-14.892 19.212-37.994 31.64-63.999 31.64-7.528 0-14.813-1.042-21.719-2.988-26.149-7.217-47.994-24.392-61.298-47.166l-131.334-223.035-3.755 46.763c-0.27 29.953-13.358 56.797-34.038 75.35-12.859 11.424-29.765 18.351-48.288 18.351-1.779 0-3.543-0.064-5.29-0.19-68.032-6.813-65.302-70.984-63.595-95.218v-3.072s29.355-163.499 3.072-271.019 26.283-211.285 151.211-278.869c3.9-2.137 8.544-3.393 13.483-3.393 15.73 0 28.481 12.752 28.481 28.481 0 10.792-6.002 20.182-14.85 25.014-102.549 56.053-144.874 128.416-123.37 215.456 27.989 114.347 0 273.067-2.048 292.864-2.048 31.744 0 32.085 12.629 34.133 0.605 0.079 1.304 0.124 2.014 0.124 4.903 0 9.304-2.154 12.306-5.567 8.692-9.269 14.021-21.749 14.021-35.474 0-0.375-0.004-0.749-0.012-1.122l7.51-124.19c2.633-16.458 16.729-28.884 33.727-28.884 11.37 0 21.441 5.559 27.645 14.108l170.735 289.891c5.699 10.32 15.069 18.023 26.307 21.422 2.598 0.906 5.23 1.382 7.973 1.382 7.806 0 14.712-3.853 18.919-9.761 4.095-5.612 6.524-12.56 6.524-20.074 0-5.122-1.128-9.981-3.15-14.341l-75.688-125.4-27.648-47.104c-2.436-4.107-3.876-9.053-3.876-14.336 0-15.713 12.738-28.452 28.452-28.452 10.431 0 19.551 5.613 24.504 13.984l102.472 172.505 36.864 62.805c5.846 8.592 15.578 14.161 26.612 14.161 4.831 0 9.413-1.068 13.522-2.98 7.522-6.225 12.412-15.746 12.412-26.409 0-5.925-1.51-11.497-4.165-16.353l-26.876-52.046c-2.403-4.045-3.824-8.917-3.824-14.122 0-9.334 4.569-17.601 11.593-22.686-2.046 1.269-4.516 2.528-7.094 3.578-58.36 21.624-84.301-13.875-102.733-48.691 0 0-63.147-153.6-143.019-230.059-100.011-95.573-77.824-254.635-6.144-356.011 44.377-67.91 119.082-112.803 204.424-115.362 41.243 0.359 79.621 10.672 113.313 28.623l131.116 64.552 193.536 98.645c27.968 15.396 46.603 44.674 46.603 78.305 0 13.971-3.216 27.19-8.948 38.959-4.678 8.8-10.959 16.714-18.448 23.285l18.68 9.637c27.968 15.396 46.603 44.674 46.603 78.305 0 13.971-3.216 27.19-8.948 38.959-4.808 9.098-11.324 17.249-19.117 23.958 16.727 11.145 29.349 27.416 35.559 46.574zM542.379 595.456c10.849 17.294 17.284 38.314 17.284 60.837 0 12.405-1.952 24.353-5.565 35.555-4.612 11.425-12.477 21.596-22.465 29.092 3.407-1.633 7.623-2.661 12.079-2.661 10.245 0 19.221 5.439 24.196 13.586 4.411 4.552 10.454 7.296 17.137 7.296s12.726-2.744 17.063-7.168c8.235-6.302 13.49-16.129 13.49-27.184 0-4.987-1.070-9.724-2.992-13.995l-25.172-38.014c-2.694-4.224-4.293-9.373-4.293-14.896 0-15.458 12.531-27.989 27.989-27.989 4.82 0 9.356 1.218 13.316 3.364l-100.158-50.932zM936.619 390.656c-2.262-7.643-7.268-13.87-13.85-17.672l-189.244-95.651-34.133-16.725c-9.346-4.964-15.602-14.637-15.602-25.771 0-16.063 13.022-29.085 29.085-29.085 4.929 0 9.572 1.226 13.64 3.39l130.915 68.19c3.923 2.029 8.564 3.219 13.483 3.219 16.482 0 29.843-13.361 29.843-29.843 0-11.563-6.577-21.591-16.193-26.546l-159.911-83.364-164.523-83.968c-133.461-68.267-221.184 36.181-245.077 68.267-57.685 83.968-76.117 210.261-0.683 283.989 88.747 84.651 153.941 243.029 155.648 247.808 12.288 25.259 14.677 24.235 27.648 19.797 3.406-6.617 5.402-14.44 5.402-22.729 0-11.673-3.959-22.421-10.607-30.975l-55.552-102.286c-1.783-4.003-2.821-8.674-2.821-13.588 0-18.851 15.282-34.133 34.133-34.133 4.454 0 8.708 0.853 12.609 2.404l299.46 153.519c6.242 3.479 13.692 5.527 21.621 5.527 4.458 0 8.764-0.647 12.831-1.853 9.609-2.371 16.938-10.976 17.429-21.371 0.034-0.602 0.052-1.244 0.052-1.891 0-11.883-6.072-22.348-15.283-28.461l-178.302-90.873c-9.23-4.814-15.424-14.313-15.424-25.259 0-15.682 12.713-28.394 28.394-28.394 4.736 0 9.201 1.16 13.127 3.21l178.361 90.72 64.512 34.133c3.923 2.029 8.564 3.219 13.483 3.219 16.482 0 29.843-13.361 29.843-29.843 0-11.563-6.577-21.591-16.193-26.546l-65.021-34.212-77.141-39.253-101.035-51.883c-9.418-4.753-15.763-14.35-15.763-25.429 0-15.681 12.712-28.393 28.393-28.393 4.602 0 8.948 1.095 12.792 3.038l178.355 90.72c3.926 2.114 8.591 3.357 13.546 3.357 16.024 0 29.013-12.99 29.013-29.013 0-3.403-0.586-6.669-1.662-9.703z" />
-<glyph unicode="&#xe925;" glyph-name="bbb-undo" d="M517.803 772.949h-307.2l120.491 121.173c5.21 5.192 8.433 12.374 8.433 20.309s-3.223 15.117-8.432 20.309c-5.265 5.051-12.424 8.16-20.31 8.16s-15.045-3.11-20.32-8.169l-167.243-167.244c-4.020-2.564-7.334-5.878-9.822-9.771l-17.143-17.194 17.067-17.067c2.564-4.020 5.878-7.334 9.771-9.822l167.381-167.33c5.198-5.198 12.378-8.412 20.309-8.412 15.863 0 28.722 12.859 28.722 28.722 0 7.931-3.215 15.112-8.412 20.309l-121.173 121.173h307.2c190.587 0 345.088-154.501 345.088-345.088s-154.501-345.088-345.088-345.088c-3.182 1.082-6.847 1.707-10.658 1.707-18.851 0-34.133-15.282-34.133-34.133s15.282-34.133 34.133-34.133c3.811 0 7.476 0.625 10.899 1.777-0.139-0.070-0.019-0.070 0.101-0.070 226.404 0 409.941 183.537 409.941 409.941 0 226.284-183.343 409.747-409.581 409.941z" />
-<glyph unicode="&#xe926;" glyph-name="bbb-pen-tool" d="M966.315 885.931c-62.464 61.44-166.912 51.2-243.371-23.893l-601.429-592.896c-3.436-3.355-6.119-7.465-7.78-12.064l-94.961-279.093c-1.167-3.173-1.843-6.836-1.843-10.658 0-9.29 3.991-17.648 10.351-23.453 5.966-5.161 13.767-8.292 22.3-8.292 4.258 0 8.334 0.78 12.093 2.204l267.712 108.125c4.094 1.696 7.603 4 10.596 6.841l601.756 593.223c76.459 75.093 87.040 177.493 24.576 239.957zM197.291 253.781l523.605 515.755 127.317-125.269-523.605-516.096zM163.157 198.144l108.203-106.496-168.96-67.584zM896 691.371l-2.048-2.048-127.317 125.269 2.048 2.048c50.517 50.176 114.688 60.416 152.917 23.893s25.6-98.987-25.6-149.163z" />
-<glyph unicode="&#xe927;" glyph-name="bbb-lock" d="M869.035 524.8h-49.835v130.731c0 158.379-136.533 287.403-307.2 287.403s-307.2-129.024-307.2-287.403v-130.731h-49.835c-0.62 0.023-1.349 0.036-2.081 0.036-32.848 0-59.607-26.067-60.721-58.643l-0.003-454.417c1.117-32.678 27.876-58.745 60.724-58.745 0.732 0 1.461 0.013 2.187 0.039l713.964-0.003c0.62-0.023 1.349-0.036 2.081-0.036 32.848 0 59.607 26.067 60.721 58.643l0.003 454.417c-1.117 32.678-27.876 58.745-60.724 58.745-0.732 0-1.461-0.013-2.187-0.039zM273.067 655.531c4.666 124.511 106.729 223.678 231.954 223.678 2.454 0 4.9-0.038 7.336-0.114 1.724 0.076 4.169 0.114 6.623 0.114 125.225 0 227.288-99.168 231.941-223.255l0.013-131.154h-477.867v130.731zM863.573 16.896h-703.147v443.733h703.147v-443.733z" />
-<glyph unicode="&#xe928;" glyph-name="bbb-polling" horiz-adv-x="1536" d="M1460.736 861.184h-1075.2c-21.94-6.106-37.773-25.908-37.773-49.408s15.832-43.302 37.413-49.322l1075.56-0.086c4.026-1.138 8.65-1.792 13.427-1.792 28.277 0 51.2 22.923 51.2 51.2s-22.923 51.2-51.2 51.2c-4.777 0-9.401-0.654-13.787-1.878zM1102.336 492.544h-716.8c-21.94-6.106-37.773-25.908-37.773-49.408s15.832-43.302 37.413-49.322l717.16-0.086c4.026-1.138 8.65-1.792 13.427-1.792 28.277 0 51.2 22.923 51.2 51.2s-22.923 51.2-51.2 51.2c-4.777 0-9.401-0.654-13.787-1.878zM743.424 133.632h-358.4c-4.026 1.138-8.65 1.792-13.427 1.792-28.277 0-51.2-22.923-51.2-51.2s22.923-51.2 51.2-51.2c4.777 0 9.401 0.654 13.787 1.878l358.040-0.086c21.94 6.106 37.773 25.908 37.773 49.408s-15.832 43.302-37.413 49.322zM225.28 812.032c0-55.14-44.7-99.84-99.84-99.84s-99.84 44.7-99.84 99.84c0 55.14 44.7 99.84 99.84 99.84s99.84-44.7 99.84-99.84zM225.28 442.88c0-55.14-44.7-99.84-99.84-99.84s-99.84 44.7-99.84 99.84c0 55.14 44.7 99.84 99.84 99.84s99.84-44.7 99.84-99.84zM225.28 83.968c0-55.14-44.7-99.84-99.84-99.84s-99.84 44.7-99.84 99.84c0 55.14 44.7 99.84 99.84 99.84s99.84-44.7 99.84-99.84z" />
-<glyph unicode="&#xe929;" glyph-name="bbb-desktop" d="M926.379 891.733h-828.757c0 0 0 0-0.001 0-44.489 0-80.555-36.066-80.555-80.555 0-0.12 0-0.24 0.001-0.36v-595.949c0-44.489 36.066-80.555 80.555-80.555h269.312v-72.363h-88.064c0 0 0 0 0 0-15.835 0-28.672-12.837-28.672-28.672s12.837-28.672 28.672-28.672c0 0 0 0 0 0h466.261c15.835 0 28.672 12.837 28.672 28.672s-12.837 28.672-28.672 28.672h-88.064v72.363h269.312c44.489 0 80.555 36.066 80.555 80.555v595.968c0 0.101 0.001 0.221 0.001 0.341 0 44.489-36.066 80.555-80.555 80.555 0 0-0.001 0-0.001 0zM600.064 61.952h-176.128v72.363h176.128v-72.363zM949.931 214.869c0-12.819-10.392-23.211-23.211-23.211h-829.099c-12.819 0-23.211 10.392-23.211 23.211v595.968c0 12.819 10.392 23.211 23.211 23.211h828.757c12.819 0 23.211-10.392 23.211-23.211v-595.968z" />
-<glyph unicode="&#xe92a;" glyph-name="bbb-fit-to-screen" d="M1004.544 435.712c1.418 3.49 2.241 7.539 2.241 11.78 0 8.695-3.459 16.582-9.075 22.36l-100.686 100.686c-5.737 9.259-15.842 15.333-27.365 15.333-17.72 0-32.085-14.365-32.085-32.085 0-11.698 6.261-21.934 15.614-27.54l46.226-46.161h-246.443c-0.991 0.109-2.141 0.171-3.305 0.171-17.72 0-32.085-14.365-32.085-32.085s14.365-32.085 32.085-32.085c1.164 0 2.314 0.062 3.446 0.183l244.937-0.012-44.715-46.421c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l100.744 100.76c2.33 2.908 4.191 6.313 5.397 10.013zM403.115 448c0 17.72-14.365 32.085-32.085 32.085h-245.077l44.715 46.080c7.486 5.928 12.245 15.016 12.245 25.216 0 17.72-14.365 32.085-32.085 32.085-10.2 0-19.288-4.759-25.165-12.178l-99.379-100.76c-5.712-5.79-9.239-13.747-9.239-22.528s3.527-16.738 9.242-22.532l100.69-100.69c4.835-3.075 10.726-4.901 17.043-4.901 17.72 0 32.085 14.365 32.085 32.085 0 6.665-2.032 12.855-5.51 17.984l-44.643 46.309h245.077c0.001 0 0.001 0 0.002 0 17.6 0 31.891 14.171 32.083 31.726zM433.835 789.333l46.080 46.080v-245.077c1.731-16.241 15.358-28.78 31.915-28.78s30.184 12.54 31.902 28.64l0.012 243.853 46.421-44.715c5.928-7.486 15.016-12.245 25.216-12.245 17.72 0 32.085 14.365 32.085 32.085 0 10.2-4.759 19.288-12.178 25.165l-100.76 99.379c-5.79 5.712-13.747 9.239-22.528 9.239s-16.738-3.527-22.532-9.242l-100.69-100.69c-8.622-5.842-14.214-15.591-14.214-26.647 0-17.72 14.365-32.085 32.085-32.085 11.403 0 21.416 5.948 27.107 14.911zM590.165 106.667l-46.080-46.080v246.443c-1.731 16.241-15.358 28.78-31.915 28.78s-30.184-12.54-31.902-28.64l-0.012-245.218-46.421 44.715c-5.928 7.486-15.016 12.245-25.216 12.245-17.72 0-32.085-14.365-32.085-32.085 0-10.2 4.759-19.288 12.178-25.165l100.76-100.744c5.79-5.712 13.747-9.239 22.528-9.239s16.738 3.527 22.532 9.242l100.69 100.69c4.282 5.403 6.87 12.32 6.87 19.84 0 17.72-14.365 32.085-32.085 32.085-7.521 0-14.437-2.587-19.907-6.921z" />
-<glyph unicode="&#xe92b;" glyph-name="bbb-fullscreen" d="M1004.544 923.136c-4.952 11.721-16.352 19.797-29.639 19.797-0.020 0-0.040 0-0.060 0h-201.384c-16.241-1.731-28.78-15.358-28.78-31.915s12.54-30.184 28.64-31.902l124.386-0.012-267.605-267.605c-7.486-5.928-12.245-15.016-12.245-25.216 0-17.72 14.365-32.085 32.085-32.085 10.2 0 19.288 4.759 25.165 12.178l267.656 267.672v-124.245c-0.109-0.991-0.171-2.141-0.171-3.305 0-17.72 14.365-32.085 32.085-32.085s32.085 14.365 32.085 32.085c0 1.164-0.062 2.314-0.183 3.446l0.012 200.905c0.009 0.289 0.015 0.629 0.015 0.97 0 4.067-0.757 7.957-2.137 11.538zM348.501 329.557l-267.605-267.605v124.245c-1.731 16.241-15.358 28.78-31.915 28.78s-30.184-12.54-31.902-28.64l-0.012-201.527c0-17.72 14.365-32.085 32.085-32.085 0 0 0 0 0 0h201.387c0.991-0.109 2.141-0.171 3.305-0.171 17.72 0 32.085 14.365 32.085 32.085s-14.365 32.085-32.085 32.085c-1.164 0-2.314-0.062-3.446-0.183l-124.446 0.012 267.605 267.605c6.991 5.924 11.398 14.71 11.398 24.526 0 17.72-14.365 32.085-32.085 32.085-9.731 0-18.449-4.332-24.334-11.172zM125.952 879.104h124.245c16.241 1.731 28.78 15.358 28.78 31.915s-12.54 30.184-28.64 31.902l-201.186 0.012c-17.72 0-32.085-14.365-32.085-32.085v-201.387c1.731-16.241 15.358-28.78 31.915-28.78s30.184 12.54 31.902 28.64l0.012 124.727 267.605-267.605c5.403-4.282 12.32-6.87 19.84-6.87 17.72 0 32.085 14.365 32.085 32.085 0 7.521-2.587 14.437-6.921 19.907zM974.848 218.283c-0.102 0.001-0.223 0.002-0.343 0.002-17.532 0-31.744-14.212-31.744-31.744 0-0.121 0.001-0.241 0.002-0.362v-124.227l-267.605 267.605c-5.928 7.486-15.016 12.245-25.216 12.245-17.72 0-32.085-14.365-32.085-32.085 0-10.2 4.759-19.288 12.178-25.165l267.672-267.656h-123.904c-16.241-1.731-28.78-15.358-28.78-31.915s12.54-30.184 28.64-31.902l201.527-0.012c0 0 0 0 0 0 17.72 0 32.085 14.365 32.085 32.085 0 0 0 0 0 0v201.387c0 0.002 0 0.005 0 0.007 0 17.532-14.212 31.744-31.744 31.744-0.24 0-0.479-0.003-0.718-0.008z" />
-<glyph unicode="&#xe92c;" glyph-name="bbb-settings" d="M1004.544 493.739c-1.185 12.647-9.554 23.075-20.94 27.235l-126.516 44.786c-5.845 17.315-11.846 31.642-18.701 45.471l58.295 118.71c1.902 3.978 3.014 8.647 3.014 13.576 0 7.845-2.816 15.033-7.491 20.607-19.794 23.736-41.027 44.969-64.021 64.161-6.317 5.278-13.504 8.094-21.35 8.094-4.928 0-9.597-1.111-13.77-3.097l-119.955-57.602c-11.707 5.903-26.034 11.905-40.791 16.984l-47.273 127.059c-4.232 11.609-14.66 19.977-27.179 21.153-13.835 1.32-29.763 2.068-45.867 2.068s-32.032-0.747-47.753-2.209c-10.632-1.034-21.060-9.403-25.221-20.788l-44.786-126.516c-17.315-5.845-31.642-11.846-45.471-18.701l-118.71 58.295c-3.978 1.902-8.647 3.014-13.576 3.014-7.845 0-15.033-2.816-20.607-7.491-23.736-19.794-44.969-41.027-64.161-64.021-5.278-6.317-8.094-13.504-8.094-21.35 0-4.928 1.111-9.597 3.097-13.77l57.602-120.297c-5.903-11.707-11.905-26.034-16.984-40.791l-127.059-47.273c-11.609-4.232-19.977-14.66-21.153-27.179-0.010-15.147-2.399-30.507-2.399-45.867s0-30.72 2.389-45.739c1.185-12.647 9.554-23.075 20.94-27.235l126.516-44.786c5.845-17.315 11.846-31.642 18.701-45.471l-58.295-118.71c-1.902-3.978-3.014-8.647-3.014-13.576 0-7.845 2.816-15.033 7.491-20.607 19.794-23.736 41.027-44.969 64.021-64.161 6.285-5.314 13.459-8.154 21.297-8.154 4.952 0 9.64 1.134 13.817 3.157l120.643 57.261c11.707-5.903 26.034-11.905 40.791-16.984l47.273-127.059c4.232-11.609 14.66-19.977 27.179-21.153 15.147-0.010 30.507-2.399 45.867-2.399s30.72 0 45.739 2.389c12.647 1.185 23.075 9.554 27.235 20.94l44.786 126.516c17.315 5.845 31.642 11.846 45.471 18.701l118.71-58.295c3.988-1.94 8.676-3.074 13.628-3.074 7.838 0 15.013 2.841 20.551 7.549 23.741 19.798 44.973 41.030 64.165 64.024 5.278 6.317 8.094 13.504 8.094 21.35 0 4.928-1.111 9.597-3.097 13.77l-57.944 120.638c5.903 11.707 11.905 26.034 16.984 40.791l127.059 47.273c11.609 4.232 19.977 14.66 21.153 27.179 0.010 15.147 2.399 30.507 2.399 45.867s-1.365 30.72-2.731 45.739zM942.421 428.203l-121.515-43.349c-9.605-3.519-16.91-11.273-19.741-20.938-6.819-23.47-15.3-43.621-25.758-62.527-1.401-2.676-2.683-7.669-2.683-12.962s1.281-10.286 3.551-14.686l55.212-116.215q-13.312-14.677-27.989-27.989l-117.419 55.296c-4.221 2.185-9.214 3.467-14.507 3.467s-10.286-1.281-14.686-3.551c-17.181-9.59-37.333-18.070-58.451-24.296-12.017-3.425-19.771-10.73-23.219-20.115l-43.42-121.735c-5.913-0.329-12.834-0.516-19.797-0.516s-13.884 0.187-20.755 0.557l-42.391 121.474c-3.519 9.605-11.273 16.91-20.938 19.741-23.47 6.819-43.621 15.3-62.527 25.758-2.676 1.401-7.669 2.683-12.962 2.683s-10.286-1.281-14.686-3.551l-116.215-55.212q-14.677 13.312-27.989 27.989l55.296 116.395c2.185 4.221 3.467 9.214 3.467 14.507s-1.281 10.286-3.551 14.686c-9.59 17.181-18.070 37.333-24.296 58.451-3.425 12.017-10.73 19.771-20.115 23.219l-122.759 43.42q0 9.899 0 19.797t0 19.797l121.515 43.349c9.605 3.519 16.91 11.273 19.741 20.938 6.819 23.47 15.3 43.621 25.758 62.527 1.401 2.676 2.683 7.669 2.683 12.962s-1.281 10.286-3.551 14.686l-54.188 116.215q13.312 14.677 27.989 27.989l116.395-55.296c4.221-2.185 9.214-3.467 14.507-3.467s10.286 1.281 14.686 3.551c17.181 9.59 37.333 18.070 58.451 24.296 12.017 3.425 19.771 10.73 23.219 20.115l43.42 121.735c5.913 0.329 12.834 0.516 19.797 0.516s13.884-0.187 20.755-0.557l42.391-121.474c3.519-9.605 11.273-16.91 20.938-19.741 23.47-6.819 43.621-15.3 62.527-25.758 2.676-1.401 7.669-2.683 12.962-2.683s10.286 1.281 14.686 3.551l116.215 55.212q14.677-13.312 27.989-27.989l-55.296-116.053c-2.185-4.221-3.467-9.214-3.467-14.507s1.281-10.286 3.551-14.686c9.59-17.181 18.070-37.333 24.296-58.451 3.425-12.017 10.73-19.771 20.115-23.219l121.735-43.42q0-9.899 0-19.797t1.024-20.139zM512 677.717c-126.681 0-229.376-102.695-229.376-229.376s102.695-229.376 229.376-229.376c126.561 0 229.181 102.501 229.376 229.016 0 0.019 0 0.019 0 0.019 0 126.749-102.653 229.523-229.357 229.717zM512 282.453c-91.429 0-165.547 74.118-165.547 165.547s74.118 165.547 165.547 165.547c91.429 0 165.547-74.118 165.547-165.547-0.194-91.351-74.196-165.353-165.528-165.547z" />
-<glyph unicode="&#xe92d;" glyph-name="bbb_thumbs_down" d="M860.843 769.877c-38.056 101.947-134.604 173.229-247.8 173.229-3.364 0-6.713-0.063-10.046-0.188l-318.666 0.014c-55.948-1.48-100.92-46.452-102.397-102.261 0.916-23.003 9.4-43.723 22.996-60.032-28.761-17.777-47.732-48.827-48.597-84.366 0.332-23.516 8.645-44.902 22.33-61.75-27.212-18.451-44.756-49.228-44.86-84.108 1.189-36.031 20.494-67.289 49.053-85.094-4.053-6.372-8.054-13.333-11.242-20.727-5.061-11.614-7.851-24.346-7.851-37.729 0-26.585 11.012-50.598 28.723-67.726 21.76-21.152 51.464-34.178 84.211-34.178 0.764 0 1.526 0.007 2.286 0.021l209.123-0.002c-23.848-69.005-41.242-149.327-48.852-232.478-0.724-7.896-0.966-12.337-0.966-16.835 0-27.591 9.093-53.058 24.447-73.568 14.222-16.41 35.187-27.175 58.68-28.006 2.284-0.156 4.785-0.243 7.306-0.243 54.169 0 98.981 40.057 106.432 92.166 21.913 71.23 65.945 194.11 91.203 223.124 37.547 42.325 53.589 59.733 60.075 68.267l6.144 5.803c94.891 92.16 126.293 284.331 68.267 426.667zM750.933 384.171v0c-12.288-10.923-32.085-34.133-68.267-75.776-42.325-47.787-97.621-224.597-102.4-246.101-12.629-49.835-42.325-49.835-50.517-48.811-0.458-0.031-0.992-0.048-1.531-0.048-6.918 0-13.159 2.898-17.574 7.547-6.082 9.762-9.682 21.599-9.682 34.277 0 2.72 0.166 5.401 0.487 8.034 8.924 90.588 28.096 174.037 56.528 253.068 2.541-1.438 5.47 6.13 5.47 14.383 0 18.851-15.282 34.133-34.133 34.133-1.169 0-2.325-0.059-3.464-0.174l-247.323 0.012c-0.973-0.056-2.111-0.087-3.257-0.087-15.395 0-29.452 5.726-40.159 15.163-7.171 6.236-11.72 15.458-11.72 25.743 0 4.993 1.072 9.735 2.998 14.009 6.363 15.856 21.298 27.242 39.027 28.449 16.729 0.008 30.177 13.456 30.177 30.045s-13.448 30.037-30.037 30.037c-6.681-0.059-13.154-0.802-19.398-2.162-2.509 1.379-6.141 2.128-9.943 2.162-22.956 1.214-41.278 19.418-42.674 42.198 1.379 22.924 19.522 41.067 42.193 42.446 1.306-0.164 2.667-0.261 4.052-0.261s2.746 0.097 4.079 0.284c2.044-0.203 4.602-0.308 7.185-0.308s5.141 0.105 7.671 0.312c16.257-0.022 29.705 13.426 29.705 30.015s-13.448 30.037-30.037 30.037c-22.985 1.603-41.135 20.227-41.982 43.269 1.365 22.768 19.33 40.851 41.842 42.398 3.353 0.119 6.388 0.735 9.216 1.779 4.793-1.082 10.564-1.7 16.466-1.771 16.648-0.001 30.096 13.448 30.096 30.037s-13.448 30.037-30.037 30.037c-22.397 1.703-40.126 19.55-41.635 41.846 1.36 22.826 19.325 40.909 41.837 42.456l318.945 0.008c2.66 0.124 5.779 0.194 8.914 0.194 88.71 0 164.246-56.401 192.706-135.3 48.578-118.163 22.978-287.806-53.822-363.582z" />
-<glyph unicode="&#xe92e;" glyph-name="bbb_thumbs_up" d="M867.669 199.851c-0.334 23.391-8.647 44.777-22.332 61.625 27.725 17.923 45.685 48.709 45.685 83.69 0 36.95-20.038 69.219-49.84 86.535 4.197 6.020 8.399 12.514 11.871 19.438 5.075 11.539 7.866 24.27 7.866 37.654 0 26.585-11.012 50.598-28.723 67.726-21.76 21.152-51.464 34.178-84.211 34.178-0.764 0-1.526-0.007-2.286-0.021l-209.465 0.002c23.845 69.004 41.239 149.325 48.851 232.476 0.732 7.928 0.978 12.402 0.978 16.934 0 27.561-9.099 52.997-24.457 73.467-14.122 16.672-35.093 27.678-58.655 28.691-2.312 0.158-4.812 0.245-7.333 0.245-54.169 0-98.981-40.057-106.432-92.166-21.913-71.23-65.945-194.11-91.545-222.782-37.205-43.008-53.248-60.075-58.709-66.901l-6.144-5.803c-95.915-93.867-126.635-286.037-68.267-428.373 38.053-101.953 134.604-173.242 247.805-173.242 3.482 0 6.949 0.067 10.398 0.201l318.309-0.015c55.948 1.48 100.92 46.452 102.397 102.261-1.408 23.032-10.343 43.602-24.333 59.65 28.733 17.819 47.703 48.868 48.568 84.407zM739.328 12.8h-318.805c-2.66-0.124-5.779-0.194-8.914-0.194-88.71 0-164.246 56.401-192.706 135.3-48.236 118.505-22.636 288.147 54.164 363.923v0c12.288 10.923 32.085 34.133 68.267 75.776 42.325 47.787 97.621 224.597 102.4 246.101 12.629 49.835 42.325 49.835 50.517 48.811 0.458 0.031 0.992 0.048 1.531 0.048 6.918 0 13.159-2.898 17.574-7.547 6.082-9.762 9.682-21.599 9.682-34.277 0-2.72-0.166-5.401-0.487-8.034-8.92-90.586-28.093-174.036-56.528-253.066-2.541 1.436-5.47-6.132-5.47-14.385 0-18.851 15.282-34.133 34.133-34.133 1.169 0 2.325 0.059 3.464 0.174l244.251-0.012c0.536 0.017 1.166 0.027 1.798 0.027 16.252 0 31.014-6.381 41.917-16.775 7.213-6.27 11.762-15.493 11.762-25.778 0-4.993-1.072-9.735-2.998-14.009-6.461-15.716-21.37-26.962-39.032-28.108-16.723-0.007-30.172-13.455-30.172-30.044s13.448-30.037 30.037-30.037c6.682 0.062 13.155 0.805 19.399 2.162 2.507-1.379 6.139-2.128 9.941-2.162 23.39 0 42.339-18.95 42.339-42.325s-18.95-42.325-42.325-42.325c-1.179 0.17-2.541 0.267-3.925 0.267s-2.746-0.097-4.079-0.284c-2.044 0.201-4.602 0.306-7.185 0.306s-5.141-0.105-7.671-0.31c-16.257 0.022-29.705-13.426-29.705-30.016s13.448-30.037 30.037-30.037c23.376 0 42.325-18.95 42.325-42.325s-18.95-42.325-42.325-42.325c-3.214-0.117-6.249-0.733-9.078-1.772-4.79 1.082-10.561 1.7-16.463 1.772-16.648 0.001-30.096-13.448-30.096-30.037s13.448-30.037 30.037-30.037c21.674-2.022 38.506-20.122 38.506-42.153 0-21.063-15.386-38.533-35.532-41.783z" />
-<glyph unicode="&#xe92f;" glyph-name="bbb_file" d="M866.645 716.629l-225.963 226.304h-425.643c-44.977-0.193-81.386-36.602-81.579-81.56v-826.728c0.193-44.977 36.602-81.386 81.56-81.579h593.939c44.977 0.193 81.386 36.602 81.579 81.56v624.317c-0.040 22.521-9.161 42.903-23.896 57.688zM658.091 840.533l130.048-130.048h-108.203c-12.065 0-21.845 9.78-21.845 21.845v108.203zM808.96 13.141h-593.92c-12.065 0-21.845 9.78-21.845 21.845v826.368c0.192 11.917 9.898 21.504 21.843 21.504 0.001 0 0.002 0 0.003 0h383.317v-150.869c0.193-44.977 36.602-81.386 81.56-81.579h150.888v-614.4c0.015-0.306 0.024-0.664 0.024-1.024 0-12.065-9.78-21.845-21.845-21.845-0.008 0-0.017 0-0.025 0z" />
-<glyph unicode="&#xe930;" glyph-name="bbb_upload" d="M512 34.645c-14.327 0-25.941 11.614-25.941 25.941v389.803l-98.304-98.304c-4.741-4.666-11.25-7.547-18.432-7.547s-13.691 2.881-18.435 7.55c-4.744 4.7-7.684 11.221-7.684 18.429s2.94 13.729 7.685 18.43l143.021 143.021c4.755 4.747 11.319 7.683 18.569 7.683 3.516 0 6.871-0.691 9.937-1.943 3.145-1.37 5.978-3.328 8.355-5.736l143.022-143.022c4.748-4.703 7.687-11.224 7.687-18.432s-2.94-13.729-7.685-18.43c-4.778-4.589-11.276-7.414-18.434-7.414s-13.656 2.825-18.441 7.421l-98.295 98.295v-389.461c0.002-0.104 0.002-0.227 0.002-0.35 0-14.327-11.614-25.941-25.941-25.941-0.241 0-0.481 0.003-0.72 0.010zM657.749 229.888c-12.63 0-22.869 10.239-22.869 22.869s10.239 22.869 22.869 22.869h159.061c0.387-0.004 0.844-0.006 1.302-0.006 74.49 0 135.711 56.813 142.696 129.472 0.286 3.646 0.424 7.218 0.424 10.821 0 36.75-14.305 70.159-37.65 94.962-25.553 27.403-61.932 44.556-102.318 44.644h-39.611v39.936s0 3.413 0 5.12c-0.247 117.445-95.512 212.558-212.992 212.558-83.419 0-155.637-47.956-190.589-117.802l-17.624-37.071-34.133 17.749c-12.676 6.879-27.754 10.923-43.777 10.923-0.090 0-0.18 0-0.269 0-45.186-2.029-81.937-35.734-88.666-79.347l-3.139-19.298-19.797-7.509c-57.253-19.371-99.398-68.696-108.1-128.845-0.741-6.143-1.105-12.26-1.105-18.461 0-40.532 15.561-77.43 41.036-105.045 28.605-32.253 70.226-52.602 116.604-52.8h145.785c12.63 0 22.869-10.239 22.869-22.869s-10.239-22.869-22.869-22.869h-146.091c-111.358 0.070-201.604 90.36-201.604 201.728 0 86.879 54.922 160.931 131.94 189.33 14.244 63.404 69.062 110.136 134.835 110.361 1.013 0.026 2.177 0.040 3.344 0.040 18.748 0 36.613-3.779 52.875-10.616 42.766 85.073 129.654 142.020 229.843 142.020 142.893 0 258.731-115.838 258.731-258.731 0-0.131 0-0.262 0-0.392v0.020c97.927-5.722 175.175-86.534 175.175-185.388 0-101.136-80.855-183.387-181.451-185.638l-164.732-0.004z" />
-<glyph unicode="&#xe931;" glyph-name="bbb-mute" d="M897.365 448l102.4 102.4c3.907 4.732 6.276 10.86 6.276 17.54 0 15.27-12.378 27.648-27.648 27.648-6.681 0-12.808-2.369-17.587-6.314l-102.353-102.362-102.4 102.4c-4.949 4.712-11.661 7.611-19.050 7.611-15.27 0-27.648-12.378-27.648-27.648 0-7.305 2.833-13.947 7.459-18.89l102.386-102.385-102.4-102.4c-6.191-5.109-10.108-12.783-10.108-21.372 0-15.27 12.378-27.648 27.648-27.648 8.589 0 16.263 3.916 21.334 10.061l102.438 102.447 102.4-102.4c4.425-3.139 9.935-5.018 15.884-5.018 15.27 0 27.648 12.378 27.648 27.648 0 6.121-1.989 11.778-5.357 16.359zM558.421-7.68c-7.613 0.054-14.487 3.176-19.454 8.19l-291.501 291.501h-138.581c-50.71 0-91.819 41.109-91.819 91.819v128.341c0 50.71 41.109 91.819 91.819 91.819h138.581l291.499 291.499c4.994 4.948 11.868 8.005 19.457 8.005 15.204 0 27.541-12.272 27.647-27.451v-856.074c0-15.27-12.378-27.648-27.648-27.648zM108.885 550.4c-20.171 0-36.523-16.352-36.523-36.523v-128.341c-0.102-1.023-0.16-2.212-0.16-3.414 0-20.171 16.352-36.523 36.523-36.523 0.056 0 0.112 0 0.169 0h149.837c7.613-0.054 14.487-3.176 19.454-8.19l252.589-252.589v724.651l-252.587-252.587c-4.969-5.016-11.843-8.138-19.446-8.192h-149.856z" />
-<glyph unicode="&#xe932;" glyph-name="bbb-unmute" d="M558.421-7.68c-7.613 0.054-14.487 3.176-19.454 8.19l-291.501 291.501h-138.581c-50.71 0-91.819 41.109-91.819 91.819v128.341c0 50.71 41.109 91.819 91.819 91.819h138.581l291.499 291.499c4.994 4.948 11.868 8.005 19.457 8.005 15.204 0 27.541-12.272 27.647-27.451v-856.074c0-15.27-12.378-27.648-27.648-27.648zM108.885 550.4c-20.171 0-36.523-16.352-36.523-36.523v-128.341c-0.102-1.023-0.16-2.212-0.16-3.414 0-20.171 16.352-36.523 36.523-36.523 0.056 0 0.112 0 0.169 0h149.837c7.613-0.054 14.487-3.176 19.454-8.19l252.589-252.589v724.651l-252.587-252.587c-4.969-5.016-11.843-8.138-19.446-8.192h-149.856z" />
-<glyph unicode="&#x1f554;" glyph-name="bbb-video" d="M673.451 153.088h-624.299c-0.101-0.001-0.221-0.002-0.341-0.002-17.532 0-31.744 14.212-31.744 31.744 0 0.001 0 0.001 0 0.002v526.336c-0.001 0.102-0.002 0.223-0.002 0.343 0 17.532 14.212 31.744 31.744 31.744 0.121 0 0.241-0.001 0.362-0.002h624.622c0.102 0.001 0.223 0.002 0.343 0.002 17.532 0 31.744-14.212 31.744-31.744 0-0.121-0.001-0.241-0.002-0.362v-526.318c0-0.002 0-0.005 0-0.007 0-17.532-14.212-31.744-31.744-31.744-0.24 0-0.479 0.003-0.718 0.008zM80.896 216.917h560.811v462.165h-560.811v-462.165zM974.848 216.235c-0.005 0-0.012 0-0.018 0-4.688 0-9.141 1.005-13.155 2.812l-236.683 105.049c-11.353 5.109-19.115 16.321-19.115 29.347 0 0.003 0 0.006 0 0.008v168.277c0.278 12.759 7.962 23.657 18.912 28.59l237.088 105.895c3.817 1.73 8.276 2.739 12.971 2.739 17.72 0 32.085-14.365 32.085-32.085 0-0.003 0-0.006 0-0.008v-378.88c0-0.001 0-0.001 0-0.002 0-17.532-14.212-31.744-31.744-31.744-0.12 0-0.24 0.001-0.36 0.002zM770.048 374.272l173.056-76.8v280.235l-173.056-76.8v-126.976z" />
-</font></defs></svg>
\ No newline at end of file
+<font id="BigBlueButton" horiz-adv-x="1024" >
+  <font-face 
+    font-family="BigBlueButton"
+    font-weight="400"
+    font-stretch="normal"
+    units-per-em="1024"
+    panose-1="2 0 5 3 0 0 0 0 0 0"
+    ascent="819"
+    descent="-205"
+    bbox="0 -205 1212 820"
+    underline-thickness="51"
+    underline-position="-102"
+    unicode-range="U+0020-E932"
+  />
+<missing-glyph horiz-adv-x="1048" 
+ />
+    <glyph glyph-name=".notdef" horiz-adv-x="1048" 
+ />
+    <glyph glyph-name="space" unicode=" " horiz-adv-x="524" 
+ />
+    <glyph glyph-name="logout" unicode="&#xe900;" 
+d="M160 -117h84c19 0 30 -14 30 -32c0 -22 -7 -34 -30 -34h-84c-83 0 -150 66 -150 150v670c0 83 67 150 150 150h84c16 0 30 -17 30 -32c0 -16 -9 -32 -30 -32h-84c-47 0 -87 -40 -87 -86v-667c0 -47 40 -87 87 -87zM676 -9c-6 -5 -14 -8 -22 -8c-7 0 -15 3 -21 8
+s-8 12 -8 19c0 9 5 20 12 27l233 233h-625c-22 0 -35 14 -35 30c0 17 13 30 35 30h625l-233 233c-7 7 -11 16 -11 25s4 17 11 23c6 5 14 8 21 8c8 0 16 -3 22 -9c14 -13 284 -283 310 -310c-30 -30 -272 -270 -314 -309z" />
+    <glyph glyph-name="more" unicode="&#xe902;" 
+d="M17 307c0 60 49 109 109 109c61 0 110 -49 110 -109s-49 -109 -110 -109c-60 0 -109 49 -109 109zM403 307c0 60 49 109 109 109s109 -49 109 -109s-49 -109 -109 -109s-109 49 -109 109zM788 307c0 60 49 109 110 109c60 0 109 -49 109 -109s-49 -109 -109 -109
+c-61 0 -110 49 -110 109z" />
+    <glyph glyph-name="promote" unicode="&#xe903;" horiz-adv-x="1028" 
+d="M993 601c10 -8 11 -18 11 -28v-522c0 -14 -10 -33 -24 -33h-4c0 0 -520 129 -529 129v0c0 -65 -58 -110 -119 -110c-65 0 -120 55 -120 120v44l-128 31v-9c0 -15 -18 -27 -32 -27c-17 0 -31 12 -31 29v184c0 14 17 28 31 28c18 0 32 -11 32 -28v-17l886 215
+c7 2 18 1 27 -6zM331 92c20 0 55 7 55 58l-113 27v-30c0 -31 27 -55 58 -55zM944 82v450l-864 -211v-31c287 -69 577 -139 864 -208z" />
+    <glyph glyph-name="video_off" unicode="&#xe904;" 
+d="M963 78l-236 106c-10 5 -20 17 -20 31v167c0 14 6 21 20 27l236 106c4 2 9 3 13 3c16 0 31 -14 31 -34v-378c0 -18 -15 -31 -31 -31c-4 0 -9 1 -13 3zM945 153v280l-174 -78v-123zM915 662l-212 -208v-410c0 -17 -14 -31 -31 -31h-409s-110 -110 -113 -112
+c-5 -4 -12 -6 -18 -6c-10 0 -20 5 -26 13c-4 5 -6 11 -6 17c0 9 5 19 13 27l61 61h-123c-17 0 -31 14 -31 31v526c0 17 14 30 31 30h625c17 0 31 -13 31 -30v-24l160 160c5 5 13 8 20 8c8 0 17 -4 22 -9c8 -8 13 -17 13 -26c0 -6 -2 -12 -7 -17zM81 74h155l406 407v58h-561
+v-465zM642 74v318l-314 -318h314z" />
+    <glyph glyph-name="user" unicode="&#xe905;" 
+d="M860 85c79 -55 123 -143 123 -239c0 -17 -14 -31 -31 -31h-880c-17 0 -31 14 -31 31c0 96 44 184 123 239c85 58 198 86 348 86s263 -28 348 -86zM106 -123v-4h812c-10 65 -44 120 -95 158c-75 51 -171 75 -311 75s-236 -21 -311 -72c-55 -38 -88 -96 -95 -157zM512 239
+c-147 0 -263 115 -263 273c0 151 112 290 263 290c154 0 263 -136 263 -290c0 -153 -120 -273 -263 -273zM307 515c0 -105 89 -211 202 -211s201 85 201 211c0 118 -78 222 -198 222c-114 0 -205 -110 -205 -222z" />
+    <glyph glyph-name="up_arrow" unicode="&#xe906;" 
+d="M659 502c8 -8 12 -18 12 -29c0 -9 -3 -18 -10 -25c-8 -8 -18 -13 -29 -13c-10 0 -20 4 -28 12l-221 222v-816c0 -20 -20 -39 -40 -39s-39 19 -39 39v816l-222 -222c-8 -8 -17 -11 -27 -11s-20 4 -28 11c-8 8 -12 17 -12 27s4 20 12 28l290 286c8 8 17 13 27 13
+s20 -5 28 -13z" />
+    <glyph glyph-name="undecided" unicode="&#xe907;" 
+d="M512 802c273 0 495 -222 495 -495s-222 -495 -495 -495s-495 222 -495 495s222 495 495 495zM512 -123c239 0 430 191 430 430s-191 430 -430 430s-430 -191 -430 -430s191 -430 430 -430zM297 430c0 36 29 65 65 65s65 -29 65 -65s-29 -65 -65 -65s-65 29 -65 65z
+M597 430c0 36 29 65 65 65s65 -29 65 -65s-29 -65 -65 -65s-65 29 -65 65zM795 120c0 -20 -17 -35 -34 -35h-498c-17 0 -31 15 -31 35s14 33 31 33h502c17 0 30 -16 30 -33z" />
+    <glyph glyph-name="time" unicode="&#xe908;" 
+d="M512 802c273 0 495 -222 495 -495s-222 -495 -495 -495s-495 222 -495 495s222 495 495 495zM512 -120c236 0 427 191 427 427s-191 427 -427 427s-427 -191 -427 -427s191 -427 427 -427zM512 580c17 0 31 -12 31 -34v-239c0 -10 -4 -17 -11 -24l-208 -205
+c-7 -7 -16 -10 -24 -10s-17 3 -24 10s-10 16 -10 24s3 17 10 24l202 198v222c0 20 14 34 34 34z" />
+    <glyph glyph-name="sad" unicode="&#xe909;" 
+d="M771 20c-5 -3 -10 -4 -15 -4c-11 0 -24 6 -29 15c-46 77 -130 129 -218 129c-89 0 -174 -51 -215 -129c-4 -7 -17 -13 -29 -13c-7 0 -13 2 -19 6c-7 4 -13 15 -13 26c0 4 1 7 3 11c55 99 160 164 273 164c112 0 218 -65 276 -164c2 -3 4 -8 4 -13c0 -9 -5 -20 -18 -28z
+M512 802c273 0 495 -222 495 -495s-222 -495 -495 -495s-495 222 -495 495s222 495 495 495zM512 -123c239 0 430 193 430 430s-191 430 -430 430s-430 -191 -430 -430s191 -430 430 -430zM294 430c0 36 29 65 64 65c36 0 65 -29 65 -65s-29 -65 -65 -65
+c-35 0 -64 29 -64 65zM591 430c0 36 29 65 64 65c36 0 65 -29 65 -65s-29 -65 -65 -65c-35 0 -64 29 -64 65z" />
+    <glyph glyph-name="right_arrow" unicode="&#xe90a;" 
+d="M58 -205c-24 0 -41 17 -41 41c0 10 3 20 10 27l396 449l-396 439c-8 8 -11 16 -11 25c0 11 6 24 15 33c8 8 16 11 25 11c11 0 24 -6 33 -15l443 -493l-443 -503c-10 -10 -21 -14 -31 -14z" />
+    <glyph glyph-name="presentation" unicode="&#xe90b;" 
+d="M973 802c20 0 34 -14 37 -34v-662c0 -20 -14 -35 -34 -35h-375l222 -201c8 -7 17 -20 17 -33c0 -6 -2 -12 -7 -18s-14 -8 -23 -8c-12 0 -24 4 -32 11l-232 209v-190c0 -19 -11 -36 -32 -36c-17 0 -33 16 -33 36v190c-20 -19 -196 -174 -236 -210c-6 -5 -16 -9 -27 -9
+c-9 0 -18 2 -23 9c-4 5 -6 11 -6 17c0 11 5 23 16 32l222 198h-376c-20 0 -34 14 -34 34v666c0 20 14 34 34 34h922zM940 136v427h-858v-427h858zM82 631h858v106h-858v-106z" />
+    <glyph glyph-name="listen" unicode="&#xe90c;" 
+d="M1096 310c72 -51 116 -133 116 -218c0 -150 -119 -277 -273 -277c-17 0 -31 14 -31 31v485c0 17 14 31 31 31c31 0 61 -7 92 -17c0 227 -233 388 -416 388c-190 0 -393 -146 -417 -375c31 10 61 17 92 17c17 0 31 -13 31 -30v-485c0 -17 -14 -31 -31 -31
+c-89 0 -171 41 -222 113c-35 49 -52 104 -52 160c0 85 40 169 114 225c0 263 222 475 485 475c266 0 481 -222 481 -492zM256 -106v416c-89 -14 -160 -85 -174 -174c-2 -12 -3 -24 -3 -36c0 -99 73 -188 177 -206zM973 -123c89 17 160 85 174 177c2 12 3 24 3 36
+c0 100 -73 189 -177 207v-420z" />
+    <glyph glyph-name="left_arrow" unicode="&#xe90d;" 
+d="M481 -188c-10 0 -20 4 -30 14l-427 486l430 480c7 9 18 13 29 13c10 0 21 -3 29 -10c9 -7 13 -18 13 -29c0 -10 -3 -21 -10 -29l-385 -425l382 -435c7 -8 10 -18 10 -27c0 -10 -4 -21 -13 -28c-7 -7 -18 -10 -28 -10z" />
+    <glyph glyph-name="happy" unicode="&#xe90e;" 
+d="M512 802c273 0 495 -222 495 -495s-222 -495 -495 -495s-495 222 -495 495s222 495 495 495zM512 -123c239 0 430 191 430 430s-191 430 -430 430s-430 -191 -430 -430s191 -430 430 -430zM294 430c0 36 28 65 64 65s66 -29 66 -65s-30 -65 -66 -65s-64 29 -64 65z
+M591 430c0 36 28 65 64 65s66 -29 66 -65s-30 -65 -66 -65s-64 29 -64 65zM509 13h-4c-113 0 -218 65 -273 164c-2 4 -4 10 -4 16c0 11 5 24 17 29c5 2 9 3 14 3c12 0 25 -6 31 -17c44 -79 126 -130 215 -130c92 0 175 51 219 130c4 9 21 17 35 17c5 0 9 -1 13 -3
+c9 -6 14 -18 14 -29c0 -6 -1 -11 -4 -16c-58 -99 -160 -164 -273 -164z" />
+    <glyph glyph-name="hand" unicode="&#xe90f;" 
+d="M829 590c55 0 103 -47 103 -102v-439c0 -130 -106 -234 -236 -234h-191c-96 0 -174 72 -215 137c-75 119 -177 294 -177 294c-12 27 -17 50 -17 68c0 28 11 46 23 58c17 20 42 27 69 27c31 0 53 -26 71 -51l48 -68v321c0 31 10 61 34 85c18 18 42 28 67 28
+c13 0 26 -2 39 -8c0 51 48 96 103 96s102 -41 102 -96c10 3 23 7 37 7c55 0 103 -47 103 -102v-28c10 3 23 7 37 7zM860 49v439c0 20 -17 37 -37 37s-38 -17 -38 -37v-178c0 -18 -13 -34 -31 -34c-17 0 -30 17 -30 34v301c0 20 -18 37 -38 37s-45 -16 -45 -37v-243
+c0 -16 -15 -27 -29 -27c-17 0 -32 12 -32 27v332c0 20 -17 34 -37 37c-20 0 -38 -17 -38 -37v-332c0 -16 -13 -27 -27 -27c-17 0 -34 10 -34 27v243c0 17 -11 30 -28 37c-3 2 -6 3 -10 3c-9 0 -20 -6 -27 -13c-10 -10 -14 -27 -14 -41v-406c0 -14 -7 -24 -17 -31
+c-6 -4 -14 -6 -21 -6c-12 0 -24 5 -30 16l-96 140c-7 10 -13 21 -24 21c-15 0 -22 -8 -22 -21c0 -10 4 -23 12 -37c0 0 99 -171 178 -290c31 -48 92 -106 160 -106h191c96 0 164 76 164 172z" />
+    <glyph glyph-name="group_chat" unicode="&#xe910;" 
+d="M956 -137c2 -8 4 -17 4 -25s-2 -15 -8 -19c-5 -4 -9 -5 -14 -5c-9 0 -19 6 -30 15c-33 25 -65 48 -96 72c-10 -3 -24 -4 -34 -4c-130 0 -232 86 -232 192v6l55 14v-20c0 -75 78 -137 177 -137c15 0 27 4 39 4c7 0 15 -2 23 -7l44 -35l-10 38c0 14 7 24 17 31
+c38 24 65 63 65 107c0 76 -71 120 -161 135l38 51h3c102 -20 175 -97 175 -186c0 -58 -31 -110 -79 -141c8 -29 17 -57 24 -86zM416 802c218 0 393 -144 393 -318s-181 -317 -399 -317h-4c-24 0 -47 4 -71 7h-4l-181 -137c-3 -3 -10 -6 -13 -6c-10 0 -18 7 -18 17l55 170
+c0 3 -4 11 -7 14c-89 51 -150 147 -150 249c0 177 177 321 399 321zM416 235c181 0 332 112 332 249s-148 250 -332 250s-331 -113 -331 -250c0 -79 48 -153 120 -191c27 -14 41 -40 41 -71c-2 -14 -5 -27 -10 -38l54 38c14 10 31 17 48 17c20 0 68 -4 78 -4z" />
+    <glyph glyph-name="confused" unicode="&#xe911;" 
+d="M512 802c273 0 495 -222 495 -495s-222 -495 -495 -495s-495 222 -495 495s222 495 495 495zM512 -120c236 0 427 191 427 427s-191 427 -427 427s-427 -191 -427 -427s191 -427 427 -427zM294 430c0 36 28 65 64 65s66 -29 66 -65s-30 -65 -66 -65s-64 29 -64 65z
+M591 430c0 36 28 65 64 65s66 -29 66 -65s-30 -65 -66 -65s-64 29 -64 65zM632 48c-50 0 -106 30 -151 61c-25 17 -48 21 -75 21c-38 0 -75 -21 -102 -45c-7 -5 -16 -7 -24 -7s-16 2 -21 7c-5 7 -7 16 -7 24s2 16 7 21c41 38 92 61 147 61s105 -22 150 -55
+c20 -14 51 -27 79 -27c34 0 66 17 86 44c7 7 18 14 28 14c6 0 11 -2 16 -7c7 -7 11 -16 11 -25c0 -8 -3 -16 -8 -23c-36 -44 -79 -64 -136 -64z" />
+    <glyph glyph-name="close" unicode="&#xe912;" 
+d="M573 307l396 -396c8 -8 13 -20 13 -31s-5 -22 -13 -30s-20 -13 -31 -13s-22 5 -30 13l-396 396l-396 -396c-8 -8 -19 -13 -30 -13s-23 5 -31 13s-13 19 -13 30s5 23 13 31l396 396l-396 396c-7 8 -11 17 -11 27s4 20 11 28c10 10 22 15 34 15c9 0 18 -3 27 -9l396 -396
+l396 396c8 8 19 13 30 13s23 -5 31 -13s13 -19 13 -30s-5 -23 -13 -31z" />
+    <glyph glyph-name="clear_status" unicode="&#xe913;" 
+d="M92 -62h458l37 -68h-532c-20 0 -35 14 -35 34c0 223 203 307 448 307c50 0 94 0 143 -10l-44 -61c-31 0 -65 3 -99 3c-193 0 -356 -48 -376 -205zM469 276c-137 0 -251 116 -251 256c0 145 105 273 251 273c141 0 244 -130 244 -273c0 -138 -107 -256 -244 -256zM284 532
+c0 -116 83 -198 185 -198s186 82 186 198c0 98 -76 208 -186 208c-109 0 -185 -100 -185 -208zM829 24l41 -41c6 -6 9 -14 9 -23c0 -8 -2 -15 -9 -22c-6 -6 -15 -9 -22 -9c-9 0 -17 4 -22 9l-41 41l-34 -34c-7 -7 -16 -11 -24 -11s-17 4 -24 11c-6 6 -8 12 -8 19
+c0 10 5 19 12 26l34 34l-34 34c-6 7 -9 15 -9 23s3 16 9 21s15 8 23 8s16 -3 21 -8l34 -34l38 38c5 5 14 8 23 8c8 0 17 -3 21 -8c5 -6 7 -15 7 -23s-2 -17 -7 -22zM788 -188c-116 0 -211 96 -211 212s95 211 211 211s212 -95 212 -211s-96 -212 -212 -212zM788 170
+c-82 0 -150 -68 -150 -150s68 -150 150 -150s151 68 151 150c0 74 -52 132 -119 147c-10 2 -21 3 -32 3z" />
+    <glyph glyph-name="circle" unicode="&#xe914;" 
+d="M512 -185c-270 0 -492 222 -492 492s222 491 492 491s491 -221 491 -491s-221 -492 -491 -492zM512 737c-236 0 -431 -194 -431 -430s195 -431 431 -431s430 195 430 431s-194 430 -430 430z" />
+    <glyph glyph-name="substract" unicode="&#xe915;" 
+d="M727 341c22 0 33 -16 33 -32s-12 -33 -36 -33h-420c-24 0 -36 16 -36 32s12 33 36 33h423zM512 -185c-270 0 -492 222 -492 492s222 491 492 491s491 -221 491 -491s-221 -492 -491 -492zM512 737c-236 0 -431 -194 -431 -430s195 -431 431 -431s430 195 430 431
+s-194 430 -430 430z" />
+    <glyph glyph-name="circle_close" unicode="&#xe916;" 
+d="M556 312l133 -131c7 -7 9 -14 9 -21c0 -17 -16 -33 -33 -33c-7 0 -15 2 -22 9l-133 130l-121 -130c-7 -7 -15 -10 -22 -10c-17 0 -31 16 -31 33c0 7 2 15 9 22l119 131l-119 123c-5 5 -7 12 -7 18c0 17 17 34 34 34c6 0 12 -3 17 -8l121 -124l123 132c5 5 11 8 17 8
+c16 0 33 -18 33 -35c0 -6 -2 -12 -7 -17zM512 -185c-270 0 -492 222 -492 492s222 491 492 491s491 -221 491 -491s-221 -492 -491 -492zM512 737c-236 0 -431 -194 -431 -430s195 -431 431 -431s430 195 430 431s-194 430 -430 430z" />
+    <glyph glyph-name="add" unicode="&#xe917;" 
+d="M727 334c19 0 29 -16 29 -32s-10 -33 -29 -33h-191v-174c0 -22 -17 -33 -33 -33s-32 11 -32 33v174h-167c-23 0 -34 16 -34 32s12 33 34 33h167v185c0 23 16 35 32 35s33 -12 33 -35v-185h191zM512 -185c-270 0 -492 222 -492 492s222 491 492 491s491 -221 491 -491
+s-221 -492 -491 -492zM512 737c-236 0 -431 -194 -431 -430s195 -431 431 -431s430 195 430 431s-194 430 -430 430z" />
+    <glyph glyph-name="check" unicode="&#xe918;" 
+d="M689 481c6 7 14 10 22 10c18 0 37 -17 37 -34c0 -6 -2 -12 -7 -17l-267 -300c-5 -8 -14 -11 -23 -11c-7 0 -15 2 -21 7l-136 120c-10 9 -15 19 -15 28c0 16 14 30 31 30c8 0 17 -3 25 -10l112 -99zM512 -185c-270 0 -492 222 -492 492s222 492 492 492s492 -222 492 -492
+s-222 -492 -492 -492zM512 737c-236 0 -430 -194 -430 -430s194 -430 430 -430s430 194 430 430s-194 430 -430 430z" />
+    <glyph glyph-name="chat" unicode="&#xe919;" 
+d="M512 737c-246 0 -444 -154 -444 -345c0 -102 62 -197 164 -262c22 -15 42 -41 42 -70c0 -3 -1 -6 -1 -9c-1 -7 -3 -17 -3 -17l-24 -75l116 89c14 10 34 17 51 17c31 0 61 -11 92 -11h7c246 0 444 154 444 342s-198 341 -444 341zM512 805c283 0 512 -191 512 -416
+s-229 -410 -512 -410h-7c-31 0 -61 4 -92 11c-77 -59 -158 -117 -236 -175c-3 -3 -10 -6 -17 -6c-14 0 -23 10 -23 24l68 218c3 9 -6 21 -10 24c-118 77 -195 191 -195 321c0 225 229 409 512 409z" />
+    <glyph glyph-name="audio_on" unicode="&#xe91a;" 
+d="M539 -140l-290 290h-140c-51 0 -92 41 -92 92v130c0 51 41 92 92 92h140l290 290c5 5 12 8 19 8c15 0 29 -12 29 -28v-857c0 -13 -14 -25 -29 -25c-6 0 -13 2 -19 8zM72 375v-129c0 -21 13 -41 34 -41h153c8 0 16 -2 21 -7l252 -253v727l-252 -252c-6 -6 -14 -7 -21 -7
+h-150c-20 0 -37 -18 -37 -38z" />
+    <glyph glyph-name="audio_off" unicode="&#xe91b;" 
+d="M898 307l102 -102c4 -4 7 -11 7 -18s-3 -14 -7 -18c-6 -6 -13 -9 -20 -9c-6 0 -12 2 -17 7l-103 102l-106 -105c-4 -4 -10 -6 -16 -6c-8 0 -15 3 -21 9c-4 4 -6 10 -6 16c0 8 3 16 9 22l103 102l-103 102c-5 5 -8 12 -8 19s3 14 8 19s12 7 19 7s14 -2 19 -7l102 -102
+l103 102c4 4 11 7 17 7s14 -3 18 -7c5 -5 8 -14 8 -22c0 -6 -2 -12 -6 -16zM539 -140l-290 290h-140c-51 0 -92 41 -92 92v130c0 51 41 92 92 92h140l290 290c6 6 13 9 20 9c13 0 24 -11 24 -29v-857c0 -16 -12 -25 -25 -25c-7 0 -14 3 -19 8zM109 413
+c-20 0 -37 -14 -37 -34v-130c0 -26 13 -41 34 -41h153c7 0 16 -2 21 -7l252 -252v723l-252 -252c-6 -6 -14 -7 -21 -7h-150z" />
+    <glyph glyph-name="linte_tool" unicode="&#xe91c;" 
+d="M403 14l-58 29l269 538l58 -29zM703 802c60 0 109 -48 109 -109s-48 -110 -109 -110s-109 49 -109 110s49 109 109 109zM703 648c26 0 48 21 48 45s-21 44 -48 44c-24 0 -44 -20 -44 -44s20 -45 44 -45zM321 31c58 0 109 -49 109 -110s-48 -109 -109 -109
+s-109 48 -109 109s48 110 109 110zM321 -123c24 0 44 20 44 44c0 25 -20 45 -44 45c-27 0 -48 -21 -48 -45s21 -44 48 -44z" />
+    <glyph glyph-name="circle_tool" unicode="&#xe91d;" 
+d="M628 -28c99 34 178 110 212 209l61 -24c-44 -116 -136 -205 -252 -246zM113 444c41 116 132 212 245 256l24 -62c-99 -38 -176 -119 -210 -218zM847 420c-34 106 -117 184 -216 222l21 61c119 -44 215 -140 256 -263zM177 181c38 -96 109 -171 205 -205l-24 -62
+c-113 41 -201 130 -242 243zM505 801c60 0 110 -47 110 -108c0 -58 -48 -106 -106 -106c-61 0 -110 48 -110 106c0 61 47 108 106 108zM505 652c24 0 45 17 45 44c0 24 -21 44 -45 44s-45 -20 -45 -44s21 -44 45 -44zM505 27c60 0 110 -48 110 -109
+c0 -58 -48 -106 -106 -106c-61 0 -110 48 -110 106c0 61 47 109 106 109zM505 -123c24 0 45 17 45 44c0 24 -21 45 -45 45s-45 -21 -45 -45s21 -44 45 -44zM898 409c58 0 105 -47 105 -105c0 -59 -47 -106 -105 -106s-106 48 -106 106s48 105 106 105zM898 259h4
+c22 0 40 22 40 45c0 24 -20 44 -44 44s-45 -20 -45 -44s21 -45 45 -45zM232 300c0 -58 -47 -106 -106 -106c-58 0 -106 48 -106 106s48 106 106 106s106 -48 106 -106zM81 300c0 -24 21 -41 45 -44c24 0 45 20 45 44s-21 45 -45 45s-45 -21 -45 -45z" />
+    <glyph glyph-name="triangle_tool" unicode="&#xe91e;" 
+d="M210 24l-58 29l269 537l58 -29zM246 -113v65h529v-65h-529zM812 30l-266 531l58 29l266 -531zM512 583c-61 0 -109 49 -109 110c0 60 48 109 109 109s109 -48 109 -109s-48 -110 -109 -110zM512 737c-24 0 -44 -20 -44 -44c0 -25 20 -45 44 -45s44 21 44 45
+s-20 44 -44 44zM898 31c60 0 109 -49 109 -110s-48 -109 -109 -109s-110 48 -110 109s49 110 110 110zM898 -123c24 0 44 20 44 44c0 25 -20 45 -44 45s-45 -21 -45 -45s21 -44 45 -44zM126 31c61 0 110 -49 110 -110s-49 -109 -110 -109s-109 48 -109 109s49 110 109 110z
+M126 -123c23 0 45 20 45 44c0 26 -23 48 -48 48c-24 0 -45 -23 -45 -48s23 -44 48 -44z" />
+    <glyph glyph-name="rectangle_tool" unicode="&#xe91f;" 
+d="M864 68v481h64v-481h-64zM290 655v65h444v-65h-444zM99 68v481h65v-481h-65zM290 -109v64h444v-64h-444zM130 802c61 0 112 -52 112 -113s-51 -112 -112 -112s-113 51 -113 112s52 113 113 113zM130 642c27 0 47 20 47 47s-20 48 -47 48s-48 -21 -48 -48s21 -47 48 -47z
+M894 37c61 0 113 -51 113 -112s-52 -113 -113 -113s-112 52 -112 113s51 112 112 112zM894 -123c27 0 48 21 48 48s-21 47 -48 47s-47 -20 -47 -47s20 -48 47 -48zM130 37c61 0 112 -51 112 -112s-51 -113 -112 -113s-113 52 -113 113s52 112 113 112zM130 -123
+c27 0 47 21 47 48s-20 47 -47 47s-48 -20 -48 -47s21 -48 48 -48zM894 802c61 0 113 -52 113 -113s-52 -112 -113 -112s-112 51 -112 112s51 113 112 113zM894 642c28 0 48 20 48 47s-21 48 -48 48s-47 -21 -47 -48s20 -47 47 -47z" />
+    <glyph glyph-name="text_tool" unicode="&#xe920;" 
+d="M935 801v-255h-27c-17 82 -41 133 -68 157s-86 37 -171 37h-82v-764c0 -58 10 -92 27 -106c38 -17 79 -28 120 -28v-27h-434v27c65 0 103 15 120 32c17 14 24 54 24 119v747h-86c-82 0 -139 -10 -170 -34s-54 -75 -68 -157h-38l7 252h846z" />
+    <glyph glyph-name="plus" unicode="&#xe921;" 
+d="M962 345c20 0 40 -19 40 -42c0 -20 -19 -37 -39 -37h-420v-410c0 -20 -18 -37 -38 -37s-37 17 -37 37v413h-413c-20 0 -38 18 -38 38s18 38 38 38h416v413c0 20 18 37 38 37s37 -17 37 -37v-413h416z" />
+    <glyph glyph-name="fit_to_width" unicode="&#xe922;" 
+d="M993 331c7 -7 11 -15 11 -23s-4 -16 -11 -21l-129 -123c-6 -4 -13 -6 -19 -6c-9 0 -18 4 -26 12c-5 5 -7 12 -7 19s2 14 7 19l75 68h-764l68 -65c8 -6 13 -16 13 -26c0 -6 -2 -12 -6 -18c-6 -8 -16 -13 -26 -13c-7 0 -13 2 -19 6c-3 3 -129 123 -129 123
+c-7 7 -11 15 -11 23s4 16 11 21l129 123c6 4 13 6 19 6c9 0 18 -4 26 -12c5 -5 7 -12 7 -19s-2 -14 -7 -19l-75 -69h764l-68 66c-8 6 -13 16 -13 26c0 6 2 12 6 18c6 8 16 13 26 13c7 0 13 -2 19 -6c3 -3 129 -123 129 -123z" />
+    <glyph glyph-name="applause" unicode="&#xe923;" 
+d="M1004 368c-7 -20 -21 -33 -38 -47c20 -13 29 -35 29 -58c0 -32 -17 -65 -46 -82l-17 -11c16 -16 25 -39 25 -62c0 -30 -15 -61 -46 -77l-324 -164c-34 -17 -75 -28 -113 -28c-82 0 -160 48 -204 116c-38 52 -61 120 -61 187c0 62 20 122 67 168c79 75 144 229 144 229
+c11 23 41 51 60 54c5 1 9 1 14 1c10 0 19 -2 29 -9c-5 5 -7 10 -7 16s2 13 6 20l28 51c3 6 4 11 4 17c0 11 -5 22 -15 28c-4 3 -10 4 -15 4c-10 0 -20 -5 -26 -15l-140 -235c-6 -11 -15 -15 -23 -15c-14 0 -28 13 -28 28c0 5 1 9 4 14l102 171c4 6 5 12 5 17
+c0 16 -15 27 -31 27c-12 0 -25 -6 -32 -20l-171 -290c-7 -10 -20 -15 -33 -15c-18 0 -35 10 -35 28v123c0 22 -14 44 -26 44h-1c-12 -2 -18 -9 -18 -24c0 -3 0 -6 1 -10c2 -14 15 -89 15 -172c0 -40 -3 -83 -12 -121c-3 -14 -5 -28 -5 -41c0 -68 43 -128 128 -174
+c10 -5 14 -14 14 -23c0 -15 -12 -31 -28 -31c-4 0 -9 1 -13 3c-92 50 -156 131 -156 231c0 16 2 31 5 48c7 38 10 77 10 116c0 52 -5 103 -13 154v8c0 24 6 91 65 91c21 0 41 -3 55 -17c20 -20 34 -48 34 -75v-48l133 225c18 27 53 49 88 49c22 0 44 -9 62 -32
+c16 22 43 34 70 34c14 0 27 -3 39 -10c27 -17 41 -44 41 -73c0 -12 -2 -24 -7 -36c10 0 21 -3 31 -10c27 -18 41 -46 41 -76c0 -15 -3 -30 -10 -44c-11 -21 -13 -27 -22 -46l117 60c16 9 32 13 47 13c45 0 81 -36 86 -78c11 4 22 6 32 6c48 0 89 -40 89 -88
+c0 -8 -2 -16 -4 -24zM543 454l-17 -34l99 51c-4 -1 -7 -2 -11 -2c-16 0 -31 14 -31 30c0 4 1 9 4 13l24 37c2 4 3 8 3 13c0 10 -5 20 -13 28c-5 5 -11 7 -17 7s-12 -2 -17 -7c-7 -7 -16 -13 -26 -13c-4 0 -8 1 -12 3c10 -7 21 -17 24 -31c4 -12 6 -24 6 -37
+c0 -21 -5 -41 -16 -58zM898 290l-178 -92c-4 -2 -8 -3 -12 -3c-15 0 -28 15 -28 30c0 9 5 18 16 24l243 123c11 6 16 16 16 25c0 16 -14 32 -31 32c-4 0 -8 -1 -13 -3l-242 -126c-5 -2 -10 -3 -14 -3c-17 0 -29 15 -29 30c0 9 5 18 16 24l177 89c12 6 18 16 18 25
+c0 15 -14 29 -32 29c-6 0 -13 -2 -20 -6l-300 -154c-4 -2 -8 -3 -12 -3c-18 0 -36 18 -36 36c0 4 1 8 3 12c0 0 39 60 55 102c4 12 9 28 9 40c0 7 -2 12 -6 15c-2 2 -5 2 -7 2c-6 0 -11 -6 -20 -23c-4 -7 -68 -164 -157 -249c-35 -34 -50 -79 -50 -127
+c0 -54 19 -111 50 -156c18 -24 75 -91 160 -91c26 0 55 6 86 22l324 168c11 6 16 15 16 25c0 16 -12 33 -29 33c-4 0 -9 -1 -14 -4l-130 -68c-5 -2 -10 -3 -14 -3c-17 0 -29 15 -29 30c0 9 5 18 16 24l222 113c12 6 16 15 16 25c0 17 -14 36 -30 36c-3 0 -7 -1 -10 -3z" />
+    <glyph glyph-name="undo" unicode="&#xe924;" 
+d="M519 631c223 0 406 -181 406 -404v-5c0 -226 -184 -410 -410 -410c-27 0 -47 10 -47 30c0 25 34 35 51 35c191 0 345 154 345 345s-154 344 -345 344h-307l119 -119c5 -5 7 -13 7 -21c0 -7 -2 -15 -7 -20s-13 -8 -21 -8c-7 0 -15 3 -20 8l-194 195l194 194c5 5 13 8 21 8
+c7 0 15 -3 20 -8s8 -13 8 -20c0 -8 -3 -16 -8 -21l-119 -123h307z" />
+    <glyph glyph-name="pen_tool" unicode="&#xe925;" 
+d="M966 761c27 -27 40 -61 40 -98c0 -47 -22 -99 -64 -141l-601 -594c-3 -3 -6 -6 -10 -7l-266 -109c-3 -1 -6 -1 -9 -1c-9 0 -18 3 -25 8c-8 8 -12 15 -12 25c0 3 0 6 1 9l96 280c2 7 4 11 7 14l601 590c42 42 94 64 142 64c38 0 73 -13 100 -40zM198 130l126 -127l523 516
+l-127 126zM164 75l-62 -174l171 68zM922 717c-16 16 -36 24 -57 24c-32 0 -67 -19 -97 -52l130 -123c30 30 47 65 47 96c0 21 -8 40 -23 55z" />
+    <glyph glyph-name="lock" unicode="&#xe926;" 
+d="M870 385c31 0 59 -24 59 -61v-450c0 -34 -28 -59 -62 -59h-713c-31 0 -62 25 -62 59v453c0 34 28 58 62 58h51v130c0 157 136 286 307 286s307 -129 307 -286v-130h51zM273 515v-130h478v130c0 130 -113 225 -239 225s-239 -99 -239 -225zM864 -124v445h-704v-445h704z
+" />
+    <glyph glyph-name="polling" unicode="&#xe927;" 
+d="M251 645h722c22 0 34 -18 34 -36s-12 -36 -34 -36h-722c-22 0 -34 18 -34 36s12 36 34 36zM251 135h231c22 0 34 -18 34 -36s-12 -36 -34 -36h-231c-22 0 -34 18 -34 36s12 36 34 36zM251 385h484c22 0 34 -18 34 -36s-12 -36 -34 -36h-484c-22 0 -34 18 -34 36
+s12 36 34 36zM12 609c0 40 30 72 68 72s69 -32 69 -72s-31 -72 -69 -72s-68 32 -68 72zM15 349c0 38 29 69 65 69s65 -31 65 -69s-29 -68 -65 -68s-65 30 -65 68zM12 97c0 40 30 72 68 72s69 -32 69 -72s-31 -72 -69 -72s-68 32 -68 72z" />
+    <glyph glyph-name="desktop" unicode="&#xe928;" 
+d="M925 751c48 0 85 -38 85 -82v-598c0 -44 -38 -81 -82 -81h-269v-72h89c14 0 27 -13 27 -27s-10 -28 -27 -28h-468c-17 0 -27 14 -27 28s10 27 27 27h89v72h-270c-44 0 -82 37 -82 81v598c0 44 38 82 82 82h826zM601 -79v72h-177v-72h177zM952 75v594c0 14 -10 24 -24 24
+h-829c-14 0 -24 -10 -24 -24v-594c0 -14 10 -24 24 -24h826c14 0 27 10 27 24z" />
+    <glyph glyph-name="fit_to_screen" unicode="&#xe929;" 
+d="M594 -34c5 5 11 8 18 8s14 -3 19 -8c8 -8 13 -18 13 -27c0 -6 -2 -12 -6 -18l-102 -102c-5 -7 -12 -11 -20 -11s-17 4 -24 11l-106 109c-5 5 -7 12 -7 18c0 10 5 20 14 26c6 4 12 6 18 6c9 0 18 -4 26 -12l48 -48v246c0 17 13 27 30 27s31 -10 31 -27v-246zM631 645
+c-5 -5 -12 -7 -19 -7s-13 2 -18 7l-48 48v-246c0 -17 -14 -27 -31 -27s-30 10 -30 27v246l-48 -48c-8 -8 -17 -12 -27 -12c-6 0 -12 1 -17 5c-9 6 -14 17 -14 27c0 6 2 12 7 17l106 110c7 7 15 10 22 10c8 0 16 -4 22 -10l102 -103c4 -6 6 -11 6 -17c0 -9 -5 -19 -13 -27z
+M847 188c-5 5 -7 11 -7 18s2 14 7 19l47 48h-245c-17 0 -28 14 -28 31s11 30 28 30h245l-47 48c-8 8 -13 18 -13 27c0 6 2 12 6 17c6 9 17 13 27 13c6 0 12 -2 17 -6l109 -106c7 -7 10 -15 10 -22c0 -8 -3 -15 -10 -22l-102 -102c-4 -4 -10 -6 -16 -6c-9 0 -20 5 -28 13z
+M177 426c5 -5 7 -11 7 -18s-2 -14 -7 -19l-47 -48h245c17 0 28 -14 28 -31s-11 -30 -28 -30h-245l47 -48c8 -8 13 -18 13 -27c0 -6 -2 -12 -6 -17c-6 -9 -17 -13 -27 -13c-6 0 -12 2 -17 6c-4 3 -109 106 -109 106c-7 7 -10 14 -10 21c0 8 4 17 10 23l102 102c5 5 10 7 16 7
+c9 0 19 -5 28 -14z" />
+    <glyph glyph-name="fullscreen" unicode="&#xe92a;" 
+d="M79 -75c0 0 266 263 269 266c6 5 14 8 21 8c9 0 18 -4 24 -11c5 -6 7 -14 7 -21c0 -8 -3 -16 -11 -24l-266 -266h126c21 0 35 -8 35 -31c0 -17 -12 -31 -35 -31h-201c-17 0 -31 14 -31 31v202c0 17 18 27 32 27s30 -10 30 -27v-123zM126 740l263 -262c6 -6 9 -13 9 -20
+c0 -8 -4 -15 -9 -21c-8 -9 -17 -13 -26 -13c-6 0 -13 2 -18 6l-266 266v-126c0 -17 -15 -30 -32 -30c-14 0 -30 14 -30 30v201c0 17 14 31 31 31h201c18 0 28 -16 28 -30c0 -17 -11 -32 -28 -32h-123zM973 71c17 0 34 -11 34 -27v-201c0 -17 -14 -31 -31 -31h-201
+c-19 0 -29 18 -29 32c0 13 10 30 29 30h123l-273 273c-7 6 -10 14 -10 22c0 9 4 18 12 24c6 5 13 7 19 7c9 0 17 -4 25 -12l271 -270v123c0 17 14 30 31 30zM635 478l263 262h-123c-20 0 -29 15 -29 32c0 14 10 30 29 30h201c17 0 31 -14 31 -31v-201c0 -17 -13 -28 -32 -28
+c-16 0 -30 11 -30 28v126l-263 -263c-6 -6 -13 -8 -20 -8c-10 0 -21 4 -27 12c-6 7 -9 14 -9 21c0 6 2 13 9 20z" />
+    <glyph glyph-name="settings" unicode="&#xe92b;" 
+d="M1004 351v-88c0 -14 -18 -24 -28 -28l-126 -44l-17 -44l58 -120c2 -5 4 -10 4 -15c0 -7 -3 -14 -8 -19l-64 -65c-5 -5 -11 -7 -18 -7c-6 0 -12 1 -17 4l-119 58l-44 -17l-45 -127c-3 -10 -13 -20 -27 -20h-89c-13 0 -24 10 -27 20l-44 127l-45 17l-119 -58
+c-6 -3 -12 -5 -17 -5c-7 0 -12 3 -17 8l-65 65c-5 5 -7 11 -7 18c0 5 1 11 3 16l58 120l-17 44l-126 44c-11 4 -21 14 -21 28v88c0 14 11 24 21 28l126 44l17 44l-58 120c-2 5 -3 10 -3 15c0 8 3 15 7 19l65 68c4 5 11 7 18 7c6 0 12 -1 16 -3l123 -62l44 17l44 127
+c4 10 14 20 28 20h92c13 0 24 -10 27 -20l44 -127l45 -17l119 58c6 3 12 5 17 5c7 0 13 -3 17 -8l65 -65c5 -5 7 -12 7 -19c0 -5 -1 -10 -3 -15l-58 -120l17 -44l126 -44c10 -4 21 -13 21 -26v-2zM945 287v37l-122 44c-11 4 -17 11 -21 21l-24 61c-4 10 -4 21 0 31l55 116
+l-27 27l-117 -54c-10 -5 -19 -4 -30 0l-62 24c-9 4 -17 10 -20 20l-45 123h-40l-45 -123c-3 -10 -9 -17 -17 -20l-61 -24c-12 -5 -21 -5 -31 0l-116 54l-27 -27l54 -109c5 -10 4 -20 0 -31l-24 -61c-3 -10 -10 -17 -20 -21l-123 -44v-41l123 -44c8 -3 13 -10 17 -21l24 -61
+c4 -10 5 -20 0 -31l-55 -116l27 -27l117 54c9 5 20 4 30 0l62 -24c10 -4 17 -10 20 -20l41 -126h41l44 122c4 11 10 17 21 21l61 24c10 4 21 4 31 0l116 -55l27 27l-54 117c-5 10 -4 20 0 30l24 62c4 10 10 16 20 20zM512 536c126 0 229 -103 229 -229s-103 -229 -229 -229
+s-229 103 -229 229s103 229 229 229zM512 140c92 0 167 75 167 167c0 89 -71 164 -164 164c-92 0 -167 -72 -167 -164s72 -167 164 -167z" />
+    <glyph glyph-name="thumbs_down" unicode="&#xe92c;" 
+d="M860 628c20 -48 30 -102 30 -157c0 -104 -35 -208 -98 -266l-7 -7c-7 -7 -23 -27 -61 -68c-27 -27 -73 -150 -93 -222c-7 -55 -57 -93 -112 -93c-54 0 -82 60 -82 113c0 79 24 161 48 236h-209c-31 0 -61 10 -85 34c-18 18 -28 42 -28 67c0 13 2 26 8 39c3 7 7 13 10 20
+c-27 17 -48 51 -48 85s17 66 48 86c-17 17 -24 37 -24 61c0 34 17 65 48 82c-14 17 -24 42 -24 62c0 55 47 101 102 101h321c113 0 215 -67 256 -173zM802 604c-31 85 -112 136 -201 136h-318c-20 0 -41 -16 -41 -40c0 -20 17 -42 41 -42c17 0 31 -13 31 -30
+s-14 -31 -31 -31h-27c-20 0 -41 -17 -41 -41s20 -45 44 -45c17 0 24 -13 24 -30s-13 -31 -30 -31h-21c-20 0 -41 -17 -41 -41c0 -20 21 -41 45 -41h30c17 0 31 -13 31 -30s-14 -31 -31 -31s-35 -14 -41 -31c-1 -3 -2 -7 -2 -11c0 -11 5 -23 13 -30c12 -11 27 -13 44 -13h246
+c7 0 18 -2 24 -7s8 -13 8 -21c0 -9 -2 -20 -5 -27c-27 -79 -55 -165 -55 -246c0 -25 5 -42 31 -47c4 -1 8 -1 12 -1c15 0 31 7 39 48c6 31 62 198 103 246c38 41 60 68 68 75c51 51 78 137 78 223c0 49 -9 97 -27 139z" />
+    <glyph glyph-name="thumbs_up" unicode="&#xe92d;" 
+d="M867 58c0 -34 -17 -65 -44 -89c14 -14 23 -38 23 -58c0 -55 -47 -102 -102 -102h-317c-116 0 -219 68 -260 174c-19 47 -28 98 -28 149c0 106 37 212 97 281l64 75c26 29 76 149 93 222c13 56 50 93 99 93c4 0 9 0 13 -1c52 -6 87 -55 87 -104c0 -4 -1 -8 -1 -12
+c-8 -78 -24 -161 -48 -236h208c31 0 62 -9 85 -34c19 -21 29 -45 29 -68c0 -21 -8 -41 -22 -58c31 -16 48 -51 48 -86c0 -32 -14 -65 -45 -85c14 -17 21 -37 21 -61zM741 -130c16 0 37 20 37 44c0 21 -12 45 -37 45c-17 0 -31 14 -31 31s14 30 31 30h27c20 0 41 17 41 41
+c0 20 -17 41 -41 41c-17 0 -31 14 -31 31s14 30 31 30h20c20 0 41 22 41 42s-17 41 -41 41h-27c-17 0 -31 13 -31 30s14 31 31 31s34 9 38 27c1 4 1 8 1 12c0 33 -29 46 -56 46h-246c-7 0 -17 0 -24 7c-8 6 -12 15 -12 25c0 8 3 17 9 23c27 79 55 161 55 246
+c0 21 -3 41 -31 47c-2 0 -5 1 -8 1c-13 0 -33 -7 -43 -48c-4 -15 -60 -199 -103 -246l-68 -75c-48 -53 -77 -141 -77 -230c0 -47 8 -94 26 -135c31 -85 112 -137 201 -137h318z" />
+    <glyph glyph-name="file" unicode="&#xe92e;" 
+d="M867 577c14 -17 23 -38 23 -58v-625c0 -44 -37 -82 -81 -82h-594c-44 0 -82 38 -82 82v826c0 44 38 81 82 81h427zM658 700v-110c0 -10 7 -21 21 -21h109zM809 -127c14 0 20 8 20 21v614h-150c-44 0 -82 38 -82 82v150h-382c-10 0 -21 -10 -21 -20v-826
+c0 -10 7 -21 21 -21h594z" />
+    <glyph glyph-name="upload" unicode="&#xe92f;" 
+d="M635 112c0 14 10 25 24 25h160c75 0 144 54 144 129c0 38 -11 79 -38 106s-64 44 -102 44h-41v45c0 116 -96 211 -215 211c-82 0 -154 -47 -192 -119l-17 -38c-23 18 -45 31 -75 31c-44 0 -81 -35 -88 -79l-4 -20l-20 -7c-58 -20 -100 -68 -110 -130c-1 -6 -1 -11 -1 -17
+c0 -36 15 -76 42 -105c31 -34 72 -51 116 -51h147c14 0 24 -11 24 -25s-10 -23 -24 -23h-147c-113 0 -201 88 -201 201c0 85 54 160 133 191c14 65 68 109 133 109c20 0 38 -3 55 -10c46 89 138 141 232 141c39 0 79 -9 116 -28c85 -44 144 -133 144 -232
+c102 0 174 -93 174 -195c0 -96 -85 -177 -181 -177h-164c-14 0 -24 9 -24 23zM679 242c4 -4 5 -8 5 -12c0 -8 -5 -16 -12 -22c-5 -4 -11 -6 -17 -6s-13 2 -17 6l-105 106v-396c0 -14 -10 -24 -24 -24s-24 10 -24 24v396l-106 -106c-5 -5 -11 -7 -17 -7s-12 2 -17 7
+s-7 11 -7 17s2 12 7 17l150 150c3 3 10 7 17 7s14 -4 17 -7z" />
+    <glyph glyph-name="video" unicode="&#xe930;" 
+d="M48 13c-17 0 -31 14 -31 31v526c0 17 14 31 31 31h624c17 0 31 -14 31 -31v-526c0 -17 -14 -31 -31 -31h-624zM82 75h560v464h-560v-464zM963 78l-236 106c-10 5 -20 17 -20 31v167c0 14 6 21 20 27l236 106c4 2 9 3 13 3c16 0 31 -14 31 -34v-378c0 -18 -15 -31 -31 -31
+c-4 0 -9 1 -13 3zM945 153v280l-174 -78v-123z" />
+    <glyph glyph-name="unmute" unicode="&#xe931;" 
+d="M410 710c-27 -27 -42 -65 -42 -103v-336c0 -37 15 -74 42 -101c28 -28 65 -41 102 -41c38 0 75 14 102 41s41 63 41 101v336c0 40 -14 76 -41 103c-28 28 -65 41 -102 41s-74 -13 -102 -41zM662 758c41 -41 61 -96 61 -151v-336c0 -116 -95 -213 -211 -213
+s-212 97 -212 213v336c0 58 24 110 62 151c40 40 95 61 150 61s110 -21 150 -61zM758 -137c20 0 37 -14 37 -34s-14 -34 -34 -34h-495c-20 0 -34 14 -34 34s14 34 34 34h212v38c-191 0 -338 171 -338 362c0 20 14 34 34 34s34 -14 34 -34c0 -164 133 -297 297 -297h14
+c164 0 297 133 297 297c0 20 14 34 34 34s34 -14 34 -34c0 -191 -147 -362 -338 -362v-38h212z" />
+    <glyph glyph-name="mute" unicode="&#xe932;" 
+d="M364 120l-4 3l-67 -67c56 -56 131 -88 212 -88h14c166 0 297 135 297 297v17c3 16 18 26 34 26c3 0 6 0 8 -1c18 -4 25 -17 25 -42c0 -191 -145 -364 -336 -364v-39h212c14 0 28 -18 28 -34c0 -18 -11 -33 -28 -33h-494c-16 0 -28 19 -28 33c0 21 13 38 31 38h212v38
+c-88 0 -233 106 -233 106l-137 -135c-8 -8 -18 -12 -26 -12c-17 0 -31 14 -31 33c0 11 5 24 18 37l130 130c-39 60 -60 131 -60 202c0 8 14 20 25 24c3 1 5 1 8 1c16 0 34 -10 34 -25c0 -53 15 -106 43 -152l70 67c-14 28 -21 56 -21 88v339c0 56 22 109 64 148
+c39 42 92 64 148 64s108 -23 145 -64c46 -51 63 -92 63 -148v-25l180 181c10 10 21 14 31 14c19 0 34 -15 34 -33c0 -10 -4 -20 -15 -31l-226 -226v-219c0 -117 -95 -212 -212 -212c-56 0 -109 25 -148 64zM614 169c28 28 39 75 39 103v148l-247 -247l4 -4
+c28 -28 63 -42 102 -42s77 14 102 42zM371 272c0 -18 7 -43 7 -43l282 283v92c0 39 -14 77 -42 102c-28 28 -63 42 -102 42s-78 -14 -103 -42c-28 -25 -42 -60 -42 -99v-335z" />
+    <glyph glyph-name="application" unicode="&#xe901;" 
+d="M952 679c31 0 55 -24 55 -55v-634c0 -31 -24 -55 -55 -55h-876c-34 0 -58 24 -58 55v634c3 31 27 55 58 55h876zM946 618h-863v-82h863v82zM83 0h863v471h-863v-471zM246 577c0 13 11 24 24 24s24 -11 24 -24s-11 -24 -24 -24s-24 11 -24 24zM148 577c0 13 11 24 24 24
+s24 -11 24 -24s-11 -24 -24 -24s-24 11 -24 24zM342 577c0 13 11 24 24 24s24 -11 24 -24s-11 -24 -24 -24s-24 11 -24 24z" />
+  </font>
+</defs></svg>
diff --git a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.ttf b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.ttf
index b9475eca5169ad10efcdafe8b0201b8b96ac90c2..cbe2b6fe99717ef5641cc1df67a4948e71507d19 100755
Binary files a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.ttf and b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.ttf differ
diff --git a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.woff b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.woff
index 425547db96b29ca343595118b6edd14d96b976d0..a57fc494d077b9e081b72e5288455e32604e5d56 100755
Binary files a/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.woff and b/bigbluebutton-html5/public/fonts/BbbIcons/bbb-icons.woff differ
diff --git a/bigbluebutton-html5/server/main.js b/bigbluebutton-html5/server/main.js
index dc6b1b509584944c34bcdb4ddee53f4ab834737a..12c0c3fc47b39d87426323c594e1c5faa03a1cd8 100755
--- a/bigbluebutton-html5/server/main.js
+++ b/bigbluebutton-html5/server/main.js
@@ -1,49 +1,19 @@
 import '/imports/startup/server';
 import '/imports/api/chat/server';
-
 import '/imports/api/cursor/server';
-
 import '/imports/api/deskshare/server/publications';
 import '/imports/api/deskshare/server/modifiers/clearDeskshareCollection';
 import '/imports/api/deskshare/server/modifiers/handleDeskShareChange';
 import '/imports/api/deskshare/server/modifiers/handleIncomingDeskshareMessage';
 import '/imports/api/deskshare/server/modifiers/eventHandlers';
-
 import '/imports/api/meetings/server';
-
-import '/imports/api/phone/server/modifiers/eventHandlers';
-
 import '/imports/api/polls/server';
-
 import '/imports/api/breakouts/server';
-
 import '/imports/api/presentations/server';
-
 import '/imports/api/shapes/server';
-
 import '/imports/api/slides/server';
-
 import '/imports/api/captions/server';
-
-import '/imports/api/users/server/publications';
-import '/imports/api/users/server/methods/kickUser';
-import '/imports/api/users/server/methods/listenOnlyRequestToggle';
-import '/imports/api/users/server/methods/muteUser';
-import '/imports/api/users/server/methods/setUserPresenter';
-import '/imports/api/users/server/methods/unmuteUser';
-import '/imports/api/users/server/methods/userLogout';
-import '/imports/api/users/server/methods/userSetEmoji';
-import '/imports/api/users/server/methods/validateAuthToken';
-import '/imports/api/users/server/modifiers/clearUsersCollection';
-import '/imports/api/users/server/modifiers/createDummyUser';
-import '/imports/api/users/server/modifiers/handleLockingMic';
-import '/imports/api/users/server/modifiers/markUserOffline';
-import '/imports/api/users/server/modifiers/requestUserLeaving';
-import '/imports/api/users/server/modifiers/setUserLockedStatus';
-import '/imports/api/users/server/modifiers/updateVoiceUser';
-import '/imports/api/users/server/modifiers/userJoined';
-import '/imports/api/users/server/modifiers/eventHandlers';
-
+import '/imports/api/users/server';
 import '/imports/api/common/server/helpers';
 import '/imports/startup/server/logger';
 import '/imports/startup/server/userPermissions';
diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
index 2b77733d195ab200e1abe10339b3aaa1dfb7e9ad..4d2449ac1cfbdf72e30574e08526b2fd6eb73128 100644
--- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
+++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
@@ -172,7 +172,7 @@ defaultAvatarURL=${bigbluebutton.web.serverURL}/client/avatar.png
 # The URL of the default configuration
 defaultConfigURL=${bigbluebutton.web.serverURL}/client/conf/config.xml
 
-apiVersion=1.0
+apiVersion=1.1
 
 # Salt which is used by 3rd-party apps to authenticate api calls
 securitySalt=a820d30da2db356124fce5bd5d8054b4
diff --git a/bigbluebutton-web/grails-app/conf/spring/resources.xml b/bigbluebutton-web/grails-app/conf/spring/resources.xml
index 0802fb33ae79aeca950aede306f2fb53513c2b02..8d9c2445efffad530bf53fcd21d0345e6dcc9eea 100755
--- a/bigbluebutton-web/grails-app/conf/spring/resources.xml
+++ b/bigbluebutton-web/grails-app/conf/spring/resources.xml
@@ -56,7 +56,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
   <bean id="recordingServiceHelper" class="org.bigbluebutton.api.RecordingServiceHelperImp"/>
   
-  <bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService">
+  <bean id="presDownloadService" class="org.bigbluebutton.presentation.PresentationUrlDownloadService" destroy-method="stop">
     <property name="presentationDir" value="${presentationDir}"/>
     <property name="presentationBaseURL" value="${presentationBaseURL}"/>
    	<property name="pageExtractor" ref="pageExtractor"/>  
diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
index c0e58e9d27feae5530ea129509fa54aed702f372..5cf6e37d548c17e740eec8c50211fb9d8490af14 100755
--- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
+++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
@@ -155,44 +155,43 @@ class ApiController {
       return
     }
 
-
-    // Translate the external meeting id into an internal meeting id.
-    String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(params.meetingID);
-    Meeting existing = meetingService.getNotEndedMeetingWithId(internalMeetingId);
-    if (existing != null) {
-      log.debug "Existing conference found"
-      Map<String, Object> updateParams = paramsProcessorUtil.processUpdateCreateParams(params);
-      if (existing.getViewerPassword().equals(params.get("attendeePW")) && existing.getModeratorPassword().equals(params.get("moderatorPW"))) {
-        paramsProcessorUtil.updateMeeting(updateParams, existing);
-        // trying to create a conference a second time, return success, but give extra info
-        // Ignore pre-uploaded presentations. We only allow uploading of presentation once.
-        //uploadDocuments(existing);
-        respondWithConference(existing, "duplicateWarning", "This conference was already in existence and may currently be in progress.");
-      } else {
-        // BEGIN - backward compatibility
-        invalid("idNotUnique", "A meeting already exists with that meeting ID.  Please use a different meeting ID.");
-        return;
-        // END - backward compatibility
-
-        // enforce meetingID unique-ness
-        errors.nonUniqueMeetingIdError()
-        respondWithErrors(errors)
-      }
-
-      return;
-    }
-
     Meeting newMeeting = paramsProcessorUtil.processCreateParams(params);
 
     if (! StringUtils.isEmpty(params.moderatorOnlyMessage)) {
       newMeeting.setModeratorOnlyMessage(params.moderatorOnlyMessage);
     }
 
-    meetingService.createMeeting(newMeeting);
+    if (meetingService.createMeeting(newMeeting)) {
+      // See if the request came with pre-uploading of presentation.
+      uploadDocuments(newMeeting);
+      respondWithConference(newMeeting, null, null)
+    } else {
+      // Translate the external meeting id into an internal meeting id.
+      String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(params.meetingID);
+      Meeting existing = meetingService.getNotEndedMeetingWithId(internalMeetingId);
+      if (existing != null) {
+        log.debug "Existing conference found"
+        Map<String, Object> updateParams = paramsProcessorUtil.processUpdateCreateParams(params);
+        if (existing.getViewerPassword().equals(params.get("attendeePW")) && existing.getModeratorPassword().equals(params.get("moderatorPW"))) {
+          paramsProcessorUtil.updateMeeting(updateParams, existing);
+          // trying to create a conference a second time, return success, but give extra info
+          // Ignore pre-uploaded presentations. We only allow uploading of presentation once.
+          //uploadDocuments(existing);
+          respondWithConference(existing, "duplicateWarning", "This conference was already in existence and may currently be in progress.");
+        } else {
+          // BEGIN - backward compatibility
+          invalid("idNotUnique", "A meeting already exists with that meeting ID.  Please use a different meeting ID.");
+          return;
+          // END - backward compatibility
+
+          // enforce meetingID unique-ness
+          errors.nonUniqueMeetingIdError()
+          respondWithErrors(errors)
+        }
 
-    // See if the request came with pre-uploading of presentation.
-    uploadDocuments(newMeeting);
-    respondWithConference(newMeeting, null, null)
+        return;
+      }
+    }
   }
 
   /**********************************************
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
index 9107015d66d67800f4053bb318a4ccac66c4d380..2d4f22553d2300c101783a50b97b9c87de263053 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
@@ -289,12 +289,19 @@ public class MeetingService implements MessageListener {
                 : Collections.unmodifiableCollection(sessions.values());
     }
 
-    public void createMeeting(Meeting m) {
-        handle(new CreateMeeting(m));
+    public  synchronized boolean createMeeting(Meeting m) {
+        String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(m.getExternalId());
+        Meeting existing = getNotEndedMeetingWithId(internalMeetingId);
+        if (existing == null) {
+            meetings.put(m.getInternalId(), m);
+            handle(new CreateMeeting(m));
+            return true;
+        }
+
+        return false;
     }
 
     private void handleCreateMeeting(Meeting m) {
-        meetings.put(m.getInternalId(), m);
         if (m.isRecord()) {
             Map<String, String> metadata = new TreeMap<String, String>();
             metadata.putAll(m.getMetadata());
@@ -551,9 +558,9 @@ public class MeetingService implements MessageListener {
 
             Meeting breakout = paramsProcessorUtil.processCreateParams(params);
 
-            handleCreateMeeting(breakout);
+            createMeeting(breakout);
 
-            presDownloadService.extractPage(message.parentMeetingId,
+            presDownloadService.extractPresentationPage(message.parentMeetingId,
                     message.sourcePresentationId,
                     message.sourcePresentationSlide, breakout.getInternalId());
         } else {
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java
index 63836e91e40be3ad1b2b9cee6b33a5dd9361b16f..15fda6d6cbeaf6764b99bd328c75cd825d854342 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/PresentationUrlDownloadService.java
@@ -6,6 +6,10 @@ import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.httpclient.HttpClient;
@@ -29,8 +33,24 @@ public class PresentationUrlDownloadService {
     private String presentationDir;
     private String BLANK_PRESENTATION;
 
-    public void processUploadedPresentation(UploadedPresentation uploadedPres) {
-        documentConversionService.processDocument(uploadedPres);
+    private ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
+
+    public void stop() {
+        scheduledThreadPool.shutdownNow();
+    }
+
+    public void processUploadedPresentation(final UploadedPresentation uploadedPres) {
+        /**
+         * We delay processing of the presentation to make sure that the meeting has already been created.
+         * Otherwise, the meeting won't get the conversion events.
+         */
+        ScheduledFuture scheduledFuture =
+                scheduledThreadPool.schedule(new Runnable() {
+                    public void run() {
+                        documentConversionService.processDocument(uploadedPres);
+                    }
+                }, 5, TimeUnit.SECONDS);
+
     }
 
     public void processUploadedFile(String meetingId, String presId,
@@ -41,8 +61,22 @@ public class PresentationUrlDownloadService {
         processUploadedPresentation(uploadedPres);
     }
 
-    public void extractPage(String sourceMeetingId, String presentationId,
-            Integer presentationSlide, String destinationMeetingId) {
+    public void extractPresentationPage(final String sourceMeetingId, final String presentationId,
+                                        final Integer presentationSlide, final String destinationMeetingId)  {
+        /**
+         * We delay processing of the presentation to make sure that the meeting has already been created.
+         * Otherwise, the meeting won't get the conversion events.
+         */
+        ScheduledFuture scheduledFuture =
+                scheduledThreadPool.schedule(new Runnable() {
+                    public void run() {
+                        extractPage(sourceMeetingId, presentationId, presentationSlide, destinationMeetingId) ;
+                    }
+                }, 5, TimeUnit.SECONDS);
+    }
+
+    private void extractPage(final String sourceMeetingId, final String presentationId,
+                             final Integer presentationSlide, final String destinationMeetingId) {
 
         // Build the source meeting path
         File sourceMeetingPath = new File(presentationDir + File.separator
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/imp/Pdf2SwfPageConverter.java b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/imp/Pdf2SwfPageConverter.java
index 42ae5dcfbf46b5070cac2aba5daaa08c3ab36853..54d20397ca5e53f2c311c2baa3b91d299846b0f6 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/imp/Pdf2SwfPageConverter.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/imp/Pdf2SwfPageConverter.java
@@ -52,8 +52,8 @@ public class Pdf2SwfPageConverter implements PageConverter {
   private long placementsThreshold;
   private long defineTextThreshold;
   private long imageTagThreshold;
-  private String convTimeout = "5s";
-  private int WAIT_FOR_SEC = 6;
+  private String convTimeout = "7s";
+  private int WAIT_FOR_SEC = 7;
 
   public boolean convert(File presentation, File output, int page, UploadedPresentation pres) {
     long convertStart = System.currentTimeMillis();
diff --git a/labs/stress-testing/bbb-test b/labs/stress-testing/bbb-test
index 7035782f3ec72419eba233c7629340f58c22441b..00df2792d3ad4da3f8141c6c806be3a65dc1079d 100755
--- a/labs/stress-testing/bbb-test
+++ b/labs/stress-testing/bbb-test
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright (c) 2008-2011 by BigBlueButton Inc.
+# Copyright (c) 2008-2017 by BigBlueButton Inc.
 #
 # Documentation: 
 #   http://code.google.com/p/bigbluebutton/wiki/Testing
@@ -24,8 +24,9 @@
 #
 # Changelog:
 #   2011-01-22 FFD  Inital Version
+#   2017-03-08 Mikhail Novosyolov, Dumalogiya online school <mikhailnov@dumalogiya.ru>, changed Firefox command line call for its new API
 
-VERSION=0.1
+VERSION=0.2
 IP=$(ifconfig | grep -v '127.0.0.1' | grep -E "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | head -1 | cut -d: -f2 | awk '{ print $1}')
 
 
@@ -76,7 +77,7 @@ sleep 3
 i=0
 while [ $i != "$NUMBER" ]; do
 	echo "Connecting user $IP-$i"
-	firefox -a firefox -remote "openURL($HOST/demo/demo1.jsp?action=create&username=$IP-$i,new-tab)" &
+	firefox -new-tab -url "$HOST/demo/demo1.jsp?action=create&username=$IP-$i" &
 	
 	# We'll give BigBlueButton a moment to process the incoming request from this IP.  
 	# If we try to open 10 clients at the same time, the session IDs for each client will
diff --git a/record-and-playback/presentation/playback/presentation/0.9.0/lib/popcorn.chattimeline.js b/record-and-playback/presentation/playback/presentation/0.9.0/lib/popcorn.chattimeline.js
index 015c2ce3e169616b5d4d29454b2bf1a74eaec28b..0838bd926819470d24fa000e5be8e1ea4e0cbdcf 100755
--- a/record-and-playback/presentation/playback/presentation/0.9.0/lib/popcorn.chattimeline.js
+++ b/record-and-playback/presentation/playback/presentation/0.9.0/lib/popcorn.chattimeline.js
@@ -58,18 +58,11 @@
 
     i++;
 
-    //  Default to empty if not used
-    //options.innerHTML = options.innerHTML || "";
+    contentDiv.innerHTML = "<strong>" + options.name + ":</strong>" + options.message;
 
     //If chat message contains a link, we add to it a target attribute
     //So when the user clicks on it, it opens in a new tab
-    if($(options.message).attr('href')) {
-       var tempHtml = $('<div/>',{html:options.message});
-       $(tempHtml).find('a').attr("target","_blank");
-       options.message = tempHtml.html();
-    }
-
-    contentDiv.innerHTML = "<strong>" + options.name + ":</strong>" + options.message;
+    $(contentDiv).find('a').attr('target', '_blank');
 
     return {