diff --git a/bigbluebutton-html5/imports/api/shapes/server/modifiers/addShape.js b/bigbluebutton-html5/imports/api/shapes/server/modifiers/addShape.js
index 231d53c9c79ec2d362c5a2fec2dae85b12c9ac9c..1e15472fe41a028cc74f51b00a52c55b92fc5ce0 100644
--- a/bigbluebutton-html5/imports/api/shapes/server/modifiers/addShape.js
+++ b/bigbluebutton-html5/imports/api/shapes/server/modifiers/addShape.js
@@ -43,7 +43,7 @@ export default function addShape(meetingId, whiteboardId, shape) {
         'shape.shape.id': shape.shape.id,
         'shape.shape.y': shape.shape.y,
         'shape.shape.calcedFontSize': shape.shape.calcedFontSize,
-        'shape.shape.text': shape.shape.text,
+        'shape.shape.text': shape.shape.text.replace(/[\r]/g, '\n'),
       });
       break;
 
diff --git a/bigbluebutton-html5/imports/startup/client/intl.js b/bigbluebutton-html5/imports/startup/client/intl.js
index 8c0ab25d02ededf59f6bce7f41d44354ba4a1f4d..6b14147766b74400eaca1bed868d8f7182d06928 100644
--- a/bigbluebutton-html5/imports/startup/client/intl.js
+++ b/bigbluebutton-html5/imports/startup/client/intl.js
@@ -15,8 +15,9 @@ class IntlStartup extends Component {
 
     this.state = {
       messages: {},
+      appLocale : this.props.locale,
     };
-
+    
     this.fetchLocalizedMessages = this.fetchLocalizedMessages.bind(this);
   }
 
@@ -27,7 +28,14 @@ class IntlStartup extends Component {
 
     baseControls.updateLoadingState(true);
     fetch(url)
-      .then(response => response.json())
+      .then(response => {
+        if (response.ok) {
+          return response.json();
+        } else {
+          this.setState({appLocale: 'en'});
+          return response.json();
+        }
+      })
       .then(messages => {
         this.setState({ messages }, () => {
           baseControls.updateLoadingState(false);
@@ -40,18 +48,19 @@ class IntlStartup extends Component {
   }
 
   componentWillMount() {
-    this.fetchLocalizedMessages(this.props.locale);
+    this.fetchLocalizedMessages(this.state.appLocale);
   }
 
   componentWillUpdate(nextProps, nextState) {
     if (this.props.locale !== nextProps.locale) {
+      this.setState({appLocale: nextProps.locale});
       this.fetchLocalizedMessages(nextProps.locale);
     }
   }
 
   render() {
     return (
-      <IntlProvider locale={this.props.locale} messages={this.state.messages}>
+      <IntlProvider locale={this.state.appLocale} messages={this.state.messages}>
         {this.props.children}
       </IntlProvider>
     );
diff --git a/bigbluebutton-html5/imports/startup/server/index.js b/bigbluebutton-html5/imports/startup/server/index.js
index a8371245e4054f5314c6ead9f7e28d39bfbf0cae..5c64b14063bcfc8ac9c8280cb1ee87526ac40dea 100755
--- a/bigbluebutton-html5/imports/startup/server/index.js
+++ b/bigbluebutton-html5/imports/startup/server/index.js
@@ -24,9 +24,8 @@ WebApp.connectHandlers.use('/locale', (req, res) => {
   let defaultLocale = APP_CONFIG.defaultLocale;
   let localeRegion = req.query.locale.split('-');
   let messages = {};
-
   let locales = [defaultLocale, localeRegion[0]];
-
+  let statusCode = 200;
   if (localeRegion.length > 1) {
     locales.push(`${localeRegion[0]}_${localeRegion[1].toUpperCase()}`);
   }
@@ -36,14 +35,15 @@ WebApp.connectHandlers.use('/locale', (req, res) => {
       const data = Assets.getText(`locales/${locale}.json`);
       messages = Object.assign(messages, JSON.parse(data));
     } catch (e) {
-      // console.error(e);
-      // We dont really care about those errors since they will be a parse error
-      // or a file not found which is ok
+      //Variant Also Negotiates Status-Code, to alert the client that we
+      //do not support the following lang.
+      //https://en.wikipedia.org/wiki/Content_negotiation
+      statusCode = 506;
     }
   });
 
   res.setHeader('Content-Type', 'application/json');
-  res.writeHead(200);
+  res.writeHead(statusCode);
   res.end(JSON.stringify(messages));
 });
 
diff --git a/bigbluebutton-html5/imports/startup/server/userPermissions.js b/bigbluebutton-html5/imports/startup/server/userPermissions.js
index 4fea3ba0ea46af05952924788959e010afec6cb2..750e536580db121b8f8a0c385275e024f87438a3 100755
--- a/bigbluebutton-html5/imports/startup/server/userPermissions.js
+++ b/bigbluebutton-html5/imports/startup/server/userPermissions.js
@@ -129,12 +129,23 @@ export function isAllowedTo(action, credentials) {
   });
 
   const allowedToInitiateRequest =
-    null != user &&
-    authToken === user.authToken &&
+    user &&
+    user.authToken === authToken &&
     user.validated &&
-    user.user.connection_status === 'online' &&
-    'HTML5' === user.clientType &&
-    null != user.user;
+    user.clientType === 'HTML5' &&
+    user.user &&
+    user.user.connection_status === 'online';
+
+  const listOfSafeActions = [
+    'logoutSelf',
+  ];
+
+  const requestIsSafe = listOfSafeActions.includes(action);
+
+  if (requestIsSafe) {
+    logger.info(`permissions: requestIsSafe for ${action} by userId=${userId} allowed`);
+    return true;
+  }
 
   if (allowedToInitiateRequest) {
     let result = false;
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 e880898ebfb1eef070c58855ce00a0fdd4b03a29..e0d3cf3b83fc660e42eec98028babb0e4211ee00 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
@@ -18,6 +18,7 @@ const propTypes = {
 class EmojiMenu extends Component {
   constructor(props) {
     super(props);
+
   }
 
   render() {
@@ -28,8 +29,8 @@ class EmojiMenu extends Component {
    } = this.props;
 
     return (
-      <Dropdown ref="dropdown">
-        <DropdownTrigger>
+      <Dropdown autoFocus={true}>
+        <DropdownTrigger placeInTabOrder={true}>
           <Button
             role="button"
             label={intl.formatMessage(intlMessages.statusTriggerLabel)}
@@ -46,7 +47,7 @@ class EmojiMenu extends Component {
             // even after the DropdownTrigger inject an onClick handler
             onClick={() => null}>
             <div id="currentStatus" hidden>
-              {intl.formatMessage(intlMessages.currentStatusDesc, { status: userEmojiStatus}) }
+              {intl.formatMessage(intlMessages.currentStatusDesc, { 0: userEmojiStatus}) }
             </div>
           </Button>
         </DropdownTrigger>
@@ -57,54 +58,63 @@ class EmojiMenu extends Component {
               label={intl.formatMessage(intlMessages.raiseLabel)}
               description={intl.formatMessage(intlMessages.raiseDesc)}
               onClick={() => actions.setEmojiHandler('raiseHand')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="happy"
               label={intl.formatMessage(intlMessages.happyLabel)}
               description={intl.formatMessage(intlMessages.happyDesc)}
               onClick={() => actions.setEmojiHandler('happy')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="undecided"
               label={intl.formatMessage(intlMessages.undecidedLabel)}
               description={intl.formatMessage(intlMessages.undecidedDesc)}
               onClick={() => actions.setEmojiHandler('neutral')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="sad"
               label={intl.formatMessage(intlMessages.sadLabel)}
               description={intl.formatMessage(intlMessages.sadDesc)}
               onClick={() => actions.setEmojiHandler('sad')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="confused"
               label={intl.formatMessage(intlMessages.confusedLabel)}
               description={intl.formatMessage(intlMessages.confusedDesc)}
               onClick={() => actions.setEmojiHandler('confused')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="time"
               label={intl.formatMessage(intlMessages.awayLabel)}
               description={intl.formatMessage(intlMessages.awayDesc)}
               onClick={() => actions.setEmojiHandler('away')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="thumbs_up"
               label={intl.formatMessage(intlMessages.thumbsupLabel)}
               description={intl.formatMessage(intlMessages.thumbsupDesc)}
               onClick={() => actions.setEmojiHandler('thumbsUp')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="thumbs_down"
               label={intl.formatMessage(intlMessages.thumbsdownLabel)}
               description={intl.formatMessage(intlMessages.thumbsdownDesc)}
               onClick={() => actions.setEmojiHandler('thumbsDown')}
+              tabIndex={-1}
             />
             <DropdownListItem
               icon="applause"
               label={intl.formatMessage(intlMessages.applauseLabel)}
               description={intl.formatMessage(intlMessages.applauseDesc)}
               onClick={() => actions.setEmojiHandler('applause')}
+              tabIndex={-1}
             />
             <DropdownListSeparator />
             <DropdownListItem
@@ -112,6 +122,7 @@ class EmojiMenu extends Component {
               label={intl.formatMessage(intlMessages.clearLabel)}
               description={intl.formatMessage(intlMessages.clearDesc)}
               onClick={() => actions.setEmojiHandler('none')}
+              tabIndex={-1}
             />
           </DropdownList>
         </DropdownContent>
diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx
index caf790869c726e4dcdaac4cf37d121a540dce274..154e5a7e3912f97879a788b1487d4f1ad5f46f7f 100755
--- a/bigbluebutton-html5/imports/ui/components/app/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx
@@ -31,7 +31,6 @@ const intlMessages = defineMessages({
   kickedMessage: {
     id: 'app.error.kicked',
     description: 'Message when the user is kicked out of the meeting',
-    defaultMessage: 'You have been kicked out of the meeting',
   },
 });
 
diff --git a/bigbluebutton-html5/imports/ui/components/chat/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
index 97e6e638e48b5ec271f5aeeefeb664a59f913028..6c1cec82e9bb723415fa38b2ed420d569d87211c 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/component.jsx
@@ -47,7 +47,7 @@ class Chat extends Component {
             <Link
               to="/users"
               role="button"
-              aria-label={intl.formatMessage(intlMessages.hideChatLabel, { title: title })}>
+              aria-label={intl.formatMessage(intlMessages.hideChatLabel, { 0: title })}>
                 <Icon iconName="left_arrow"/> {title}
             </Link>
           </div>
@@ -58,7 +58,7 @@ class Chat extends Component {
                 <Link
                   to="/users"
                   role="button"
-                  aria-label={intl.formatMessage(intlMessages.closeChatLabel, { title: title })}>
+                  aria-label={intl.formatMessage(intlMessages.closeChatLabel, { 0: title })}>
                     <Icon iconName="close" onClick={() => actions.handleClosePrivateChat(chatID)}/>
                 </Link>)
             }
diff --git a/bigbluebutton-html5/imports/ui/components/chat/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/container.jsx
index c7578a846596a6b56c842e60a8d239d935841c68..e4705b2976db00564f20aa027d1b1e351e93f8c6 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/container.jsx
@@ -11,17 +11,14 @@ import ChatService from './service';
 const intlMessages = defineMessages({
   titlePublic: {
     id: 'app.chat.titlePublic',
-    defaultMessage: 'Public Chat',
     description: 'Public chat title',
   },
   titlePrivate: {
     id: 'app.chat.titlePrivate',
-    defaultMessage: 'Private Chat with {name}',
     description: 'Private chat title',
   },
   partnerDisconnected: {
     id: 'app.chat.partnerDisconnected',
-    defaultMessage: '{name} has left the meeting',
     description: 'System chat message when the private chat partnet disconnect from the meeting',
   },
 });
@@ -65,7 +62,7 @@ export default injectIntl(createContainer(({ params, intl }) => {
       let userMessage = messages.find(m => m.sender !== null);
       let user = ChatService.getUser(chatID, '{{NAME}}');
 
-      title = intl.formatMessage(intlMessages.titlePrivate, { name: user.name });
+      title = intl.formatMessage(intlMessages.titlePrivate, { 0: user.name });
       chatName = user.name;
 
       if (!user.isOnline) {
@@ -75,7 +72,7 @@ export default injectIntl(createContainer(({ params, intl }) => {
           id,
           content: [{
             id,
-            text: intl.formatMessage(intlMessages.partnerDisconnected, { name: user.name }),
+            text: intl.formatMessage(intlMessages.partnerDisconnected, { 0: user.name }),
             time,
           },],
           time,
diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
index f58beaaab0890011374cb5bfa03f37ba882d3143..030ffa9cbd1cbc3d82bc1c203bdcb35ac6283237 100755
--- a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx
@@ -105,9 +105,9 @@ class MessageForm extends Component {
         <TextareaAutosize
           className={styles.input}
           id="message-input"
-          placeholder={intl.formatMessage(messages.inputPlaceholder, { name: chatName })}
+          placeholder={intl.formatMessage(messages.inputPlaceholder, { 0: chatName })}
           aria-controls={this.props.chatAreaId}
-          aria-label={intl.formatMessage(messages.inputLabel, { name: chatTitle })}
+          aria-label={intl.formatMessage(messages.inputLabel, { 0: chatTitle })}
           autoCorrect="off"
           autoComplete="off"
           spellCheck="true"
diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx
index 7190e0d410d1e5e6d5688841d805f9885a0e0eee..3676e902756c1eaec51e375cfde8e8074d1a2b89 100755
--- a/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx
@@ -83,15 +83,18 @@ class Dropdown extends Component {
 
   handleShow() {
     this.setState({ isOpen: true }, this.handleStateCallback);
-
-    const contentElement = findDOMNode(this.refs.content);
-    contentElement.querySelector(FOCUSABLE_CHILDREN).focus();
   }
 
   handleHide() {
+
+    const { autoFocus } = this.props;
+
     this.setState({ isOpen: false }, this.handleStateCallback);
-    const triggerElement = findDOMNode(this.refs.trigger);
-    triggerElement.focus();
+
+    if (autoFocus) {
+      const triggerElement = findDOMNode(this.refs.trigger);
+      triggerElement.focus();
+    }
   }
 
   componentDidMount () {
@@ -122,7 +125,14 @@ class Dropdown extends Component {
   }
 
   render() {
-    const { children, className, style, intl } = this.props;
+    const {
+      children,
+      className,
+      style, intl,
+      hasPopup,
+      ariaLive,
+      ariaRelevant,
+    } = this.props;
 
     let trigger = children.find(x => x.type === DropdownTrigger);
     let content = children.find(x => x.type === DropdownContent);
@@ -143,7 +153,12 @@ class Dropdown extends Component {
     });
 
     return (
-      <div style={style} className={cx(styles.dropdown, className)}>
+      <div
+      style={style}
+      className={cx(styles.dropdown, className)}
+      aria-live={ariaLive}
+      aria-relevant={ariaRelevant}
+      aria-haspopup={hasPopup}>
         {trigger}
         {content}
         { this.state.isOpen ?
diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx
index c355a4fc27333f8ca175fb2540222004f6595916..b6349a23d3c0032685913c41dd236e1eefd783b9 100755
--- a/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx
@@ -78,7 +78,7 @@ export default class DropdownList extends Component {
       nextActiveItemIndex = this.childrenRefs.length - 1;
     }
 
-    if ([KEY_CODES.TAB, KEY_CODES.ESCAPE].includes(event.which)) {
+    if ([KEY_CODES.ESCAPE].includes(event.which)) {
       nextActiveItemIndex = 0;
       dropdownHide();
     }
diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/list/item/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/list/item/component.jsx
index 369904192a254ee6de176e20c439e3730eb22957..2c8e215984dafa60044d0f88fd8bfe9610585d51 100755
--- a/bigbluebutton-html5/imports/ui/components/dropdown/list/item/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/dropdown/list/item/component.jsx
@@ -29,14 +29,16 @@ export default class DropdownListItem extends Component {
 
   render() {
     const { label, description, children, injectRef, tabIndex, onClick, onKeyDown,
-      className, style, separator, intl, } = this.props;
+      className, style, separator, intl, placeInTabOrder, } = this.props;
+
+    let index = (placeInTabOrder) ? 0 : -1;
 
     return (
       <li
         ref={injectRef}
         onClick={onClick}
         onKeyDown={onKeyDown}
-        tabIndex={tabIndex}
+        tabIndex={index}
         aria-labelledby={this.labelID}
         aria-describedby={this.descID}
         className={cx(styles.item, className)}
diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/list/title/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/list/title/component.jsx
index 716c22896741492054e756bc6d11c5285c63f75f..96500c1df1f8b3b6cbf6b8155a56301c449a589b 100755
--- a/bigbluebutton-html5/imports/ui/components/dropdown/list/title/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/dropdown/list/title/component.jsx
@@ -1,22 +1,22 @@
-import React, { Component, PropTypes } from 'react';
-import styles from '../styles';
-
-const propTypes = {
-  description: PropTypes.string,
-};
-
-export default class DropdownListTitle extends Component {
-
-  render() {
-    const { intl, description } = this.props;
-
-    return (
-      <div>
-        <li className={styles.title} aria-describedby="labelContext">{this.props.children}</li>
-        <div id="labelContext" aria-label={description}></div>
-      </div>
-    );
-  }
-}
-
-DropdownListTitle.propTypes = propTypes;
+import React, { Component, PropTypes } from 'react';
+import styles from '../styles';
+
+const propTypes = {
+  description: PropTypes.string,
+};
+
+export default class DropdownListTitle extends Component {
+
+  render() {
+    const { intl, description } = this.props;
+
+    return (
+      <div>
+        <li className={styles.title} aria-describedby="labelContext">{this.props.children}</li>
+        <div id="labelContext" aria-label={description}></div>
+      </div>
+    );
+  }
+}
+
+DropdownListTitle.propTypes = propTypes;
diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/trigger/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/trigger/component.jsx
index 75ede0df9c501427551f5310bced381d90b3a9d7..2df2f49f669943b7b8425dbf29ae3bc10c1aa357 100755
--- a/bigbluebutton-html5/imports/ui/components/dropdown/trigger/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/dropdown/trigger/component.jsx
@@ -41,14 +41,16 @@ export default class DropdownTrigger extends Component {
   }
 
   render() {
-    const { children, style, className, } = this.props;
+    const { children, style, className, placeInTabOrder, } = this.props;
     const TriggerComponent = React.Children.only(children);
 
+    let index = (placeInTabOrder) ? '0' : '-1';
+
     const TriggerComponentBounded = React.cloneElement(children, {
       onClick: this.handleClick,
       onKeyDown: this.handleKeyDown,
       'aria-haspopup': true,
-      tabIndex: '0',
+      tabIndex: index,
       style: style,
       className: cx(children.props.className, className),
     });
diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/component.jsx
index 72b3cbe9c90f70b4de536e36129de4acfc01b7a6..961625f114954c0e9082999d8bc679534449da85 100755
--- a/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/component.jsx
@@ -83,8 +83,8 @@ class SettingsDropdown extends Component {
     }
 
     return (
-      <Dropdown ref="dropdown">
-        <DropdownTrigger>
+      <Dropdown autoFocus={true}>
+        <DropdownTrigger placeInTabOrder={true}>
           <Button
             label={intl.formatMessage(intlMessages.optionsLabel)}
             icon="more"
diff --git a/bigbluebutton-html5/imports/ui/components/notifications-bar/container.jsx b/bigbluebutton-html5/imports/ui/components/notifications-bar/container.jsx
old mode 100644
new mode 100755
index eee4b867ff67f1e4512ed36601571e72e69a80eb..6b38d1c875cf5094b1ef1749951e4555f544d147
--- a/bigbluebutton-html5/imports/ui/components/notifications-bar/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/notifications-bar/container.jsx
@@ -27,32 +27,26 @@ const STATUS_OFFLINE = 'offline';
 const intlMessages = defineMessages({
   failedMessage: {
     id: 'app.failedMessage',
-    defaultMessage: 'Apologies, trouble connecting to the server.',
-    description: 'Message when the client is trying to connect to the server',
+    description: 'Notification for connecting to server problems',
   },
   connectingMessage: {
     id: 'app.connectingMessage',
-    defaultMessage: 'Connecting...',
-    description: 'Message when the client is trying to connect to the server',
+    description: 'Notification message for when client is connecting to server',
   },
   waitingMessage: {
     id: 'app.waitingMessage',
-    defaultMessage: 'Disconnected. Trying to reconnect in {seconds} seconds...',
-    description: 'Message when the client is trying to reconnect to the server',
+    description: 'Notification message for disconnection with reconnection counter',
   },
   breakoutTimeRemaining: {
     id: 'app.breakoutTimeRemainingMessage',
-    defaultMessage: 'Breakout Room time remaining: {time}',
     description: 'Message that tells how much time is remaining for the breakout room',
   },
   breakoutWillClose: {
     id: 'app.breakoutWillCloseMessage',
-    defaultMessage: 'Time ended. Breakout Room will close soon',
     description: 'Message that tells time has ended and breakout will close',
   },
   calculatingBreakoutTimeRemaining: {
     id: 'app.calculatingBreakoutTimeRemaining',
-    defaultMessage: 'Calculating remaining time...',
     description: 'Message that tells that the remaining time is being calculated',
   },
 });
@@ -146,7 +140,7 @@ export default injectIntl(createContainer(({ intl }) => {
         retryInterval = startCounter(sec, setRetrySeconds, getRetrySeconds, retryInterval);
         data.message = intl.formatMessage(
           intlMessages.waitingMessage,
-          { seconds: getRetrySeconds() }
+          { 0: getRetrySeconds() }
         );
         break;
     }
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 db94fdb95357c4fae75a0c6eb43249c3a9a88e45..097b4a6e83683741d9a8fd5d5bd460c5e72a2b0d 100755
--- a/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/presentation/default-content/component.jsx
@@ -31,8 +31,8 @@ export default class DefaultContent extends Component {
                 <FormattedMessage
                   id="app.home.greeting"
                   description="Message to greet the user."
-                  defaultMessage="Welcome {name}! Your presentation will begin shortly..."
-                  values={{ name: 'James Bond' }}
+                  defaultMessage="Welcome {0}! Your presentation will begin shortly..."
+                  values={{ 0: 'James Bond' }}
                 />
                 <br/>
                 Today is {' '}<FormattedDate value={Date.now()} />
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
index 78f64162af94f2d29927e3a17251f56b8cbdf3c6..0ade0c7fc6ff46bf5165e887a0aff0ed17382f18 100755
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
@@ -181,7 +181,7 @@ class ApplicationMenu extends BaseMenu {
                   defaultValue={this.state.settings.locale}
                   className={styles.select}
                   onChange={this.handleSelectChange.bind(this, 'locale', availableLocales)}>
-                  <option>
+                  <option disabled={true}>
                     { availableLocales &&
                       availableLocales.length ?
                       intl.formatMessage(intlMessages.languageOptionLabel) :
diff --git a/bigbluebutton-html5/imports/ui/components/user-avatar/component.jsx b/bigbluebutton-html5/imports/ui/components/user-avatar/component.jsx
index f95e3702746238873b5ba4962d43935218544d04..bffd9d4e8e4d19027f74458c5e47a564877da90f 100755
--- a/bigbluebutton-html5/imports/ui/components/user-avatar/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-avatar/component.jsx
@@ -33,7 +33,7 @@ export default class UserAvatar extends Component {
 
     return (
       <div className={user.isOnline ? styles.userAvatar : styles.userLogout}
-           style={avatarStyles}>
+           style={avatarStyles} aria-hidden="true">
         <div>
           {this.renderAvatarContent()}
         </div>
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx
index c48ee6d265194e7747788a8f1809eb8b5f59c5dd..f615401d42ced4eab231f8024c9f167ef73b9dce 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/component.jsx
@@ -43,6 +43,7 @@ class ChatListItem extends Component {
       openChat,
       compact,
       intl,
+      tabIndex,
     } = this.props;
 
     const linkPath = [PRIVATE_CHAT_PATH, chat.id].join('');
@@ -57,12 +58,13 @@ class ChatListItem extends Component {
     }
 
     return (
-      <li className={cx(styles.chatListItem, linkClasses)}>
         <Link
           to={linkPath}
-          className={styles.chatListItemLink}
+          className={cx(styles.chatListItem, linkClasses)}
           role="button"
-          aria-expanded={isCurrentChat}>
+          aria-expanded={isCurrentChat}
+          tabIndex={tabIndex}>
+            <div className={styles.chatListItemLink}>
             {chat.icon ? this.renderChatIcon() : this.renderChatAvatar()}
             <div className={styles.chatName}>
               {!compact ? <span className={styles.chatNameMain}>{chat.name}</span> : null }
@@ -71,15 +73,15 @@ class ChatListItem extends Component {
               <div
                 className={styles.unreadMessages}
                 aria-label={isSingleMessage
-                  ? intl.formatMessage(intlMessages.unreadSingular, { count: chat.unreadCounter })
-                  : intl.formatMessage(intlMessages.unreadPlural, { count: chat.unreadCounter })}>
+                  ? intl.formatMessage(intlMessages.unreadSingular, { 0: chat.unreadCounter })
+                  : intl.formatMessage(intlMessages.unreadPlural, { 0: chat.unreadCounter })}>
                 <div className={styles.unreadMessagesText} aria-hidden="true">
                   {chat.unreadCounter}
                 </div>
               </div>
               : null}
+              </div>
         </Link>
-      </li>
     );
   }
 
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/styles.scss b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/styles.scss
index 05cdca0d7b6e8f2b4e32a59119ef3315ebc4ccb5..eb2e80c3b7658e26b1246e0f54c1694285036618 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/user-list/chat-list-item/styles.scss
@@ -4,6 +4,7 @@
   @extend %list-item;
   cursor: pointer;
   padding: 0;
+  text-decoration: none;
 }
 
 .chatListItemLink {
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/component.jsx
index 89ac3240b849f6bf3cb06836eb8b4972087bd4af..b6e161f1508844cc508b9b2870e8df61b3ad68c6 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-list/component.jsx
@@ -6,6 +6,7 @@ import cx from 'classnames';
 import { defineMessages, injectIntl } from 'react-intl';
 import UserListItem from './user-list-item/component.jsx';
 import ChatListItem from './chat-list-item/component.jsx';
+import KEY_CODES from '/imports/utils/keyCodes';
 
 const propTypes = {
   openChats: PropTypes.array.isRequired,
@@ -30,6 +31,128 @@ class UserList extends Component {
     this.state = {
       compact: this.props.compact,
     };
+
+    this.rovingIndex = this.rovingIndex.bind(this);
+    this.focusList = this.focusList.bind(this);
+    this.focusListItem = this.focusListItem.bind(this);
+    this.counter = -1;
+  }
+
+  focusList(activeElement, list) {
+    activeElement.tabIndex = -1;
+    this.counter = 0;
+    list.tabIndex = 0;
+    list.focus();
+  }
+
+  focusListItem(active, direction, element, count) {
+
+    function select() {
+      element.tabIndex = 0;
+      element.focus();
+    }
+
+    active.tabIndex = -1;
+
+    switch (direction) {
+      case 'down':
+        element.childNodes[this.counter].tabIndex = 0;
+        element.childNodes[this.counter].focus();
+        this.counter++;
+        break;
+      case 'up':
+        this.counter--;
+        element.childNodes[this.counter].tabIndex = 0;
+        element.childNodes[this.counter].focus();
+        break;
+      case 'upLoopUp':
+      case 'upLoopDown':
+        this.counter = count - 1;
+        select();
+        break;
+      case 'downLoopDown':
+        this.counter = -1;
+        select();
+        break;
+      case 'downLoopUp':
+        this.counter = 1;
+        select();
+        break;
+    }
+  }
+
+  rovingIndex(...Args) {
+    const { users, openChats } = this.props;
+
+    let active = document.activeElement;
+    let list;
+    let items;
+    let count;
+
+    switch (Args[1]) {
+      case 'users':
+        list = this._usersList;
+        items = this._userItems;
+        count = users.length;
+        break;
+      case 'messages':
+        list = this._msgsList;
+        items = this._msgItems;
+        count = openChats.length;
+        break;
+    }
+
+    if (Args[0].keyCode === KEY_CODES.ESCAPE
+      || this.counter === -1
+      || this.counter > count) {
+      this.focusList(active, list);
+    }
+
+    if (Args[0].keyCode === KEY_CODES.ENTER
+        || Args[0].keyCode === KEY_CODES.ARROW_RIGHT
+        || Args[0].keyCode === KEY_CODES.ARROW_LEFT) {
+      active.firstChild.click();
+    }
+
+    if (Args[0].keyCode === KEY_CODES.ARROW_DOWN) {
+      if (this.counter < count) {
+        this.focusListItem(active, 'down', items);
+      }else if (this.counter === count) {
+        this.focusListItem(active, 'downLoopDown', list);
+      }else if (this.counter === 0) {
+        this.focusListItem(active, 'downLoopUp', list);
+      }
+    }
+
+    if (Args[0].keyCode === KEY_CODES.ARROW_UP) {
+      if (this.counter < count && this.counter !== 0) {
+        this.focusListItem(active, 'up', items);
+      }else if (this.counter === 0) {
+        this.focusListItem(active, 'upLoopUp', list, count);
+      }else if (this.counter === count) {
+        this.focusListItem(active, 'upLoopDown', list, count);
+      }
+    }
+  }
+
+  componentDidMount() {
+    let _this = this;
+
+    if (!this.state.compact) {
+      this._msgsList.addEventListener('keypress', function (event) {
+        _this.rovingIndex.call(this, event, 'messages');
+      });
+
+      this._usersList.addEventListener('keypress', function (event) {
+        _this.rovingIndex.call(this, event, 'users');
+      });
+    }
+  }
+
+  componentWillUnmount() {
+    this._msgsList.removeEventListener('keypress', function (event) {}, false);
+
+    this._usersList.removeEventListener('keypress', function (event) {}, false);
   }
 
   render() {
@@ -48,9 +171,9 @@ class UserList extends Component {
       <div className={styles.header}>
         {
           !this.state.compact ?
-          <h2 className={styles.headerTitle}>
+          <div className={styles.headerTitle} role="banner">
             {intl.formatMessage(intlMessages.participantsTitle)}
-          </h2> : null
+          </div> : null
         }
       </div>
     );
@@ -76,11 +199,14 @@ class UserList extends Component {
       <div className={styles.messages}>
         {
           !this.state.compact ?
-          <h3 className={styles.smallTitle}>
+          <div className={styles.smallTitle} role="banner">
             {intl.formatMessage(intlMessages.messagesTitle)}
-          </h3> : <hr className={styles.separator}></hr>
+          </div> : <hr className={styles.separator}></hr>
         }
-        <div className={styles.scrollableList}>
+        <div
+          tabIndex={0}
+          className={styles.scrollableList}
+          ref={(r) => this._msgsList = r}>
           <ReactCSSTransitionGroup
             transitionName={listTransition}
             transitionAppear={true}
@@ -89,15 +215,18 @@ class UserList extends Component {
             transitionAppearTimeout={0}
             transitionEnterTimeout={0}
             transitionLeaveTimeout={0}
-            component="ul"
+            component="div"
             className={cx(styles.chatsList, styles.scrollableList)}>
+            <div ref={(r) => this._msgItems = r}>
               {openChats.map(chat => (
                 <ChatListItem
                   compact={this.state.compact}
                   key={chat.id}
                   openChat={openChat}
-                  chat={chat} />
+                  chat={chat}
+                  tabIndex={-1} />
               ))}
+            </div>
           </ReactCSSTransitionGroup>
         </div>
       </div>
@@ -111,6 +240,7 @@ class UserList extends Component {
       isBreakoutRoom,
       intl,
       makeCall,
+      meeting,
     } = this.props;
 
     const userActions = {
@@ -150,33 +280,41 @@ class UserList extends Component {
       <div className={styles.participants}>
         {
           !this.state.compact ?
-          <h3 className={styles.smallTitle}>
+          <div className={styles.smallTitle} role="banner">
             {intl.formatMessage(intlMessages.usersTitle)}
             &nbsp;({users.length})
-          </h3> : <hr className={styles.separator}></hr>
+          </div> : <hr className={styles.separator}></hr>
         }
-        <ReactCSSTransitionGroup
-          transitionName={listTransition}
-          transitionAppear={true}
-          transitionEnter={true}
-          transitionLeave={true}
-          transitionAppearTimeout={0}
-          transitionEnterTimeout={0}
-          transitionLeaveTimeout={0}
-          component="ul"
-          className={cx(styles.participantsList, styles.scrollableList)}>
-          {
-            users.map(user => (
-            <UserListItem
-              compact={this.state.compact}
-              key={user.id}
-              isBreakoutRoom={isBreakoutRoom}
-              user={user}
-              currentUser={currentUser}
-              userActions={userActions}
-            />
-          ))}
-        </ReactCSSTransitionGroup>
+        <div
+          className={styles.scrollableList}
+          tabIndex={0}
+          ref={(r) => this._usersList = r}>
+          <ReactCSSTransitionGroup
+            transitionName={listTransition}
+            transitionAppear={true}
+            transitionEnter={true}
+            transitionLeave={true}
+            transitionAppearTimeout={0}
+            transitionEnterTimeout={0}
+            transitionLeaveTimeout={0}
+            component="div"
+            className={cx(styles.participantsList, styles.scrollableList)}>
+            <div ref={(r) => this._userItems = r}>
+              {
+                users.map(user => (
+                <UserListItem
+                  compact={this.state.compact}
+                  key={user.id}
+                  isBreakoutRoom={isBreakoutRoom}
+                  user={user}
+                  currentUser={currentUser}
+                  userActions={userActions}
+                  meeting={meeting}
+                />))
+              }
+            </div>
+          </ReactCSSTransitionGroup>
+        </div>
       </div>
     );
   }
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/container.jsx b/bigbluebutton-html5/imports/ui/components/user-list/container.jsx
index 6aab0c71ab632e243d4b03cb44ec9fef141966aa..a3433b154f06518a49cc05c81141aa0ad0ff1cd5 100644
--- a/bigbluebutton-html5/imports/ui/components/user-list/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-list/container.jsx
@@ -3,6 +3,7 @@ import { createContainer } from 'meteor/react-meteor-data';
 import { meetingIsBreakout } from '/imports/ui/components/app/service';
 import { makeCall } from '/imports/ui/services/api';
 import Service from './service.js';
+import Meetings from '/imports/api/meetings';
 
 import UserList from './component.jsx';
 
@@ -17,12 +18,14 @@ class UserListContainer extends Component {
       userActions,
       isBreakoutRoom,
       children,
+      meeting,
     } = this.props;
 
     return (
       <UserList
         compact={compact}
         users={users}
+        meeting={meeting}
         currentUser={currentUser}
         openChats={openChats}
         openChat={openChat}
@@ -37,6 +40,7 @@ class UserListContainer extends Component {
 
 export default createContainer(({ params }) => ({
   users: Service.getUsers(),
+  meeting: Meetings.findOne({}),
   currentUser: Service.getCurrentUser(),
   openChats: Service.getOpenChats(params.chatID),
   openChat: params.chatID,
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 75b55c8609ebfec865cc81bec8e3b319b8c2c292..f7bdaf1ac7479cd3286facab571255bbaeb835b8 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
@@ -54,6 +54,14 @@ const messages = defineMessages({
     id: 'app.userlist.menuTitleContext',
     description: 'adds context to userListItem menu title',
   },
+  userItemStatusAriaLabel: {
+    id: 'app.userlist.useritem.status.arialabel',
+    description: 'adds aria label for user and status',
+  },
+  userItemAriaLabel: {
+    id: 'app.userlist.useritem.nostatus.arialabel',
+    description: 'aria label for user',
+  },
 });
 
 const userActionsTransition = {
@@ -234,15 +242,81 @@ class UserListItem extends Component {
     userItemContentsStyle[styles.userItemContentsCompact] = compact;
     userItemContentsStyle[styles.active] = this.state.isActionsOpen;
 
+    const {
+      user,
+      intl,
+    } = this.props;
+
+    let you = (user.isCurrent) ? intl.formatMessage(messages.you) : null;
+
+    let presenter = (user.isPresenter)
+      ? intl.formatMessage(messages.presenter)
+      : null;
+
+    let userAriaLabel = (user.emoji.status === 'none')
+      ? intl.formatMessage(messages.userItemAriaLabel,
+          { username: user.name, presenter: presenter, you: you, })
+      : intl.formatMessage(messages.userItemStatusAriaLabel,
+          { username: user.name,
+            presenter: presenter,
+            you: you,
+            status: user.emoji.status, });
+
+    let actions = this.getAvailableActions();
+    let contents = (
+      <div
+        className={cx(styles.userListItem, userItemContentsStyle)}
+        aria-label={userAriaLabel}>
+        <div className={styles.userItemContents} aria-hidden="true">
+          <UserAvatar user={user} />
+          {this.renderUserName()}
+          {this.renderUserIcons()}
+        </div>
+      </div>
+    );
+
+    if (!actions.length) {
+      return contents;
+    }
+
+    const { dropdownOffset, dropdownDirection, dropdownVisible, } = this.state;
+
     return (
-      <li
-        role="button"
-        aria-haspopup="true"
-        aria-live="assertive"
-        aria-relevant="additions"
-        className={cx(styles.userListItem, userItemContentsStyle)}>
-        {this.renderUserContents()}
-      </li>
+      <Dropdown
+        ref="dropdown"
+        isOpen={this.state.isActionsOpen}
+        onShow={this.onActionsShow}
+        onHide={this.onActionsHide}
+        className={styles.dropdown}
+        autoFocus={false}
+        hasPopup="true"
+        ariaLive="assertive"
+        ariaRelevant="additions">
+        <DropdownTrigger>
+          {contents}
+        </DropdownTrigger>
+        <DropdownContent
+          style={{
+            visibility: dropdownVisible ? 'visible' : 'hidden',
+            [dropdownDirection]: `${dropdownOffset}px`,
+          }}
+          className={styles.dropdownContent}
+          placement={`right ${dropdownDirection}`}>
+
+          <DropdownList>
+            {
+              [
+                (<DropdownListTitle
+                    description={intl.formatMessage(messages.menuTitleContext)}
+                    key={_.uniqueId('dropdown-list-title')}>
+                      {user.name}
+                 </DropdownListTitle>),
+                (<DropdownListSeparator key={_.uniqueId('action-separator')} />),
+              ].concat(actions)
+            }
+          </DropdownList>
+        </DropdownContent>
+      </Dropdown>
     );
   }
 
@@ -254,7 +328,7 @@ class UserListItem extends Component {
 
     let actions = this.getAvailableActions();
     let contents = (
-      <div tabIndex={0} className={styles.userItemContents}>
+      <div className={styles.userItemContents}>
         <UserAvatar user={user} />
         {this.renderUserName()}
         {this.renderUserIcons()}
@@ -273,7 +347,8 @@ class UserListItem extends Component {
         isOpen={this.state.isActionsOpen}
         onShow={this.onActionsShow}
         onHide={this.onActionsHide}
-        className={styles.dropdown}>
+        className={styles.dropdown}
+        autoFocus={false}>
         <DropdownTrigger>
           {contents}
         </DropdownTrigger>
@@ -307,6 +382,7 @@ class UserListItem extends Component {
       user,
       intl,
       compact,
+      meeting,
     } = this.props;
 
     if (compact) {
@@ -325,6 +401,8 @@ class UserListItem extends Component {
 
     userNameSub = userNameSub.join(' ');
 
+    const { disablePrivateChat, disableCam, disableMic, lockedLayout, disablePublicChat } = meeting.roomLockSettings;
+
     return (
       <div className={styles.userName}>
         <span className={styles.userNameMain}>
@@ -332,11 +410,15 @@ class UserListItem extends Component {
         </span>
         <span className={styles.userNameSub}>
           {userNameSub}
-          {(user.isLocked) ?
-            <span> {(user.isCurrent? " | " : null)}
+          {(user.isLocked && (disablePrivateChat
+            || disableCam
+            || disableMic
+            || lockedLayout
+            || disablePublicChat)) ?
+            <span> {(user.isCurrent ? ' | ' : null)}
               <Icon iconName='lock' />
               {intl.formatMessage(messages.locked)}
-            </span>: null}
+            </span> : null}
         </span>
       </div>
     );
@@ -404,6 +486,7 @@ class UserListItem extends Component {
         label={action.label}
         defaultMessage={action.label}
         onClick={action.handler.bind(this, ...parameters)}
+        placeInTabOrder={true}
       />
     );
 
diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/text/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/text/component.jsx
index 099b1a430ff8faa5e8bb5a7c1ae94cf64a274ce2..fb581a43729d7e848d05742dcf6a2e297702adb3 100755
--- a/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/text/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/whiteboard/shapes/text/component.jsx
@@ -38,6 +38,7 @@ export default class TextDrawComponent extends React.Component {
       fontStretch: 'normal',
       lineHeight: 'normal',
       fontFamily: 'Arial',
+      whiteSpace: 'pre-wrap',
       wordWrap: 'break-word',
       wordBreak: 'normal',
       textAlign: 'left',
diff --git a/bigbluebutton-html5/imports/ui/services/auth/index.js b/bigbluebutton-html5/imports/ui/services/auth/index.js
index ec00d61c6ed85faf69c4e4f855a765aefe63b207..4ea2e8bc0cd9a0d12870b5e0b33ddbb74d1e5e46 100755
--- a/bigbluebutton-html5/imports/ui/services/auth/index.js
+++ b/bigbluebutton-html5/imports/ui/services/auth/index.js
@@ -4,7 +4,7 @@ import { Tracker } from 'meteor/tracker';
 import Storage from '/imports/ui/services/storage/session';
 
 import Users from '/imports/api/users';
-import { makeCall } from '/imports/ui/services/api';
+import { makeCall, logClient } from '/imports/ui/services/api';
 
 const CONNECTION_TIMEOUT = Meteor.settings.public.app.connectionTimeout;
 
@@ -89,10 +89,22 @@ class Auth {
     }
 
     return new Promise((resolve, reject) => {
-      makeCall('userLogout').then(() => {
-        this.fetchLogoutUrl()
+      const credentialsSnapshot = {
+        meetingId: this.meetingID,
+        requesterUserId: this.userID,
+        requesterToken: this.token,
+      };
+
+      // make sure users who did not connect are not added to the meeting
+      // do **not** use the custom call - it relies on expired data
+      Meteor.call('userLogout', credentialsSnapshot, (error, result) => {
+        if (error) {
+          logClient('error', { error, method: 'userLogout', credentialsSnapshot });
+        } else {
+          this.fetchLogoutUrl()
           .then(this.clearCredentials)
           .then(resolve);
+        }
       });
     });
   };
@@ -109,6 +121,13 @@ class Auth {
 
     return new Promise((resolve, reject) => {
       Tracker.autorun((c) => {
+        if (!(credentials.meetingId && credentials.requesterToken && credentials.requesterUserId)) {
+          return reject({
+            error: 500,
+            description: 'Authentication subscription failed due to missing credentials.',
+          });
+        }
+
         setTimeout(() => {
           c.stop();
           reject({
diff --git a/bigbluebutton-html5/imports/utils/keyCodes.js b/bigbluebutton-html5/imports/utils/keyCodes.js
old mode 100644
new mode 100755
index 555e0ef1bf49204671ed80199b7a03229d2d7f83..5042c536a0124842f2aa14d201ebaeda2db89d7e
--- a/bigbluebutton-html5/imports/utils/keyCodes.js
+++ b/bigbluebutton-html5/imports/utils/keyCodes.js
@@ -4,6 +4,8 @@ export const TAB = 9;
 export const ESCAPE = 27;
 export const ARROW_UP = 38;
 export const ARROW_DOWN = 40;
+export const ARROW_RIGHT = 39;
+export const ARROW_LEFT = 37;
 
 export default {
   SPACE,
@@ -12,4 +14,6 @@ export default {
   ESCAPE,
   ARROW_UP,
   ARROW_DOWN,
+  ARROW_RIGHT,
+  ARROW_LEFT,
 };
diff --git a/bigbluebutton-html5/private/locales/bg_BG.json b/bigbluebutton-html5/private/locales/bg_BG.json
old mode 100644
new mode 100755
index 73ceb36dea69e6899b4f4d1e39c23d5043d55fcd..575eae9805496cceede9d7f63b06d6c4544535f9
--- a/bigbluebutton-html5/private/locales/bg_BG.json
+++ b/bigbluebutton-html5/private/locales/bg_BG.json
@@ -1,16 +1,16 @@
 {
-  "app.home.greeting": "Добре дошли, {name}! Вашата презентация ще започне всеки момент",
+  "app.home.greeting": "Добре дошли, {0}! Вашата презентация ще започне всеки момент",
   "app.userlist.usersTitle": "Потребители",
   "app.userlist.participantsTitle": "Участници",
   "app.userlist.messagesTitle": "Съобщения",
   "app.userlist.presenter": "Лектор",
   "app.userlist.you": "Вие",
   "app.chat.submitLabel": "Изпрати",
-  "app.chat.inputLabel": "Въведи съобщение за {name}",
-  "app.chat.inputPlaceholder": "Съобщение {name}",
+  "app.chat.inputLabel": "Въведи съобщение за {0}",
+  "app.chat.inputPlaceholder": "Съобщение {0}",
   "app.chat.titlePublic": "Общ чат",
-  "app.chat.titlePrivate": "Private Chat with {name}",
-  "app.chat.partnerDisconnected": "{name} has left the meeting",
+  "app.chat.titlePrivate": "Private Chat with {0}",
+  "app.chat.partnerDisconnected": "{0} has left the meeting",
   "app.chat.moreMessages": "More messages below",
   "app.kickMessage": "You have been kicked out of the meeting",
   "app.whiteboard.slideControls.prevSlideLabel": "Previous slide",
@@ -27,7 +27,7 @@
   "app.whiteboard.slideControls.zoomDescrip": "Change the zoom level of the presentation",
   "app.failedMessage": "Apologies, trouble connecting to the server.",
   "app.connectingMessage": "Connecting...",
-  "app.waitingMessage": "Disconnected. Trying to reconnect in {seconds} seconds...",
+  "app.waitingMessage": "Disconnected. Trying to reconnect in {0} seconds...",
   "app.navBar.settingsDropdown.optionsLabel": "Options",
   "app.navBar.settingsDropdown.fullscreenLabel": "Make fullscreen",
   "app.navBar.settingsDropdown.settingsLabel": "Open settings",
@@ -89,7 +89,7 @@
   "app.breakoutJoinConfirmation.confirmDesc": "Join you to the Breakout Room",
   "app.breakoutJoinConfirmation.dismissLabel": "Cancel",
   "app.breakoutJoinConfirmation.dismissDesc": "Closes and rejects Joining the Breakout Room",
-  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {time}",
+  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {0}",
   "app.breakoutWillCloseMessage": "Time ended. Breakout Room will close soon",
   "app.calculatingBreakoutTimeRemaining": "Calculating remaining time...",
   "app.audioModal.microphoneLabel": "Microphone",
diff --git a/bigbluebutton-html5/private/locales/de.json b/bigbluebutton-html5/private/locales/de.json
old mode 100644
new mode 100755
index c6a7cba1b0065f8257be456c8075ceccc7b12f89..78eea4450b2900f2078953426fb9f4cb2c2c0a30
--- a/bigbluebutton-html5/private/locales/de.json
+++ b/bigbluebutton-html5/private/locales/de.json
@@ -1,5 +1,5 @@
 {
-  "app.home.greeting": "Willkommen {name}! Ihre Präsentation startet in Kürze...",
+  "app.home.greeting": "Willkommen {0}! Ihre Präsentation startet in Kürze...",
   "app.userlist.usersTitle": "Teilnehmer",
   "app.userlist.participantsTitle": "Teilnehmer",
   "app.userlist.messagesTitle": "Nachrichten",
@@ -7,17 +7,17 @@
   "app.userlist.you": "Sie",
   "app.userlist.Label": "Teilnehmerliste",
   "app.chat.submitLabel": "Nachricht senden",
-  "app.chat.inputLabel": "Chat-Nachricht eingeben für {name}",
-  "app.chat.inputPlaceholder": "Nachricht an {name}",
+  "app.chat.inputLabel": "Chat-Nachricht eingeben für {0}",
+  "app.chat.inputPlaceholder": "Nachricht an {0}",
   "app.chat.titlePublic": "Öffentlicher Chat",
-  "app.chat.titlePrivate": "Privater Chat mit {name}",
-  "app.chat.partnerDisconnected": "{name} hat die Konferenz verlassen",
-  "app.chat.closeChatLabel": "Schließe {title}",
-  "app.chat.hideChatLabel": "Verstecke {title}",
+  "app.chat.titlePrivate": "Privater Chat mit {0}",
+  "app.chat.partnerDisconnected": "{0} hat die Konferenz verlassen",
+  "app.chat.closeChatLabel": "Schließe {0}",
+  "app.chat.hideChatLabel": "Verstecke {0}",
   "app.chat.moreMessages": "Weitere Nachrichten",
   "app.userlist.menuTitleContext": "verfügbare Optionen",
-  "app.userlist.chatlistitem.unreadSingular": "{count} neue Nachricht",
-  "app.userlist.chatlistitem.unreadPlural": "{count} neue Nachrichten",
+  "app.userlist.chatlistitem.unreadSingular": "{0} neue Nachricht",
+  "app.userlist.chatlistitem.unreadPlural": "{0} neue Nachrichten",
   "app.chat.Label": "Chat",
   "app.chat.emptyLogLabel": "Chat-Log ist leer",
   "app.media.Label": "Medien",
@@ -100,7 +100,7 @@
   "app.submenu.closedCaptions.fontColorLabel": "Schriftfarbe",
   "app.submenu.participants.muteAllLabel": "Alle stummschalten außer Präsentator",
   "app.submenu.participants.lockAllLabel": "Alle Teilnehmer sperren",
-  "app.submenu.participants.lockItemLabel": "Teilnehmer {lockItem}",
+  "app.submenu.participants.lockItemLabel": "Teilnehmer {0}",
   "app.submenu.participants.lockMicDesc": "Deaktiviert das Mikrofon für alle gesperrten Teilnehmer",
   "app.submenu.participants.lockCamDesc": "Deaktiviert die Webcam für alle gesperrten Teilnehmer",
   "app.submenu.participants.lockPublicChatDesc": "Deaktiviert den öffentlichen Chat für alle gesperrten Teilnehmer",
@@ -158,7 +158,7 @@
   "app.breakoutJoinConfirmation.confirmDesc": "Dem Breakout-Raum beitreten",
   "app.breakoutJoinConfirmation.dismissLabel": "Abbrechen",
   "app.breakoutJoinConfirmation.dismissDesc": "Beitritt zum Breakout-Raum ablehnen",
-  "app.breakoutTimeRemainingMessage": "Verbleibende Zeit für den Breakout-Raum: {time}",
+  "app.breakoutTimeRemainingMessage": "Verbleibende Zeit für den Breakout-Raum: {0}",
   "app.breakoutWillCloseMessage": "Zeit abgelaufen. Der Breakout-Raum wird in Kürze geschlossen",
   "app.calculatingBreakoutTimeRemaining": "Berechne die verbleibende Zeit...",
   "app.audioModal.microphoneLabel": "Mit Mikrofon",
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json
index 2ca27397a8024dfd1815a1eb7e5905ea39c20ad4..25ca747596d3e46e643f7fdc4813a21027d3ca96 100755
--- a/bigbluebutton-html5/private/locales/en.json
+++ b/bigbluebutton-html5/private/locales/en.json
@@ -1,5 +1,5 @@
 {
-  "app.home.greeting": "Welcome {name}! Your presentation will begin shortly...",
+  "app.home.greeting": "Welcome {0}! Your presentation will begin shortly...",
   "app.userlist.usersTitle": "Users",
   "app.userlist.participantsTitle": "Participants",
   "app.userlist.messagesTitle": "Messages",
@@ -8,23 +8,25 @@
   "app.userlist.locked": "Locked",
   "app.userlist.Label": "User List",
   "app.chat.submitLabel": "Send Message",
-  "app.chat.inputLabel": "Message input for chat {name}",
-  "app.chat.inputPlaceholder": "Message {name}",
+  "app.chat.inputLabel": "Message input for chat {0}",
+  "app.chat.inputPlaceholder": "Message {0}",
   "app.chat.titlePublic": "Public Chat",
-  "app.chat.titlePrivate": "Private Chat with {name}",
-  "app.chat.partnerDisconnected": "{name} has left the meeting",
-  "app.chat.closeChatLabel": "Close {title}",
-  "app.chat.hideChatLabel": "Hide {title}",
+  "app.chat.titlePrivate": "Private Chat with {0}",
+  "app.chat.partnerDisconnected": "{0} has left the meeting",
+  "app.chat.closeChatLabel": "Close {0}",
+  "app.chat.hideChatLabel": "Hide {0}",
   "app.chat.moreMessages": "More messages below",
   "app.userlist.menuTitleContext": "available options",
-  "app.userlist.chatlistitem.unreadSingular": "{count} New Message",
-  "app.userlist.chatlistitem.unreadPlural": "{count} New Messages",
+  "app.userlist.chatlistitem.unreadSingular": "{0} New Message",
+  "app.userlist.chatlistitem.unreadPlural": "{0} New Messages",
   "app.userlist.menu.chat.label": "Chat",
   "app.userlist.menu.clearStatus.label": "Clear Status",
   "app.userlist.menu.makePresenter.label": "Make Presenter",
   "app.userlist.menu.kickUser.label": "Kick user",
   "app.userlist.menu.muteUserAudio.label": "Mute user",
   "app.userlist.menu.unmuteUserAudio.label": "Unmute user",
+  "app.userlist.useritem.nostatus.arialabel": "{username} {presenter} {you}",
+  "app.userlist.useritem.status.arialabel": "{username} {presenter} {you} current status {status}",
   "app.chat.Label": "Chat",
   "app.chat.emptyLogLabel": "Chat log empty",
   "app.media.Label": "Media",
@@ -43,7 +45,7 @@
   "app.polling.pollingTitle": "Polling Options",
   "app.failedMessage": "Apologies, trouble connecting to the server.",
   "app.connectingMessage": "Connecting...",
-  "app.waitingMessage": "Disconnected. Trying to reconnect in {seconds} seconds...",
+  "app.waitingMessage": "Disconnected. Trying to reconnect in {0} seconds...",
   "app.navBar.settingsDropdown.optionsLabel": "Options",
   "app.navBar.settingsDropdown.fullscreenLabel": "Make fullscreen",
   "app.navBar.settingsDropdown.settingsLabel": "Open settings",
@@ -108,7 +110,7 @@
   "app.submenu.closedCaptions.fontColorLabel": "Font color",
   "app.submenu.participants.muteAllLabel": "Mute all except the presenter",
   "app.submenu.participants.lockAllLabel": "Lock all participants",
-  "app.submenu.participants.lockItemLabel": "Participants {lockItem}",
+  "app.submenu.participants.lockItemLabel": "Participants {0}",
   "app.submenu.participants.lockMicDesc": "Disables the microphone for all locked participants",
   "app.submenu.participants.lockCamDesc": "Disables the webcam for all locked participants",
   "app.submenu.participants.lockPublicChatDesc": "Disables public chat for all locked participants",
@@ -162,7 +164,7 @@
   "app.actionsBar.emojiMenu.thumbsupDesc": "Change your status to thumbs up",
   "app.actionsBar.emojiMenu.thumbsdownLabel": "Thumbs down",
   "app.actionsBar.emojiMenu.thumbsdownDesc": "Change your status to thumbs down",
-  "app.actionsBar.currentStatusDesc": "current status {status}",
+  "app.actionsBar.currentStatusDesc": "current status {0}",
   "app.audioNotification.audioFailedMessage": "Your audio connection failed to connect",
   "app.audioNotification.mediaFailedMessage": "getUserMicMedia failed, Only secure origins are allowed",
   "app.audioNotification.closeLabel": "Close",
@@ -172,7 +174,7 @@
   "app.breakoutJoinConfirmation.confirmDesc": "Join you to the Breakout Room",
   "app.breakoutJoinConfirmation.dismissLabel": "Cancel",
   "app.breakoutJoinConfirmation.dismissDesc": "Closes and rejects Joining the Breakout Room",
-  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {time}",
+  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {0}",
   "app.breakoutWillCloseMessage": "Time ended. Breakout Room will close soon",
   "app.calculatingBreakoutTimeRemaining": "Calculating remaining time...",
   "app.audioModal.microphoneLabel": "Microphone",
diff --git a/bigbluebutton-html5/private/locales/pt_BR.json b/bigbluebutton-html5/private/locales/pt_BR.json
old mode 100644
new mode 100755
index 27c70401b22b530564ee010372d56982e63d2d71..977ecac483925f8d12edb9be9891b470d91fd1bd
--- a/bigbluebutton-html5/private/locales/pt_BR.json
+++ b/bigbluebutton-html5/private/locales/pt_BR.json
@@ -1,16 +1,16 @@
 {
-  "app.home.greeting": "Bem-vindo {name}! Sua aprensentação começará em breve...",
+  "app.home.greeting": "Bem-vindo {0}! Sua aprensentação começará em breve...",
   "app.userlist.usersTitle": "Users",
   "app.userlist.participantsTitle": "Participantes",
   "app.userlist.messagesTitle": "Mensagens",
   "app.userlist.presenter": "Apresentador",
   "app.userlist.you": "Você",
   "app.chat.submitLabel": "Enviar Mensagem",
-  "app.chat.inputLabel": "Campo de mensagem para conversa {name}",
-  "app.chat.inputPlaceholder": "Message {name}",
+  "app.chat.inputLabel": "Campo de mensagem para conversa {0}",
+  "app.chat.inputPlaceholder": "Message {0}",
   "app.chat.titlePublic": "Conversa Publíca",
-  "app.chat.titlePrivate": "Conversa Privada com {name}",
-  "app.chat.partnerDisconnected": "{name} saiu da sala",
+  "app.chat.titlePrivate": "Conversa Privada com {0}",
+  "app.chat.partnerDisconnected": "{0} saiu da sala",
   "app.chat.moreMessages": "Mais mensagens abaixo",
   "app.kickMessage": "Você foi expulso da apresentação",
   "app.whiteboard.slideControls.prevSlideLabel": "Slide Anterior",
@@ -27,7 +27,7 @@
   "app.whiteboard.slideControls.zoomDescrip": "Change the zoom level of the presentation",
   "app.failedMessage": "Desculpas, estamos com problemas para se conectar ao servidor.",
   "app.connectingMessage": "Conectando...",
-  "app.waitingMessage": "Desconectado. Tentando reconectar em {seconds} segundos...",
+  "app.waitingMessage": "Desconectado. Tentando reconectar em {0} segundos...",
   "app.navBar.settingsDropdown.optionsLabel": "Options",
   "app.navBar.settingsDropdown.fullscreenLabel": "Make fullscreen",
   "app.navBar.settingsDropdown.settingsLabel": "Open settings",
@@ -89,7 +89,7 @@
   "app.breakoutJoinConfirmation.confirmDesc": "Join you to the Breakout Room",
   "app.breakoutJoinConfirmation.dismissLabel": "Cancel",
   "app.breakoutJoinConfirmation.dismissDesc": "Closes and rejects Joining the Breakout Room",
-  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {time}",
+  "app.breakoutTimeRemainingMessage": "Breakout Room time remaining: {0}",
   "app.breakoutWillCloseMessage": "Time ended. Breakout Room will close soon",
   "app.calculatingBreakoutTimeRemaining": "Calculating remaining time...",
   "app.audioModal.microphoneLabel": "Microphone",