From b01f14cb330e90a88aeedc810093d61e881e1d0d Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Mon, 17 Nov 2014 12:19:25 +0100 Subject: [PATCH 001/121] Add group chat buddyPicture hover functionality to show call/chat actions. --- src/styles/components/_chat.scss | 36 +++++++++++ static/js/controllers/chatroomcontroller.js | 66 ++++++++++++++------- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss index a4cdcbb9..a442d1ce 100644 --- a/src/styles/components/_chat.scss +++ b/src/styles/components/_chat.scss @@ -434,6 +434,42 @@ &.with_name { // none } + &.with_hoverimage { + .buddyPicture { + overflow: visible; + z-index: initial; + &:hover .buddyInfoActions { + height: 40px; + opacity: 1; + } + } + .buddyInfoActions { + cursor: default; + display: inline-block; + height: 0; + left: 0; + opacity: 0; + overflow: hidden; + position: absolute; + top: 48px; + transition: opacity 0.1s .1s linear, height .4s .1s ease-out; + white-space: nowrap; + z-index: 1; + .btn-group { + display: block; + margin: 0 auto; + width: 55px; + } + .btn-primary { + padding: 2px 4px; + } + .fa { + color: #fff; + font-size: 20px; + line-height: 24px; + } + } + } } .chat { diff --git a/static/js/controllers/chatroomcontroller.js b/static/js/controllers/chatroomcontroller.js index dea0d14b..f82378ef 100644 --- a/static/js/controllers/chatroomcontroller.js +++ b/static/js/controllers/chatroomcontroller.js @@ -23,7 +23,7 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!partials/contactrequest.html', 'text!partials/geolocation.html'], function($, _, moment, templateFileInfo, templateContactRequest, templateGeolocation) { // ChatroomController - return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation) { + return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", "mediaStream", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation, mediaStream) { $scope.outputElement = $element.find(".output"); $scope.inputElement = $element.find(".input"); @@ -50,6 +50,7 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p var fileInfo = $compile(templateFileInfo); var contactRequest = $compile(templateContactRequest); var geoLocation = $compile(templateGeolocation); + var pictureHover = $compile('
'); var knowMessage = { r: {}, @@ -101,6 +102,42 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p } }; + var addPictureHover = function(from, msg, is_self) { + if (msg.picture && !is_self) { + var subscope = $scope.$new(); + subscope.startChat = function() { + $scope.$emit("startchat", from, { + autofocus: true, + restore: true + }); + }; + subscope.doCall = function() { + mediaStream.webrtc.doCall(from); + }; + pictureHover(subscope, function(clonedElement, scope) { + msg.picture.append(clonedElement); + }); + } else { + return; + } + msg.extra_css += "with_hoverimage "; + }; + + var showTitleAndPicture = function(from, msg, is_self) { + if ($scope.isgroupchat) { + msg.title = $(""); + msg.title.html(displayName(from, true)); + msg.extra_css += "with_name "; + var imgSrc = buddyImageSrc(from); + msg.picture = $('
'); + if (imgSrc) { + msg.picture.find("img").attr("src", imgSrc); + } + addPictureHover(from, msg, is_self); + } + }; + + // Make sure that chat links are openend in a new window. $element.on("click", function(event) { var elem = $(event.target); @@ -302,27 +339,16 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p var is_new_message = lastSender !== from; var is_self = from === sessonid; - var extra_css = ""; - var title = null; - var picture = null; - - var showTitleAndPicture = function() { - if ($scope.isgroupchat) { - title = $(""); - title.html(displayName(from, true)); - extra_css += "with_name "; - var imgSrc = buddyImageSrc(from); - picture = $('
'); - if (imgSrc) { - picture.find("img").attr("src", imgSrc); - } - } + var msg = { + extra_css: "", + title: null, + picture: null }; if (is_new_message) { lastSender = from; $scope.showdate(timestamp); - showTitleAndPicture() + showTitleAndPicture(from, msg, is_self); } var strMessage = s.join(" "); @@ -336,9 +362,9 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p } if (is_self) { - extra_css += "is_self"; + msg.extra_css += "is_self"; } else { - extra_css += "is_remote"; + msg.extra_css += "is_remote"; } if (timestamp) { var ts = $('
'); @@ -349,7 +375,7 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p nodes = ts; } } - return $scope.display(strMessage, nodes, extra_css, title, picture); + return $scope.display(strMessage, nodes, msg.extra_css, msg.title, msg.picture); }; From c27aef693aadd43bcd65aaa20e6945b252a06ff6 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Mon, 24 Nov 2014 09:21:38 +0100 Subject: [PATCH 002/121] Move pictureHover dom to a partials template. --- static/js/controllers/chatroomcontroller.js | 4 ++-- static/partials/picturehover.html | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 static/partials/picturehover.html diff --git a/static/js/controllers/chatroomcontroller.js b/static/js/controllers/chatroomcontroller.js index f82378ef..ca36a3a8 100644 --- a/static/js/controllers/chatroomcontroller.js +++ b/static/js/controllers/chatroomcontroller.js @@ -20,7 +20,7 @@ */ "use strict"; -define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!partials/contactrequest.html', 'text!partials/geolocation.html'], function($, _, moment, templateFileInfo, templateContactRequest, templateGeolocation) { +define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!partials/contactrequest.html', 'text!partials/geolocation.html', 'text!partials/picturehover.html'], function($, _, moment, templateFileInfo, templateContactRequest, templateGeolocation, templatePictureHover) { // ChatroomController return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", "mediaStream", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation, mediaStream) { @@ -50,7 +50,7 @@ define(['jquery', 'underscore', 'moment', 'text!partials/fileinfo.html', 'text!p var fileInfo = $compile(templateFileInfo); var contactRequest = $compile(templateContactRequest); var geoLocation = $compile(templateGeolocation); - var pictureHover = $compile('
'); + var pictureHover = $compile(templatePictureHover); var knowMessage = { r: {}, diff --git a/static/partials/picturehover.html b/static/partials/picturehover.html new file mode 100644 index 00000000..80abe643 --- /dev/null +++ b/static/partials/picturehover.html @@ -0,0 +1,11 @@ +
+ +
+ From e1fb7ccf3b6d7b7fd7e44871faea8848c8d22099 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Mon, 24 Nov 2014 10:26:04 +0100 Subject: [PATCH 003/121] Remove font size for btn and use bootstrap class. --- src/styles/components/_chat.scss | 3 +-- static/partials/picturehover.html | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss index a442d1ce..3c86e432 100644 --- a/src/styles/components/_chat.scss +++ b/src/styles/components/_chat.scss @@ -461,11 +461,10 @@ width: 55px; } .btn-primary { - padding: 2px 4px; + padding: 2px 5px; } .fa { color: #fff; - font-size: 20px; line-height: 24px; } } diff --git a/static/partials/picturehover.html b/static/partials/picturehover.html index 80abe643..03954b49 100644 --- a/static/partials/picturehover.html +++ b/static/partials/picturehover.html @@ -1,11 +1,11 @@ From ee5b9af4e16184b6cfaa06e4810dac8fbd8fb414 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Thu, 5 Mar 2015 10:17:24 +0100 Subject: [PATCH 004/121] Fix scss-lint error SelectorDepth. --- html/logo.html | 2 +- src/styles/components/_audiovideo.scss | 3 + src/styles/components/_bar.scss | 74 ++++++++++----------- src/styles/components/_buddylist.scss | 12 ++-- src/styles/components/_contactsmanager.scss | 26 ++++---- src/styles/components/_fileinfo.scss | 15 ++--- src/styles/components/_presentation.scss | 47 +++++++------ src/styles/components/_youtubevideo.scss | 2 +- 8 files changed, 89 insertions(+), 92 deletions(-) diff --git a/html/logo.html b/html/logo.html index ab7b9a7b..22c2622a 100644 --- a/html/logo.html +++ b/html/logo.html @@ -1 +1 @@ -<%define "logo"%><%end%> \ No newline at end of file +<%define "logo"%><%end%> diff --git a/src/styles/components/_audiovideo.scss b/src/styles/components/_audiovideo.scss index 6c3777a0..d5fdcb2d 100644 --- a/src/styles/components/_audiovideo.scss +++ b/src/styles/components/_audiovideo.scss @@ -226,6 +226,7 @@ } .peerActions { + // scss-lint:disable SelectorDepth bottom: 5%; left: 40px; opacity: 0; @@ -350,6 +351,7 @@ } .renderer-smally { + // scss-lint:disable SelectorDepth background: #000; border-right: 0; border-top: 0; @@ -401,6 +403,7 @@ } .renderer-conferencekiosk { + // scss-lint:disable SelectorDepth .remoteVideos { background: $video-background; bottom: 2px; diff --git a/src/styles/components/_bar.scss b/src/styles/components/_bar.scss index f1903eea..bba29bc3 100644 --- a/src/styles/components/_bar.scss +++ b/src/styles/components/_bar.scss @@ -37,42 +37,43 @@ padding: 2px 5px 0 11px; padding: 2px 5px 0 11px; } +} - .logo { - background: $logo no-repeat; - background-size: 100%; - color: #000; - display: inline-block; - font: normal 11px/11px $font-sans-serif; - height: 32px; - text-align: left; - vertical-align: middle; - width: 90px; +.logo { + background: $logo no-repeat; + background-size: 100%; + color: #000; + display: inline-block; + font: normal 11px/11px $font-sans-serif; + height: 32px; + text-align: left; + vertical-align: middle; + width: 90px; - @include breakpt($breakpoint-medium) { - background: $scalable-logo no-repeat center; - height: 46px; - width: 46px; + @include breakpt($breakpoint-medium) { + background: $scalable-logo no-repeat center; + height: 46px; + width: 46px; - span { - display: none; - } + .desc { + display: none; } + } - span { - font-style: italic; - left: 38px; - position: relative; - top: 26px; - } + .desc { + font-style: italic; + left: 38px; + position: relative; + top: 26px; - span a { + a { color: $bar-logo-text-desc; } } } .bar .middle { + // scss-lint:disable SelectorDepth left: 0; pointer-events: none; position: absolute; @@ -178,23 +179,22 @@ color: #fff; } } +} - .btn-mutemicrophone i:before { - content: '\f130'; - } - - .btn-mutemicrophone.active i:before { - content: '\f131'; - } +.btn-mutemicrophone i:before { + content: '\f130'; +} - .btn-mutecamera i:before { - content: '\f06e'; - } +.btn-mutemicrophone.active i:before { + content: '\f131'; +} - .btn-mutecamera.active i:before { - content: '\f070'; - } +.btn-mutecamera i:before { + content: '\f06e'; +} +.btn-mutecamera.active i:before { + content: '\f070'; } @keyframes shakeityeah { diff --git a/src/styles/components/_buddylist.scss b/src/styles/components/_buddylist.scss index 7c12a828..5cc99341 100644 --- a/src/styles/components/_buddylist.scss +++ b/src/styles/components/_buddylist.scss @@ -276,7 +276,7 @@ } } -.buddy .buddysessions { +.buddysessions { margin-bottom: 10px; margin-top: 56px; max-height: 0; @@ -292,20 +292,20 @@ padding-top: 10px; } - ul li { + li { list-style-type: none; margin-bottom: 2px; margin-left: 0; - .btn-group { - visibility: hidden; - } - &:hover .btn-group { visibility: visible; } } + .btn-group { + visibility: hidden; + } + .currentsession .buddy3 { font-weight: bold; } diff --git a/src/styles/components/_contactsmanager.scss b/src/styles/components/_contactsmanager.scss index f216ea58..e7bb7157 100644 --- a/src/styles/components/_contactsmanager.scss +++ b/src/styles/components/_contactsmanager.scss @@ -68,22 +68,22 @@ .table { margin-bottom: 0; + } - tr:first-child td { - border-top: 0; - } + tr:first-child td { + border-top: 0; + } - .name { - text-align: left; - vertical-align: middle; - width: 40%; - } + .name { + text-align: left; + vertical-align: middle; + width: 40%; + } - .action { - padding-right: 15px; - text-align: right; - vertical-align: middle; - } + .action { + padding-right: 15px; + text-align: right; + vertical-align: middle; } } diff --git a/src/styles/components/_fileinfo.scss b/src/styles/components/_fileinfo.scss index 1a145e0f..c11a5a57 100644 --- a/src/styles/components/_fileinfo.scss +++ b/src/styles/components/_fileinfo.scss @@ -37,17 +37,14 @@ .file-info-bg { bottom: 0; + color: $fileinfo-icon-background-color; + font-size: 20em; left: 41px; overflow: hidden; position: absolute; right: 0; - top: -17px; + top: -82px; z-index: 2; - - .#{$fa-css-prefix} { - color: $fileinfo-icon-background-color; - font-size: 20em; - } } .actions { @@ -64,10 +61,8 @@ border: 1px solid $fileinfo-border-remote; .file-info-bg { - .#{$fa-css-prefix} { - color: $fileinfo-icon-background-color-remote; - font-size: 20em; - } + color: $fileinfo-icon-background-color-remote; + font-size: 20em; } } diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index e1c227c9..ffe8ad56 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -27,30 +27,6 @@ top: 0; } -.presentationpane .welcome { - padding: 0; -} - -.presentationpane .welcome h1 { - white-space: normal; -} - -.presentationpane .welcome button { - margin-top: 30px; -} - -.presentationpane .welcome .progress span { - text-shadow: none; -} - -.presentationpane .welcome .progress .download-info { - color: $text-color; - left: 0; - position: absolute; - text-shadow: 1px 1px 1px #fff; - width: 100%; -} - .mainPresentation #presentation { display: block; } @@ -62,6 +38,26 @@ position: absolute; right: 0; top: 0; + + .welcome { + padding: 0; + + .btn { + margin-top: 30px; + } + } + + h1 { + white-space: normal; + } + + .download-info { + color: $text-color; + left: 0; + position: absolute; + text-shadow: 1px 1px 1px #fff; + width: 100%; + } } .presentationpane { @@ -165,14 +161,17 @@ } .presentation .thumbnail .caption .size { + // scss-lint:disable SelectorDepth font-size: 10px; } .presentation .thumbnail .caption .progress { + // scss-lint:disable SelectorDepth position: relative; } .presentation .thumbnail .caption .download-info { + // scss-lint:disable SelectorDepth bottom: 0; color: $text-color; left: 0; diff --git a/src/styles/components/_youtubevideo.scss b/src/styles/components/_youtubevideo.scss index e0b99305..452cf135 100644 --- a/src/styles/components/_youtubevideo.scss +++ b/src/styles/components/_youtubevideo.scss @@ -112,7 +112,7 @@ width: 100%; } -.youtubevideo .overlaybar-content form .overlaybar-buttons { +.youtubevideo .overlaybar-content .overlaybar-buttons { position: absolute; right: 23px; top: 6px; From c2fe1bf1a2e4b13d54b9c96c43262f899ee4974a Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 18 Mar 2015 10:19:51 +0100 Subject: [PATCH 005/121] Make text.js available in base to allow early plugins to load text resources. --- static/js/base.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/js/base.js b/static/js/base.js index b24dd8ca..730ee3fa 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -32,4 +32,5 @@ define([ // Helper module to put non dependency base libraries together. 'rAF', 'humanize', 'sha', - 'sjcl'], function() {}); + 'sjcl', + 'text'], function() {}); From 63324502c31604fe11b682bf77aefaaad131a5ff Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 31 Mar 2015 18:14:20 +0200 Subject: [PATCH 006/121] Update jed.js to 1.1.0 --- package.json | 2 +- src/i18n/helpers/po2json | 2 +- static/js/libs/jed.js | 80 ++++++++++++++++++------------- static/js/services/translation.js | 16 +++---- 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index c4839aca..167ee1f8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "dependencies": { "autoprefixer": ">= 3.1.0", - "po2json": ">= 0.3.0", + "po2json": ">= 0.4.1", "jshint": ">= 2.5.5" } } diff --git a/src/i18n/helpers/po2json b/src/i18n/helpers/po2json index c23f6572..f46f00a6 100755 --- a/src/i18n/helpers/po2json +++ b/src/i18n/helpers/po2json @@ -7,7 +7,7 @@ var po2json = require('po2json'), assert.equal(argv.length, 4, 'Usage: po2json '); -var result = po2json.parseFileSync(argv[2], { stringify: true, format: 'jed', pretty: false }), +var result = po2json.parseFileSync(argv[2], { stringify: true, format: 'jed1.x', pretty: false }), stream = fs.createWriteStream(argv[3], {}); stream.write(result); diff --git a/static/js/libs/jed.js b/static/js/libs/jed.js index 4e958e87..87074f33 100644 --- a/static/js/libs/jed.js +++ b/static/js/libs/jed.js @@ -1,8 +1,7 @@ +/** + * @preserve jed.js 1.1.0 https://github.com/SlexAxton/Jed + */ /* -jed.js -v0.5.4 - -https://github.com/SlexAxton/Jed ----------- A gettext compatible i18n library for modern JavaScript Applications @@ -91,7 +90,9 @@ in order to offer easy upgrades -- jsgettext.berlios.de } }, // The default domain if one is missing - "domain" : "messages" + "domain" : "messages", + // enable debug mode to log untranslated strings to the console + "debug" : false }; // Mix in the sent options with the default options @@ -136,7 +137,7 @@ in order to offer easy upgrades -- jsgettext.berlios.de }, fetch : function ( sArr ) { if ( {}.toString.call( sArr ) != '[object Array]' ) { - sArr = [].slice.call(arguments); + sArr = [].slice.call(arguments, 0); } return ( sArr && sArr.length ? Jed.sprintf : function(x){ return x; } )( this._i18n.dcnpgettext(this._domain, this._context, this._key, this._pkey, this._val), @@ -221,9 +222,6 @@ in order to offer easy upgrades -- jsgettext.berlios.de // isn't explicitly passed in domain = domain || this._textdomain; - // Default the value to the singular case - val = typeof val == 'undefined' ? 1 : val; - var fallback; // Handle special cases @@ -257,23 +255,34 @@ in order to offer easy upgrades -- jsgettext.berlios.de throw new Error('No translation key found.'); } - // Handle invalid numbers, but try casting strings for good measure - if ( typeof val != 'number' ) { - val = parseInt( val, 10 ); - - if ( isNaN( val ) ) { - throw new Error('The number that was passed in is not a number.'); - } - } - var key = context ? context + Jed.context_delimiter + singular_key : singular_key, locale_data = this.options.locale_data, dict = locale_data[ domain ], - pluralForms = dict[""].plural_forms || (locale_data.messages || this.defaults.locale_data.messages)[""].plural_forms, - val_idx = getPluralFormFunc(pluralForms)(val) + 1, + defaultConf = (locale_data.messages || this.defaults.locale_data.messages)[""], + pluralForms = dict[""].plural_forms || dict[""]["Plural-Forms"] || dict[""]["plural-forms"] || defaultConf.plural_forms || defaultConf["Plural-Forms"] || defaultConf["plural-forms"], val_list, res; + var val_idx; + if (val === undefined) { + // No value passed in; assume singular key lookup. + val_idx = 0; + + } else { + // Value has been passed in; use plural-forms calculations. + + // Handle invalid numbers, but try casting strings for good measure + if ( typeof val != 'number' ) { + val = parseInt( val, 10 ); + + if ( isNaN( val ) ) { + throw new Error('The number that was passed in is not a number.'); + } + } + + val_idx = getPluralFormFunc(pluralForms)(val); + } + // Throw an error if a domain isn't found if ( ! dict ) { throw new Error('No domain named `' + domain + '` could be found.'); @@ -283,20 +292,25 @@ in order to offer easy upgrades -- jsgettext.berlios.de // If there is no match, then revert back to // english style singular/plural with the keys passed in. - if ( ! val_list || val_idx >= val_list.length ) { + if ( ! val_list || val_idx > val_list.length ) { if (this.options.missing_key_callback) { - this.options.missing_key_callback(key); + this.options.missing_key_callback(key, domain); + } + res = [ singular_key, plural_key ]; + + // collect untranslated strings + if (this.options.debug===true) { + console.log(res[ getPluralFormFunc(pluralForms)( val ) ]); } - res = [ null, singular_key, plural_key ]; - return res[ getPluralFormFunc(pluralForms)( val ) + 1 ]; + return res[ getPluralFormFunc()( val ) ]; } res = val_list[ val_idx ]; // This includes empty strings on purpose if ( ! res ) { - res = [ null, singular_key, plural_key ]; - return res[ getPluralFormFunc(pluralForms)( val ) + 1 ]; + res = [ singular_key, plural_key ]; + return res[ getPluralFormFunc()( val ) ]; } return res; } @@ -600,15 +614,15 @@ performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { var $0 = $$.length - 1; switch (yystate) { -case 1: return { type : 'GROUP', expr: $$[$0-1] }; +case 1: return { type : 'GROUP', expr: $$[$0-1] }; break; -case 2:this.$ = { type: 'TERNARY', expr: $$[$0-4], truthy : $$[$0-2], falsey: $$[$0] }; +case 2:this.$ = { type: 'TERNARY', expr: $$[$0-4], truthy : $$[$0-2], falsey: $$[$0] }; break; case 3:this.$ = { type: "OR", left: $$[$0-2], right: $$[$0] }; break; case 4:this.$ = { type: "AND", left: $$[$0-2], right: $$[$0] }; break; -case 5:this.$ = { type: 'LT', left: $$[$0-2], right: $$[$0] }; +case 5:this.$ = { type: 'LT', left: $$[$0-2], right: $$[$0] }; break; case 6:this.$ = { type: 'LTE', left: $$[$0-2], right: $$[$0] }; break; @@ -622,11 +636,11 @@ case 10:this.$ = { type: 'EQ', left: $$[$0-2], right: $$[$0] }; break; case 11:this.$ = { type: 'MOD', left: $$[$0-2], right: $$[$0] }; break; -case 12:this.$ = { type: 'GROUP', expr: $$[$0-1] }; +case 12:this.$ = { type: 'GROUP', expr: $$[$0-1] }; break; -case 13:this.$ = { type: 'VAR' }; +case 13:this.$ = { type: 'VAR' }; break; -case 14:this.$ = { type: 'NUM', val: Number(yytext) }; +case 14:this.$ = { type: 'NUM', val: Number(yytext) }; break; } }, @@ -912,7 +926,7 @@ next:function () { if (this._input === "") { return this.EOF; } else { - this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), + this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), {text: "", token: null, line: this.yylineno}); } }, diff --git a/static/js/services/translation.js b/static/js/services/translation.js index 2641e85d..9bb7d3ee 100644 --- a/static/js/services/translation.js +++ b/static/js/services/translation.js @@ -30,25 +30,25 @@ define(["jed", "underscore"], function(Jed, _) { this._ = _.bind(function() { if (domain && context) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 0); var r = i18n.translate(singular).onDomain(domain).withContext(context); return r.fetch.apply(r, vars); }, this); } else if (domain) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 0); var r = i18n.translate(singular).onDomain(domain); return r.fetch.apply(r, vars); }, this); } else if (context) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 0); var r = i18n.translate(singular).withContext(context); return r.fetch.apply(r, vars); }, this); } else { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 0); var r = i18n.translate(singular); return r.fetch.apply(r, vars); }, this); @@ -59,25 +59,25 @@ define(["jed", "underscore"], function(Jed, _) { this._n = _.bind(function() { if (domain && context) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 2); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).onDomain(domain).withContext(context).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else if (domain) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 2); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).onDomain(domain).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else if (context) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 2); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).withContext(context).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 2); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }) From f7b0f4228cdd1dc4ba3505b8dde7aa62a1bc2851 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 31 Mar 2015 18:15:16 +0200 Subject: [PATCH 007/121] Update translations to reflect new jed api. --- src/i18n/messages-de.po | 2 +- src/i18n/messages-ja.po | 2 +- src/i18n/messages-ko.po | 2 +- src/i18n/messages-zh-cn.po | 2 +- src/i18n/messages-zh-tw.po | 2 +- src/i18n/messages.pot | 2 +- static/translation/messages-de.json | 2 +- static/translation/messages-ja.json | 2 +- static/translation/messages-ko.json | 2 +- static/translation/messages-zh-cn.json | 2 +- static/translation/messages-zh-tw.json | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/i18n/messages-de.po b/src/i18n/messages-de.po index 9fc5e658..6fb3fd27 100644 --- a/src/i18n/messages-de.po +++ b/src/i18n/messages-de.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: 2015-02-18 14:49+0100\n" "Last-Translator: Simon Eisenmann \n" "Language-Team: struktur AG \n" diff --git a/src/i18n/messages-ja.po b/src/i18n/messages-ja.po index beaa7a57..775942bb 100644 --- a/src/i18n/messages-ja.po +++ b/src/i18n/messages-ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: 2014-04-23 22:25+0100\n" "Last-Translator: Curt Frisemo \n" "Language-Team: Curt Frisemo \n" diff --git a/src/i18n/messages-ko.po b/src/i18n/messages-ko.po index 596e8133..86758626 100644 --- a/src/i18n/messages-ko.po +++ b/src/i18n/messages-ko.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: 2014-04-13 20:30+0900\n" "Last-Translator: Curt Frisemo \n" "Language-Team: Curt Frisemo \n" diff --git a/src/i18n/messages-zh-cn.po b/src/i18n/messages-zh-cn.po index abb8904b..eeeffda3 100644 --- a/src/i18n/messages-zh-cn.po +++ b/src/i18n/messages-zh-cn.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: 2014-05-21 09:54+0800\n" "Last-Translator: Michael P.\n" "Language-Team: Curt Frisemo \n" diff --git a/src/i18n/messages-zh-tw.po b/src/i18n/messages-zh-tw.po index 0d4abd54..267d08dc 100644 --- a/src/i18n/messages-zh-tw.po +++ b/src/i18n/messages-zh-tw.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: 2014-05-21 09:55+0800\n" "Last-Translator: Michael P.\n" "Language-Team: Curt Frisemo \n" diff --git a/src/i18n/messages.pot b/src/i18n/messages.pot index b856e386..226649d7 100644 --- a/src/i18n/messages.pot +++ b/src/i18n/messages.pot @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-02-18 14:46+0100\n" +"POT-Creation-Date: 2015-03-31 18:11+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/static/translation/messages-de.json b/static/translation/messages-de.json index 3eca0fb4..5b96a499 100644 --- a/static/translation/messages-de.json +++ b/static/translation/messages-de.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=2; plural=(n != 1)"},"Your audio level":[null,"Ihr Audio-Pegel"],"Standard view":[null,"Standardansicht"],"Large view":[null,"Große Videos"],"Kiosk view":[null,"Kiosk-Ansicht"],"Auditorium":[null,"Auditorium"],"Start chat":[null,"Chat starten"],"Start video call":[null,"Video-Anruf starten"],"Start audio conference":[null,"Audio-Konferenz starten"],"No one else here":[null,"Niemand sonst hier"],"Take":[null,"Los"],"Retake":[null,"Nochmal"],"Cancel":[null,"Abbrechen"],"Set as Profile Picture":[null,"Als Bild setzen"],"Take picture":[null,"Bild machen"],"Upload picture":[null,"Bild hochladen"],"Waiting for camera":[null,"Warte auf die Kamera"],"Picture":[null,"Bild"],"The file couldn't be read.":[null,"Die Datei konnte nicht geöffnet werden."],"The file is not an image.":[null,"Diese Datei ist kein Bild."],"The file is too large. Max. %d MB.":[null,"Diese Datei ist zu groß. Max. %d MB."],"Select file":[null,"Datei wählen"],"Chat sessions":[null,"Chat-Sitzungen"],"Room chat":[null,"Raum-Chat"],"Peer to peer":[null,"Peer-to-peer"],"Close chat":[null,"Chat schließen"],"Upload files":[null,"Dateien hochladen"],"Share my location":[null,"Meinen Standort teilen"],"Clear chat":[null,"Chat löschen"],"is typing...":[null," schreibt gerade..."],"has stopped typing...":[null," schreibt nicht mehr..."],"Type here to chat...":[null,"Nachricht hier eingeben..."],"Send":[null,"Senden"],"Accept":[null,"Akzeptieren"],"Reject":[null,"Abweisen"],"You have no contacts.":[null,"Sie haben keine Kontakte."],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[null,"Betreten Sie einen Raum und klicken dann auf das Stern-Symbol eines anderen Nutzers um eine Kontaktanfrage zu starten."],"Edit contact":[null,"Kontakt bearbeiten"],"Edit":[null,"Bearbeiten"],"Name":[null,"Name"],"Remove":[null,"Entfernen"],"Refresh":[null,"Aktualisieren"],"Save":[null,"Speichern"],"Close":[null,"Schließen"],"File sharing":[null,"Datei-Austausch"],"File is no longer available":[null,"Datei ist nicht mehr verfügbar"],"Download":[null,"Laden"],"Open":[null,"Öffnen"],"Unshare":[null,"Zurückziehen"],"Retry":[null,"Nochmal versuchen"],"Download failed.":[null,"Fehler beim Download."],"Share a YouTube video":[null,"Ein YouTube Video teilen"],"Share a file as presentation":[null,"Datei als Präsentation teilen."],"Share your screen":[null,"Bildschirm freigeben"],"Chat":[null,"Chat"],"Contacts":[null,"Kontakte"],"Mute microphone":[null,"Mikrofon abschalten"],"Turn camera off":[null,"Kamera abschalten"],"Settings":[null,"Einstellungen"],"Loading presentation ...":[null,"Präsentation wird geladen..."],"Please upload a document":[null,"Bitte Dokument hochladen"],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[null,"Das Dokument wird mit allen Gesprächsteilnehmern geteilt. Unterstützt werden PDF und OpenDocument Dateien."],"Upload":[null,"Hochladen"],"You can drag files here too.":[null,"Sie können Dateien auch hierhin ziehen."],"Presentation controls":[null,"Präsentations-Steuerung"],"Prev":[null,"Zurück"],"Next":[null,"Vor"],"Change room":[null,"Raum wechseln"],"Room":[null,"Raum"],"Leave room":[null,"Raum verlassen"],"Main":[null,"Standard"],"Current room":[null,"Raum"],"Screen sharing options":[null,"Optionen für Bildschirmfreigabe"],"Fit screen.":[null,"Bildschirm einpassen."],"Profile":[null,"Profil"],"Your name":[null,"Ihr Name"],"Your picture":[null,"Ihr Bild"],"Status message":[null,"Status Nachricht"],"What's on your mind?":[null,"Was machen Sie gerade?"],"Your picture, name and status message identify yourself in calls, chats and rooms.":[null,"Ihr Bild, Name und Status Nachricht repräsentiert Sie in Anrufen, Chats und Räumen."],"Your ID":[null,"Ihre ID"],"Register":[null,"Registrieren"],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[null,"Mit Zertifikat angemeldet. Melden Sie sich ab indem Sie das Zertifikat aus dem Browser entfernen."],"Sign in":[null,"Anmelden"],"Create an account":[null,"Registrieren"],"Sign out":[null,"Abmelden"],"Manage account":[null,"Konto verwalten"],"Media":[null,"Kamera / Mikrofon"],"Microphone":[null,"Mikrofon"],"Camera":[null,"Kamera"],"Video quality":[null,"Video-Qualität"],"Low":[null,"Gering"],"High":[null,"Hoch"],"HD":[null,"HD"],"Full HD":[null,"Full HD"],"General":[null,"Allgemein"],"Language":[null,"Sprache"],"Language changes become active on reload.":[null,"Sie müssen die Seite neu laden, um die Spracheinstellung zu übernehmen."],"Default room":[null,"Standard Raum"],"Set alternative room to join at start.":[null," Raum wird beim Start automatisch betreten."],"Desktop notification":[null,"Desktop-Benachrichtigung"],"Enable":[null,"Aktivieren"],"Denied - check your browser settings":[null,"Verweigert - prüfen Sie die Browser-Einstellungen"],"Allowed":[null,"Aktiviert"],"Advanced settings":[null,"Erweiterte Einstellungen"],"Play audio on same device as selected microphone":[null,"Audioausgabe auf dem zum Mikrofon gehörenden Gerät"],"Experimental AEC":[null,"Experimentelle AEC"],"Experimental AGC":[null,"Experimentelle AGC"],"Experimental noise suppression":[null,"Experimentelle Geräuschunterdrückung"],"Max video frame rate":[null,"Max. Bildwiederholrate"],"auto":[null,"auto"],"Send stereo audio":[null,"Audio in Stereo übertragen"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[null,"Um Stereo zu übertragen wird die Echo-Unterdrückung deaktiviert. Nur aktivieren wenn das Eingangssignal Stereo ist."],"Detect CPU over use":[null,"CPU-Überlast erkennen"],"Automatically reduces video quality as needed.":[null,"Reduziert die Videoqualität wenn nötig."],"Optimize for high resolution video":[null,"Für hohe Auflösung optimieren"],"Reduce video noise":[null,"Rauschen reduzieren"],"Enable experiments":[null,"Experimente aktivieren"],"Show advanced settings":[null,"Erweiterte Einstellungen anzeigen"],"Hide advanced settings":[null,"Erweiterte Einstellungen ausblenden"],"Remember settings":[null,"Einstellungen merken"],"Your ID will still be kept - press the log out button above to delete the ID.":[null,"Ihre ID bleibt dennoch gespeichert. Klicken Sie Ausloggen weiter oben um die ID zu löschen."],"Room link":[null,"Raum-Link"],"Invite by Email":[null,"Per E-Mail einladen"],"Invite with Facebook":[null,"Mit Facebook einladen"],"Invite with Twitter":[null,"Mit Twitter einladen"],"Invite with Google Plus":[null,"Mit Google Plus einladen"],"Invite with XING":[null,"Mit XING einladen"],"Initializing":[null,"Initialisiere"],"Online":[null,"Online"],"Calling":[null,"Verbinde mit"],"Hangup":[null,"Auflegen"],"In call with":[null,"Verbunden mit"],"Conference with":[null,"Konferenz mit"],"Your are offline":[null,"Sie sind offline"],"Go online":[null,"Online gehen"],"Connection interrupted":[null,"Verbindung unterbrochen"],"An error occured":[null,"Ein Fehler ist aufgetreten"],"Incoming call":[null,"Eingehender Anruf"],"from":[null,"von"],"Accept call":[null,"Anruf annehmen"],"Waiting for camera/microphone access":[null,"Warte auf Kamera/Mikrofon Freigabe"],"Checking camera and microphone access.":[null,"Prüfe Zugriff auf Kamera und Mikrofon."],"Please allow access to your camera and microphone.":[null,"Bitte gestatten Sie den Zugriff auf Ihre Kamera und Mikrofon."],"Camera / microphone access required.":[null,"Kamera / Mikrofon Zugriff wird benötigt."],"Please check your browser settings and allow camera and microphone access for this site.":[null,"Bitte prüfen Sie Ihre Browser-Einstellungen und gestatten Sie den Zugriff auf Kamera und Mikrofon für diese Seite."],"Skip check":[null,"Überspringen"],"Click here for help (Google Chrome).":[null,"Hier klicken für weitere Infos (Google Chrome)."],"Please set your user details and settings.":[null,"Bitte vervollständigen Sie Ihre Daten und Einstellungen."],"Enter a room name":[null,"Raum eingeben"],"Random room name":[null,"Zufälliger Raum"],"Enter room":[null,"Raum betreten"],"Enter the name of an existing room. You can create new rooms when you are signed in.":[null,"Geben Sie den Namen eines existierenden Raums ein. Melden Sie sich an um eigene Räume zu erstellen."],"Room history":[null,"Raum-Verlauf"],"Please sign in.":[null,"Bitte melden Sie sich an."],"Videos play simultaneously for everyone in this call.":[null,"Das Video wird bei allen Gesprächsteilnehmern angezeigt."],"YouTube URL":[null,"YouTube URL"],"Share":[null,"Teilen"],"Could not load YouTube player API, please check your network / firewall settings.":[null,"Es konnte keine Verbindung zu YouTube aufgebaut werden. Bitte prüfen Sie Ihre Internetverbindung / Firewall."],"Currently playing":[null,"Aktuelles Video"],"YouTube controls":[null,"YouTube Steuerung"],"YouTube video to share":[null,"YouTube Video teilen"],"Peer to peer chat active.":[null,"Peer-to-peer Chat ist aktiv."],"Peer to peer chat is now off.":[null,"Peer-to-peer Chat ist nicht mehr aktiv."]," is now offline.":[null," ist jetzt offline."]," is now online.":[null," ist jetzt online."],"You share file:":[null,"Sie geben eine Datei frei:"],"Incoming file:":[null,"Eingehende Datei:"],"You shared your location:":[null,"Sie haben Ihren Standort geteilt:"],"Location received:":[null,"Standort erhalten:"],"You accepted the contact request.":[null,"Sie haben die Kontaktanfrage angenommen."],"You rejected the contact request.":[null,"Sie haben die Kontaktanfrage abgelehnt."],"You sent a contact request.":[null,"Sie haben eine Kontaktanfrage gesendet."],"Your contact request was accepted.":[null,"Ihre Kontaktanfrage wurde angenommen."],"Incoming contact request.":[null,"Kontaktanfrage erhalten."],"Your contact request was rejected.":[null,"Ihre Kontaktanfrage wurde abgelehnt."],"Edit Contact":[null,"Kontakt bearbeiten"],"Close this window and disconnect?":[null,"Fenster schließen und die Verbindung trennen?"],"Contacts Manager":[null,"Kontakte"],"Restart required to apply updates. Click ok to restart now.":[null,"Es stehen Updates zur Verfügung. Klicken Sie Ok um die Anwendung neu zu starten."],"Failed to access camera/microphone.":[null,"Fehler beim Zugriff auf die Kamera / das Mikrofon."],"Failed to establish peer connection.":[null,"Fehler beim Verbindungsaufbau."],"We are sorry but something went wrong. Boo boo.":[null,"Leider ist ein Fehler aufgetreten. Buhuhu."],"Oops":[null,"Hoppla"],"Peer connection failed. Check your settings.":[null,"Verbindung fehlgeschlagen. Überprüfen Sie Ihre Einstellungen."],"User hung up because of error.":[null,"Teilnehmer hat aufgelegt, da ein Fehler aufgetreten ist."]," is busy. Try again later.":[null," ist in einem Gespräch. Probieren Sie es später."]," rejected your call.":[null," hat Ihren Anruf abgelehnt."]," does not pick up.":[null," nimmt nicht ab."]," tried to call you":[null," hat versucht Sie anzurufen"]," called you":[null," hat Sie angerufen"],"Your browser is not supported. Please upgrade to a current version.":[null,"Ihr Browser wird nicht unterstützt. Bitte aktualisieren Sie auf eine aktuelle Version."],"Your browser does not support WebRTC. No calls possible.":[null,"Ihr Browser unterstützt kein WebRTC. Keine Anrufe möglich."],"Chat with":[null,"Chat mit"],"Message from ":[null,"Nachricht von "],"You are now in room %s ...":[null,"Sie sind nun im Raum %s ..."],"Your browser does not support file transfer.":[null,"Mit Ihrem Browser können keine Dateien übertragen werden."],"Could not load PDF: Please make sure to select a PDF document.":[null,"PDF konnte nicht geladen werden - Bitte stellen Sie sicher, dass Sie ein gültiges PDF-Dokument ausgewählt haben."],"Could not load PDF: Missing PDF file.":[null,"Das PDF konnte nicht geladen werden: Datei fehlt."],"An error occurred while loading the PDF (%s).":[null,"Beim Laden des PDF's ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF.":[null,"Beim Laden des PDF ist ein unbekannter Fehler aufgetreten."],"An error occurred while loading the PDF page (%s).":[null,"Beim Laden der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF page.":[null,"Beim Laden der PDF-Seite ist ein unbekannter Fehler aufgetreten (%s)."],"An error occurred while rendering the PDF page (%s).":[null,"Beim Anzeigen der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while rendering the PDF page.":[null,"Beim Anzeigen der PDF-Seite ist ein ubekannter Fehler aufgetreten."],"Only PDF documents and OpenDocument files can be shared at this time.":[null,"Es können nur Dokumente im PDF oder OpenDocument-Format als Präsentation verwendet werden."],"Failed to start screen sharing (%s).":[null,"Die Bildschirmfreigabe konnte nicht gestartet werden (%s)."],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":[null,"Die Berechtigung für die Bildschirmaufzeichnung wurde verweigert. Bitte stellen Sie sicher die Unterstützung für Bildschimaufzeichnung in Ihrem Browser aktiviert ist. Kopieren Sie dazu chrome://flags/#enable-usermedia-screen-capture und öffnen Sie diese Adresse in Ihrem Browser. Aktivieren Sie die oberste Einstellung und starten dann den Browser neu. Anschließend können Sie die Bildschirmfreigabe benutzen."],"Permission to start screen sharing was denied.":[null,"Die Berechtigung den Bildschirm freizugeben wurde verweigert."],"Use browser language":[null,"Browsereinstellung"],"Meet with me here:":[null,"Meeting:"],"Room name":[null,"Raum-Name"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[null,"Unbekanntes URL-Format. Bitte geben Sie eine gültige YouTube URL ein."],"Error":[null,"Fehler"],"Hint":[null,"Hinweis"],"Please confirm":[null,"Bitte bestätigen"],"More information required":[null,"Weitere Informationen nötig"],"Ok":[null,"OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[null,"Die Bildschrimfreigabe benötigt eine Browser-Erweiterung. Bitte fügen Sie die \"Spreed WebRTC screen sharing\" Erweiterung zu Chrome hinzu."],"Access code required":[null,"Bitte Zugriffscode eingeben"],"Access denied":[null,"Zugriff verweigert"],"Please provide a valid access code.":[null,"Bitte geben Sie einen gültigen Zugriffscode ein."],"Failed to verify access code. Check your Internet connection and try again.":[null,"Der Zugriffscode konnte nicht überprueft werden. Bitte prüfen Sie Ihre Internetverbindung."],"PIN for room %s is now '%s'.":[null,"PIN für Raum %s ist jetzt '%s'."],"PIN lock has been removed from room %s.":[null,"Raum %s ist nicht mehr PIN-geschützt."],"Enter the PIN for room %s":[null,"Geben Sie die PIN für Raum %s ein"],"Please sign in to create rooms.":[null,"Bitte melden Sie sich an um Räume zu erstellen."],"and %s":[null,"und %s"],"and %d others":[null,"und %d weiteren"],"User":[null,"Teilnehmer"],"Someone":[null,"Unbekannt"],"Me":[null,"Ich"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=2; plural=(n != 1)"},"Your audio level":["Ihr Audio-Pegel"],"Standard view":["Standardansicht"],"Large view":["Große Videos"],"Kiosk view":["Kiosk-Ansicht"],"Auditorium":["Auditorium"],"Start chat":["Chat starten"],"Start video call":["Video-Anruf starten"],"Start audio conference":["Audio-Konferenz starten"],"No one else here":["Niemand sonst hier"],"Take":["Los"],"Retake":["Nochmal"],"Cancel":["Abbrechen"],"Set as Profile Picture":["Als Bild setzen"],"Take picture":["Bild machen"],"Upload picture":["Bild hochladen"],"Waiting for camera":["Warte auf die Kamera"],"Picture":["Bild"],"The file couldn't be read.":["Die Datei konnte nicht geöffnet werden."],"The file is not an image.":["Diese Datei ist kein Bild."],"The file is too large. Max. %d MB.":["Diese Datei ist zu groß. Max. %d MB."],"Select file":["Datei wählen"],"Chat sessions":["Chat-Sitzungen"],"Room chat":["Raum-Chat"],"Peer to peer":["Peer-to-peer"],"Close chat":["Chat schließen"],"Upload files":["Dateien hochladen"],"Share my location":["Meinen Standort teilen"],"Clear chat":["Chat löschen"],"is typing...":[" schreibt gerade..."],"has stopped typing...":[" schreibt nicht mehr..."],"Type here to chat...":["Nachricht hier eingeben..."],"Send":["Senden"],"Accept":["Akzeptieren"],"Reject":["Abweisen"],"You have no contacts.":["Sie haben keine Kontakte."],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":["Betreten Sie einen Raum und klicken dann auf das Stern-Symbol eines anderen Nutzers um eine Kontaktanfrage zu starten."],"Edit contact":["Kontakt bearbeiten"],"Edit":["Bearbeiten"],"Name":["Name"],"Remove":["Entfernen"],"Refresh":["Aktualisieren"],"Save":["Speichern"],"Close":["Schließen"],"File sharing":["Datei-Austausch"],"File is no longer available":["Datei ist nicht mehr verfügbar"],"Download":["Laden"],"Open":["Öffnen"],"Unshare":["Zurückziehen"],"Retry":["Nochmal versuchen"],"Download failed.":["Fehler beim Download."],"Share a YouTube video":["Ein YouTube Video teilen"],"Share a file as presentation":["Datei als Präsentation teilen."],"Share your screen":["Bildschirm freigeben"],"Chat":["Chat"],"Contacts":["Kontakte"],"Mute microphone":["Mikrofon abschalten"],"Turn camera off":["Kamera abschalten"],"Settings":["Einstellungen"],"Loading presentation ...":["Präsentation wird geladen..."],"Please upload a document":["Bitte Dokument hochladen"],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":["Das Dokument wird mit allen Gesprächsteilnehmern geteilt. Unterstützt werden PDF und OpenDocument Dateien."],"Upload":["Hochladen"],"You can drag files here too.":["Sie können Dateien auch hierhin ziehen."],"Presentation controls":["Präsentations-Steuerung"],"Prev":["Zurück"],"Next":["Vor"],"Change room":["Raum wechseln"],"Room":["Raum"],"Leave room":["Raum verlassen"],"Main":["Standard"],"Current room":["Raum"],"Screen sharing options":["Optionen für Bildschirmfreigabe"],"Fit screen.":["Bildschirm einpassen."],"Profile":["Profil"],"Your name":["Ihr Name"],"Your picture":["Ihr Bild"],"Status message":["Status Nachricht"],"What's on your mind?":["Was machen Sie gerade?"],"Your picture, name and status message identify yourself in calls, chats and rooms.":["Ihr Bild, Name und Status Nachricht repräsentiert Sie in Anrufen, Chats und Räumen."],"Your ID":["Ihre ID"],"Register":["Registrieren"],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":["Mit Zertifikat angemeldet. Melden Sie sich ab indem Sie das Zertifikat aus dem Browser entfernen."],"Sign in":["Anmelden"],"Create an account":["Registrieren"],"Sign out":["Abmelden"],"Manage account":["Konto verwalten"],"Media":["Kamera / Mikrofon"],"Microphone":["Mikrofon"],"Camera":["Kamera"],"Video quality":["Video-Qualität"],"Low":["Gering"],"High":["Hoch"],"HD":["HD"],"Full HD":["Full HD"],"General":["Allgemein"],"Language":["Sprache"],"Language changes become active on reload.":["Sie müssen die Seite neu laden, um die Spracheinstellung zu übernehmen."],"Default room":["Standard Raum"],"Set alternative room to join at start.":[" Raum wird beim Start automatisch betreten."],"Desktop notification":["Desktop-Benachrichtigung"],"Enable":["Aktivieren"],"Denied - check your browser settings":["Verweigert - prüfen Sie die Browser-Einstellungen"],"Allowed":["Aktiviert"],"Advanced settings":["Erweiterte Einstellungen"],"Play audio on same device as selected microphone":["Audioausgabe auf dem zum Mikrofon gehörenden Gerät"],"Experimental AEC":["Experimentelle AEC"],"Experimental AGC":["Experimentelle AGC"],"Experimental noise suppression":["Experimentelle Geräuschunterdrückung"],"Max video frame rate":["Max. Bildwiederholrate"],"auto":["auto"],"Send stereo audio":["Audio in Stereo übertragen"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":["Um Stereo zu übertragen wird die Echo-Unterdrückung deaktiviert. Nur aktivieren wenn das Eingangssignal Stereo ist."],"Detect CPU over use":["CPU-Überlast erkennen"],"Automatically reduces video quality as needed.":["Reduziert die Videoqualität wenn nötig."],"Optimize for high resolution video":["Für hohe Auflösung optimieren"],"Reduce video noise":["Rauschen reduzieren"],"Enable experiments":["Experimente aktivieren"],"Show advanced settings":["Erweiterte Einstellungen anzeigen"],"Hide advanced settings":["Erweiterte Einstellungen ausblenden"],"Remember settings":["Einstellungen merken"],"Your ID will still be kept - press the log out button above to delete the ID.":["Ihre ID bleibt dennoch gespeichert. Klicken Sie Ausloggen weiter oben um die ID zu löschen."],"Room link":["Raum-Link"],"Invite by Email":["Per E-Mail einladen"],"Invite with Facebook":["Mit Facebook einladen"],"Invite with Twitter":["Mit Twitter einladen"],"Invite with Google Plus":["Mit Google Plus einladen"],"Invite with XING":["Mit XING einladen"],"Initializing":["Initialisiere"],"Online":["Online"],"Calling":["Verbinde mit"],"Hangup":["Auflegen"],"In call with":["Verbunden mit"],"Conference with":["Konferenz mit"],"Your are offline":["Sie sind offline"],"Go online":["Online gehen"],"Connection interrupted":["Verbindung unterbrochen"],"An error occured":["Ein Fehler ist aufgetreten"],"Incoming call":["Eingehender Anruf"],"from":["von"],"Accept call":["Anruf annehmen"],"Waiting for camera/microphone access":["Warte auf Kamera/Mikrofon Freigabe"],"Checking camera and microphone access.":["Prüfe Zugriff auf Kamera und Mikrofon."],"Please allow access to your camera and microphone.":["Bitte gestatten Sie den Zugriff auf Ihre Kamera und Mikrofon."],"Camera / microphone access required.":["Kamera / Mikrofon Zugriff wird benötigt."],"Please check your browser settings and allow camera and microphone access for this site.":["Bitte prüfen Sie Ihre Browser-Einstellungen und gestatten Sie den Zugriff auf Kamera und Mikrofon für diese Seite."],"Skip check":["Überspringen"],"Click here for help (Google Chrome).":["Hier klicken für weitere Infos (Google Chrome)."],"Please set your user details and settings.":["Bitte vervollständigen Sie Ihre Daten und Einstellungen."],"Enter a room name":["Raum eingeben"],"Random room name":["Zufälliger Raum"],"Enter room":["Raum betreten"],"Enter the name of an existing room. You can create new rooms when you are signed in.":["Geben Sie den Namen eines existierenden Raums ein. Melden Sie sich an um eigene Räume zu erstellen."],"Room history":["Raum-Verlauf"],"Please sign in.":["Bitte melden Sie sich an."],"Videos play simultaneously for everyone in this call.":["Das Video wird bei allen Gesprächsteilnehmern angezeigt."],"YouTube URL":["YouTube URL"],"Share":["Teilen"],"Could not load YouTube player API, please check your network / firewall settings.":["Es konnte keine Verbindung zu YouTube aufgebaut werden. Bitte prüfen Sie Ihre Internetverbindung / Firewall."],"Currently playing":["Aktuelles Video"],"YouTube controls":["YouTube Steuerung"],"YouTube video to share":["YouTube Video teilen"],"Peer to peer chat active.":["Peer-to-peer Chat ist aktiv."],"Peer to peer chat is now off.":["Peer-to-peer Chat ist nicht mehr aktiv."]," is now offline.":[" ist jetzt offline."]," is now online.":[" ist jetzt online."],"You share file:":["Sie geben eine Datei frei:"],"Incoming file:":["Eingehende Datei:"],"You shared your location:":["Sie haben Ihren Standort geteilt:"],"Location received:":["Standort erhalten:"],"You accepted the contact request.":["Sie haben die Kontaktanfrage angenommen."],"You rejected the contact request.":["Sie haben die Kontaktanfrage abgelehnt."],"You sent a contact request.":["Sie haben eine Kontaktanfrage gesendet."],"Your contact request was accepted.":["Ihre Kontaktanfrage wurde angenommen."],"Incoming contact request.":["Kontaktanfrage erhalten."],"Your contact request was rejected.":["Ihre Kontaktanfrage wurde abgelehnt."],"Edit Contact":["Kontakt bearbeiten"],"Close this window and disconnect?":["Fenster schließen und die Verbindung trennen?"],"Contacts Manager":["Kontakte"],"Restart required to apply updates. Click ok to restart now.":["Es stehen Updates zur Verfügung. Klicken Sie Ok um die Anwendung neu zu starten."],"Failed to access camera/microphone.":["Fehler beim Zugriff auf die Kamera / das Mikrofon."],"Failed to establish peer connection.":["Fehler beim Verbindungsaufbau."],"We are sorry but something went wrong. Boo boo.":["Leider ist ein Fehler aufgetreten. Buhuhu."],"Oops":["Hoppla"],"Peer connection failed. Check your settings.":["Verbindung fehlgeschlagen. Überprüfen Sie Ihre Einstellungen."],"User hung up because of error.":["Teilnehmer hat aufgelegt, da ein Fehler aufgetreten ist."]," is busy. Try again later.":[" ist in einem Gespräch. Probieren Sie es später."]," rejected your call.":[" hat Ihren Anruf abgelehnt."]," does not pick up.":[" nimmt nicht ab."]," tried to call you":[" hat versucht Sie anzurufen"]," called you":[" hat Sie angerufen"],"Your browser is not supported. Please upgrade to a current version.":["Ihr Browser wird nicht unterstützt. Bitte aktualisieren Sie auf eine aktuelle Version."],"Your browser does not support WebRTC. No calls possible.":["Ihr Browser unterstützt kein WebRTC. Keine Anrufe möglich."],"Chat with":["Chat mit"],"Message from ":["Nachricht von "],"You are now in room %s ...":["Sie sind nun im Raum %s ..."],"Your browser does not support file transfer.":["Mit Ihrem Browser können keine Dateien übertragen werden."],"Could not load PDF: Please make sure to select a PDF document.":["PDF konnte nicht geladen werden - Bitte stellen Sie sicher, dass Sie ein gültiges PDF-Dokument ausgewählt haben."],"Could not load PDF: Missing PDF file.":["Das PDF konnte nicht geladen werden: Datei fehlt."],"An error occurred while loading the PDF (%s).":["Beim Laden des PDF's ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF.":["Beim Laden des PDF ist ein unbekannter Fehler aufgetreten."],"An error occurred while loading the PDF page (%s).":["Beim Laden der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF page.":["Beim Laden der PDF-Seite ist ein unbekannter Fehler aufgetreten (%s)."],"An error occurred while rendering the PDF page (%s).":["Beim Anzeigen der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while rendering the PDF page.":["Beim Anzeigen der PDF-Seite ist ein ubekannter Fehler aufgetreten."],"Only PDF documents and OpenDocument files can be shared at this time.":["Es können nur Dokumente im PDF oder OpenDocument-Format als Präsentation verwendet werden."],"Failed to start screen sharing (%s).":["Die Bildschirmfreigabe konnte nicht gestartet werden (%s)."],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["Die Berechtigung für die Bildschirmaufzeichnung wurde verweigert. Bitte stellen Sie sicher die Unterstützung für Bildschimaufzeichnung in Ihrem Browser aktiviert ist. Kopieren Sie dazu chrome://flags/#enable-usermedia-screen-capture und öffnen Sie diese Adresse in Ihrem Browser. Aktivieren Sie die oberste Einstellung und starten dann den Browser neu. Anschließend können Sie die Bildschirmfreigabe benutzen."],"Permission to start screen sharing was denied.":["Die Berechtigung den Bildschirm freizugeben wurde verweigert."],"Use browser language":["Browsereinstellung"],"Meet with me here:":["Meeting:"],"Room name":["Raum-Name"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":["Unbekanntes URL-Format. Bitte geben Sie eine gültige YouTube URL ein."],"Error":["Fehler"],"Hint":["Hinweis"],"Please confirm":["Bitte bestätigen"],"More information required":["Weitere Informationen nötig"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":["Die Bildschrimfreigabe benötigt eine Browser-Erweiterung. Bitte fügen Sie die \"Spreed WebRTC screen sharing\" Erweiterung zu Chrome hinzu."],"Access code required":["Bitte Zugriffscode eingeben"],"Access denied":["Zugriff verweigert"],"Please provide a valid access code.":["Bitte geben Sie einen gültigen Zugriffscode ein."],"Failed to verify access code. Check your Internet connection and try again.":["Der Zugriffscode konnte nicht überprueft werden. Bitte prüfen Sie Ihre Internetverbindung."],"PIN for room %s is now '%s'.":["PIN für Raum %s ist jetzt '%s'."],"PIN lock has been removed from room %s.":["Raum %s ist nicht mehr PIN-geschützt."],"Enter the PIN for room %s":["Geben Sie die PIN für Raum %s ein"],"Please sign in to create rooms.":["Bitte melden Sie sich an um Räume zu erstellen."],"and %s":["und %s"],"and %d others":["und %d weiteren"],"User":["Teilnehmer"],"Someone":["Unbekannt"],"Me":["Ich"]}}} \ No newline at end of file diff --git a/static/translation/messages-ja.json b/static/translation/messages-ja.json index fc2a831e..5be7e269 100644 --- a/static/translation/messages-ja.json +++ b/static/translation/messages-ja.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":[null,"あなたの音量"],"Standard view":[null,""],"Large view":[null,""],"Kiosk view":[null,""],"Auditorium":[null,""],"Start chat":[null,"チャットを始める"],"Start video call":[null,"テレビ電話を始める"],"Start audio conference":[null,"音声会議を始める"],"No one else here":[null,""],"Take":[null,""],"Retake":[null,""],"Cancel":[null,"キャンセル"],"Set as Profile Picture":[null,""],"Take picture":[null,"写真を取る"],"Waiting for camera":[null,"カメラ待ち"],"The file couldn't be read.":[null,""],"The file is not an image.":[null,""],"The file is too large. Max. %d MB.":[null,""],"Select file":[null,""],"Chat sessions":[null,"チャットのセッション"],"Room chat":[null,"ルームチャット"],"Peer to peer":[null,"ピア・ツー・ピア"],"Close chat":[null,"チャットを終える"],"Share my location":[null,""],"is typing...":[null,"は入力中です..."],"has stopped typing...":[null,"は入力を止めました..."],"Type here to chat...":[null,"ここに入力してチャット開始します..."],"Send":[null,"送信"],"Accept":[null,""],"Reject":[null,"拒否"],"You have no contacts.":[null,""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[null,""],"Edit contact":[null,""],"Edit":[null,""],"Name":[null,"名前"],"Remove":[null,""],"Refresh":[null,""],"Save":[null,""],"Close":[null,"閉じる"],"File sharing":[null,"ファイル共有"],"File is no longer available":[null,"ファイルは有効ではありません"],"Download":[null,"ダウンロード"],"Open":[null,"開く"],"Unshare":[null,"共有取り消し"],"Retry":[null,"リトライ"],"Download failed.":[null,"ダウンロード失敗."],"Share a YouTube video":[null,""],"Share a file as presentation":[null,""],"Share your screen":[null,"画面を共有する."],"Chat":[null,"チャット"],"Contacts":[null,""],"Mute microphone":[null,"消音"],"Turn camera off":[null,"カメラをオフにする"],"Settings":[null,"設定"],"Loading presentation ...":[null,""],"Please upload a document":[null,""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[null,""],"Upload":[null,""],"You can drag files here too.":[null,""],"Presentation controls":[null,""],"Prev":[null,""],"Next":[null,""],"Change room":[null,"ルームチェンジ"],"Room":[null,"ルーム"],"Leave room":[null,"ルームを出る"],"Main":[null,"メイン"],"Current room":[null,"現在のルーム"],"Screen sharing options":[null,"画面共有オプション"],"Fit screen.":[null,"画面に合わせる"],"Profile":[null,""],"Your name":[null,"あなたの名前"],"Your picture":[null,"あなたの写真"],"Status message":[null,""],"What's on your mind?":[null,""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[null,""],"Your ID":[null,""],"Register":[null,""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[null,""],"Sign in":[null,""],"Create an account":[null,""],"Sign out":[null,""],"Manage account":[null,""],"Media":[null,""],"Microphone":[null,"マイク"],"Camera":[null,"カメラ"],"Video quality":[null,"ビデオ画質"],"Low":[null,"低い"],"High":[null,"高い"],"HD":[null,"HD"],"Full HD":[null,""],"General":[null,""],"Language":[null,"言語"],"Language changes become active on reload.":[null,"言語の変更は再読み込み時に適用となります."],"Default room":[null,"デフォルト・ルーム"],"Set alternative room to join at start.":[null,"スタート時に別のルームに参加する."],"Desktop notification":[null,"デスクトップ通知"],"Enable":[null,"有効にする"],"Denied - check your browser settings":[null,"拒否 - ブラウザ設定を確認して下さい"],"Allowed":[null,"許可"],"Advanced settings":[null,"詳細設定"],"Play audio on same device as selected microphone":[null,""],"Experimental AEC":[null,""],"Experimental AGC":[null,""],"Experimental noise suppression":[null,""],"Max video frame rate":[null,"ビデオ最高フレームレート"],"auto":[null,"自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[null,""],"Detect CPU over use":[null,""],"Automatically reduces video quality as needed.":[null,""],"Optimize for high resolution video":[null,""],"Reduce video noise":[null,""],"Enable experiments":[null,""],"Show advanced settings":[null,"詳細設定を表示"],"Hide advanced settings":[null,"詳細設定を隠す"],"Remember settings":[null,"設定を保存"],"Your ID will still be kept - press the log out button above to delete the ID.":[null,""],"Room link":[null,""],"Invite with Facebook":[null,""],"Invite with Twitter":[null,""],"Invite with Google Plus":[null,""],"Invite with XING":[null,""],"Initializing":[null,"初期化中"],"Online":[null,"オンライン"],"Calling":[null,"発信中"],"Hangup":[null,"切断"],"In call with":[null,"と会話中"],"Conference with":[null,"と会議中"],"Your are offline":[null,"オフラインです"],"Go online":[null,"オンラインにする"],"Connection interrupted":[null,"接続は中断されました"],"An error occured":[null,"エラーが発生しました"],"Incoming call":[null,"着信中"],"from":[null,"から"],"Accept call":[null,"通話"],"Waiting for camera/microphone access":[null,"カメラ・マイクの接続待ち."],"Checking camera and microphone access.":[null,"カメラ・マイクの接続確認中."],"Please allow access to your camera and microphone.":[null,"カメラとマイクの接続を許可してください."],"Camera / microphone access required.":[null,"カメラ・マイクの接続が必要です."],"Please check your browser settings and allow camera and microphone access for this site.":[null,"ブラウザ設定で、このサイトへのカメラ・マイクの接続を許可してください."],"Skip check":[null,"チェックをスキップ"],"Click here for help (Google Chrome).":[null,"ここをクリックしてヘルプ表示(Google Chrome)"],"Please set your user details and settings.":[null,"あなたのプロフィールとアプリの動作を設定してください."],"Enter a room name":[null,""],"Random room name":[null,""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[null,""],"Room history":[null,""],"Please sign in.":[null,""],"Videos play simultaneously for everyone in this call.":[null,""],"YouTube URL":[null,""],"Could not load YouTube player API, please check your network / firewall settings.":[null,""],"Currently playing":[null,""],"YouTube controls":[null,""],"YouTube video to share":[null,""],"Peer to peer chat active.":[null,"ピア・ツー・ピア・チャットがアクティブです."],"Peer to peer chat is now off.":[null,"ピア・ツー・ピア・チャットがオフです."]," is now offline.":[null,"は今オフラインです"]," is now online.":[null,"は今オンラインです"],"You share file:":[null,"あなたの共有ファイル:"],"Incoming file:":[null,"受信中ファイル:"],"You shared your location:":[null,""],"Location received:":[null,""],"You accepted the contact request.":[null,""],"You rejected the contact request.":[null,""],"You sent a contact request.":[null,""],"Your contact request was accepted.":[null,""],"Incoming contact request.":[null,""],"Your contact request was rejected.":[null,""],"Edit Contact":[null,""],"Close this window and disconnect?":[null,""],"Contacts Manager":[null,""],"Restart required to apply updates. Click ok to restart now.":[null,"アップデート適用のため再起動してください.ここをクリックして再起動する."],"Failed to access camera/microphone.":[null,"カメラ・マイクへの接続に失敗しました."],"Failed to establish peer connection.":[null,"ピアとの接続に失敗しました."],"We are sorry but something went wrong. Boo boo.":[null,"申し訳ないのですが、不具合が生じました。"],"Oops":[null,"しまった"],"Peer connection failed. Check your settings.":[null,"ピア接続に失敗しました.設定を確認してください."],"User hung up because of error.":[null,"エラーのため切断しました."]," is busy. Try again later.":[null,"は話中です.後で掛けなおしてください."]," rejected your call.":[null,"着信拒否されました."]," does not pick up.":[null,"は電話にでません."],"Your browser does not support WebRTC. No calls possible.":[null,"ブラウザがWebRTCをサポートしていない為通話はできません."],"Chat with":[null,"とチャットする"],"Message from ":[null,"からのメッセージ"],"You are now in room %s ...":[null,"あなたは%sのルームにいます..."],"Your browser does not support file transfer.":[null,"ブラウザがファイル転送をサポートしていません."],"Could not load PDF: Please make sure to select a PDF document.":[null,""],"Could not load PDF: Missing PDF file.":[null,""],"An error occurred while loading the PDF (%s).":[null,""],"An unknown error occurred while loading the PDF.":[null,""],"An error occurred while loading the PDF page (%s).":[null,""],"An unknown error occurred while loading the PDF page.":[null,""],"An error occurred while rendering the PDF page (%s).":[null,""],"An unknown error occurred while rendering the PDF page.":[null,""],"Only PDF documents and OpenDocument files can be shared at this time.":[null,""],"Failed to start screen sharing (%s).":[null,""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":[null,"画面共有は拒否されました.ブラウザの画面共有の設定を確認して下さい. Chromeのアドレスバーに chrome://flags/#enable-usermedia-screen-capture を入力して開き、スクリーンキャプチャのサポートを有効にしてください。その後ブラウザを再起動してください。"],"Permission to start screen sharing was denied.":[null,""],"Use browser language":[null,"ブラウザの言語を使用"],"Meet with me here:":[null,"ここで私と会う:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[null,""],"Error":[null,"エラー"],"Hint":[null,"ヒント"],"Please confirm":[null,"確認して下さい"],"More information required":[null,"さらなる情報が必要です"],"Ok":[null,"OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[null,""],"Access code required":[null,"アクセスコードが必要です"],"Access denied":[null,"アクセスが拒否されました"],"Please provide a valid access code.":[null,"有効なアクセスコードを入力してください."],"Failed to verify access code. Check your Internet connection and try again.":[null,"アクセスコードの確認に失敗しました.インターネット接続を確認してリトライしてください."],"PIN for room %s is now '%s'.":[null,""],"PIN lock has been removed from room %s.":[null,""],"Enter the PIN for room %s":[null,""],"Please sign in to create rooms.":[null,""],"and %d others":[null,""],"User":[null,"ユーザー"],"Someone":[null,"誰か"],"Me":[null,"私"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["あなたの音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["チャットを始める"],"Start video call":["テレビ電話を始める"],"Start audio conference":["音声会議を始める"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["キャンセル"],"Set as Profile Picture":[""],"Take picture":["写真を取る"],"Waiting for camera":["カメラ待ち"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["チャットのセッション"],"Room chat":["ルームチャット"],"Peer to peer":["ピア・ツー・ピア"],"Close chat":["チャットを終える"],"Share my location":[""],"is typing...":["は入力中です..."],"has stopped typing...":["は入力を止めました..."],"Type here to chat...":["ここに入力してチャット開始します..."],"Send":["送信"],"Accept":[""],"Reject":["拒否"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名前"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["閉じる"],"File sharing":["ファイル共有"],"File is no longer available":["ファイルは有効ではありません"],"Download":["ダウンロード"],"Open":["開く"],"Unshare":["共有取り消し"],"Retry":["リトライ"],"Download failed.":["ダウンロード失敗."],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["画面を共有する."],"Chat":["チャット"],"Contacts":[""],"Mute microphone":["消音"],"Turn camera off":["カメラをオフにする"],"Settings":["設定"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["ルームチェンジ"],"Room":["ルーム"],"Leave room":["ルームを出る"],"Main":["メイン"],"Current room":["現在のルーム"],"Screen sharing options":["画面共有オプション"],"Fit screen.":["画面に合わせる"],"Profile":[""],"Your name":["あなたの名前"],"Your picture":["あなたの写真"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["マイク"],"Camera":["カメラ"],"Video quality":["ビデオ画質"],"Low":["低い"],"High":["高い"],"HD":["HD"],"Full HD":[""],"General":[""],"Language":["言語"],"Language changes become active on reload.":["言語の変更は再読み込み時に適用となります."],"Default room":["デフォルト・ルーム"],"Set alternative room to join at start.":["スタート時に別のルームに参加する."],"Desktop notification":["デスクトップ通知"],"Enable":["有効にする"],"Denied - check your browser settings":["拒否 - ブラウザ設定を確認して下さい"],"Allowed":["許可"],"Advanced settings":["詳細設定"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["ビデオ最高フレームレート"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["詳細設定を表示"],"Hide advanced settings":["詳細設定を隠す"],"Remember settings":["設定を保存"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初期化中"],"Online":["オンライン"],"Calling":["発信中"],"Hangup":["切断"],"In call with":["と会話中"],"Conference with":["と会議中"],"Your are offline":["オフラインです"],"Go online":["オンラインにする"],"Connection interrupted":["接続は中断されました"],"An error occured":["エラーが発生しました"],"Incoming call":["着信中"],"from":["から"],"Accept call":["通話"],"Waiting for camera/microphone access":["カメラ・マイクの接続待ち."],"Checking camera and microphone access.":["カメラ・マイクの接続確認中."],"Please allow access to your camera and microphone.":["カメラとマイクの接続を許可してください."],"Camera / microphone access required.":["カメラ・マイクの接続が必要です."],"Please check your browser settings and allow camera and microphone access for this site.":["ブラウザ設定で、このサイトへのカメラ・マイクの接続を許可してください."],"Skip check":["チェックをスキップ"],"Click here for help (Google Chrome).":["ここをクリックしてヘルプ表示(Google Chrome)"],"Please set your user details and settings.":["あなたのプロフィールとアプリの動作を設定してください."],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["ピア・ツー・ピア・チャットがアクティブです."],"Peer to peer chat is now off.":["ピア・ツー・ピア・チャットがオフです."]," is now offline.":["は今オフラインです"]," is now online.":["は今オンラインです"],"You share file:":["あなたの共有ファイル:"],"Incoming file:":["受信中ファイル:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["アップデート適用のため再起動してください.ここをクリックして再起動する."],"Failed to access camera/microphone.":["カメラ・マイクへの接続に失敗しました."],"Failed to establish peer connection.":["ピアとの接続に失敗しました."],"We are sorry but something went wrong. Boo boo.":["申し訳ないのですが、不具合が生じました。"],"Oops":["しまった"],"Peer connection failed. Check your settings.":["ピア接続に失敗しました.設定を確認してください."],"User hung up because of error.":["エラーのため切断しました."]," is busy. Try again later.":["は話中です.後で掛けなおしてください."]," rejected your call.":["着信拒否されました."]," does not pick up.":["は電話にでません."],"Your browser does not support WebRTC. No calls possible.":["ブラウザがWebRTCをサポートしていない為通話はできません."],"Chat with":["とチャットする"],"Message from ":["からのメッセージ"],"You are now in room %s ...":["あなたは%sのルームにいます..."],"Your browser does not support file transfer.":["ブラウザがファイル転送をサポートしていません."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["画面共有は拒否されました.ブラウザの画面共有の設定を確認して下さい. Chromeのアドレスバーに chrome://flags/#enable-usermedia-screen-capture を入力して開き、スクリーンキャプチャのサポートを有効にしてください。その後ブラウザを再起動してください。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["ブラウザの言語を使用"],"Meet with me here:":["ここで私と会う:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["エラー"],"Hint":["ヒント"],"Please confirm":["確認して下さい"],"More information required":["さらなる情報が必要です"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["アクセスコードが必要です"],"Access denied":["アクセスが拒否されました"],"Please provide a valid access code.":["有効なアクセスコードを入力してください."],"Failed to verify access code. Check your Internet connection and try again.":["アクセスコードの確認に失敗しました.インターネット接続を確認してリトライしてください."],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["ユーザー"],"Someone":["誰か"],"Me":["私"]}}} \ No newline at end of file diff --git a/static/translation/messages-ko.json b/static/translation/messages-ko.json index 67823d8b..99aa9730 100644 --- a/static/translation/messages-ko.json +++ b/static/translation/messages-ko.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":[null,"음성크기"],"Standard view":[null,""],"Large view":[null,""],"Kiosk view":[null,""],"Auditorium":[null,""],"Start chat":[null,"대화시작"],"Start video call":[null,"화상회의 시작"],"Start audio conference":[null,"음성회의 시작"],"No one else here":[null,""],"Take":[null,""],"Retake":[null,""],"Cancel":[null,"취소"],"Set as Profile Picture":[null,""],"Take picture":[null,"사진 찍음"],"Waiting for camera":[null,"카메라 대기중"],"The file couldn't be read.":[null,""],"The file is not an image.":[null,""],"The file is too large. Max. %d MB.":[null,""],"Select file":[null,""],"Chat sessions":[null,"대화 세션"],"Room chat":[null,"대화 방"],"Peer to peer":[null,"일대일"],"Close chat":[null,"대화 종료"],"Share my location":[null,""],"is typing...":[null,"입력중"],"has stopped typing...":[null,"입력 종료"],"Type here to chat...":[null,"대화 입력"],"Send":[null,"전송"],"Accept":[null,""],"Reject":[null,"거부"],"You have no contacts.":[null,""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[null,""],"Edit contact":[null,""],"Edit":[null,""],"Name":[null,"이름"],"Remove":[null,""],"Refresh":[null,""],"Save":[null,""],"Close":[null,"닫음"],"File sharing":[null,"회일 공유"],"File is no longer available":[null,"화일이 유효하지 않습니다"],"Download":[null,"다운로드"],"Open":[null,"열기"],"Unshare":[null,"비공유"],"Retry":[null,"재시도"],"Download failed.":[null,"다운로드실패"],"Share a YouTube video":[null,""],"Share a file as presentation":[null,""],"Share your screen":[null,"화면 공유하기"],"Chat":[null,"대화"],"Contacts":[null,""],"Mute microphone":[null,"음성제거"],"Turn camera off":[null,"카메라꺼짐"],"Settings":[null,"설정"],"Loading presentation ...":[null,""],"Please upload a document":[null,""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[null,""],"Upload":[null,""],"You can drag files here too.":[null,""],"Presentation controls":[null,""],"Prev":[null,""],"Next":[null,""],"Change room":[null,"방 변경"],"Room":[null,"방"],"Leave room":[null,"방 이동"],"Main":[null,"메인"],"Current room":[null,"현재 방"],"Screen sharing options":[null,"화면 공유 옵션"],"Fit screen.":[null,"화면에 맟춤"],"Profile":[null,""],"Your name":[null,"사용자 이름"],"Your picture":[null,"사용자 사진"],"Status message":[null,""],"What's on your mind?":[null,""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[null,""],"Your ID":[null,""],"Register":[null,""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[null,""],"Sign in":[null,""],"Create an account":[null,""],"Sign out":[null,""],"Manage account":[null,""],"Media":[null,""],"Microphone":[null,"마이크"],"Camera":[null,"카메라"],"Video quality":[null,"영상 수준"],"Low":[null,"낮음"],"High":[null,"높음"],"HD":[null,"고화질"],"Full HD":[null,""],"General":[null,""],"Language":[null,"언어"],"Language changes become active on reload.":[null,"언어 변경이 재로드 되고 있습니다"],"Default room":[null,"기본 방"],"Set alternative room to join at start.":[null,"시작시에 다른 방에 합류하도록 설정 되었습니다"],"Desktop notification":[null,"데스크탑에 통보"],"Enable":[null,"활성화"],"Denied - check your browser settings":[null,"거부됨 - 브라우저 설정을 확인하세요"],"Allowed":[null,"허락됨"],"Advanced settings":[null,"고급 설정"],"Play audio on same device as selected microphone":[null,""],"Experimental AEC":[null,""],"Experimental AGC":[null,""],"Experimental noise suppression":[null,""],"Max video frame rate":[null,"비디오프레임 비율 최대화"],"auto":[null,"자동"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[null,""],"Detect CPU over use":[null,""],"Automatically reduces video quality as needed.":[null,""],"Optimize for high resolution video":[null,""],"Reduce video noise":[null,""],"Enable experiments":[null,""],"Show advanced settings":[null,"고급 설정 보기"],"Hide advanced settings":[null,"고급 설정 감추기"],"Remember settings":[null,"설정 기억"],"Your ID will still be kept - press the log out button above to delete the ID.":[null,""],"Room link":[null,""],"Invite with Facebook":[null,""],"Invite with Twitter":[null,""],"Invite with Google Plus":[null,""],"Invite with XING":[null,""],"Initializing":[null,"초기화"],"Online":[null,"온라인"],"Calling":[null,"전화걸기"],"Hangup":[null,"전화끊기"],"In call with":[null,"전화중"],"Conference with":[null,"회의중"],"Your are offline":[null,"오프라인 입니다"],"Go online":[null,"온라인에 연결합니다"],"Connection interrupted":[null,"연결이 중단"],"An error occured":[null,"에러 발생"],"Incoming call":[null,"전화 걸려옴"],"from":[null,"부터"],"Accept call":[null,"전화 받음"],"Waiting for camera/microphone access":[null,"카메라/마이크 사용을 기다림"],"Checking camera and microphone access.":[null,"카메라와 마이크의 사용을 확인 하세요"],"Please allow access to your camera and microphone.":[null,"카메라와 마이크의 사용을 허용 하세요"],"Camera / microphone access required.":[null,"카메라/마이크 사용이 필요합니다"],"Please check your browser settings and allow camera and microphone access for this site.":[null,"이 사이트에 대하여 브라우저의 설정을 확인하고 카메라와 마이크의 사용을 허용 하세요"],"Skip check":[null,"확인 넘어가기"],"Click here for help (Google Chrome).":[null,"도움말을 원하면 여기를 클릭 하세요 (구글 크롬)"],"Please set your user details and settings.":[null,"사용자의 세부상세와 설정을 지정하세요 "],"Enter a room name":[null,""],"Random room name":[null,""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[null,""],"Room history":[null,""],"Please sign in.":[null,""],"Videos play simultaneously for everyone in this call.":[null,""],"YouTube URL":[null,""],"Could not load YouTube player API, please check your network / firewall settings.":[null,""],"Currently playing":[null,""],"YouTube controls":[null,""],"YouTube video to share":[null,""],"Peer to peer chat active.":[null,"일대일 대화 활성화"],"Peer to peer chat is now off.":[null,"일대일 대화 꺼짐"]," is now offline.":[null,"현재 오프라인 상태"]," is now online.":[null,"현재 온라인 상태"],"You share file:":[null,"공유 화일:"],"Incoming file:":[null,"도착하는 화일:"],"You shared your location:":[null,""],"Location received:":[null,""],"You accepted the contact request.":[null,""],"You rejected the contact request.":[null,""],"You sent a contact request.":[null,""],"Your contact request was accepted.":[null,""],"Incoming contact request.":[null,""],"Your contact request was rejected.":[null,""],"Edit Contact":[null,""],"Close this window and disconnect?":[null,""],"Contacts Manager":[null,""],"Restart required to apply updates. Click ok to restart now.":[null,"업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"],"Failed to access camera/microphone.":[null,"카메라/마이크 사용 실패"],"Failed to establish peer connection.":[null,"상대연결 설정이 실패 하였습니다"],"We are sorry but something went wrong. Boo boo.":[null,"죄송합니다만 현재 문제가 있습니다."],"Oops":[null,"이런"],"Peer connection failed. Check your settings.":[null,"상대연결이 실패 했습니다. 설정을 확인 하십시오"],"User hung up because of error.":[null,"오류로 인해 사용자 끊어짐"]," is busy. Try again later.":[null,"통화중. 다시 시도 하세요."]," rejected your call.":[null,"전화가 거부 되었습니다."]," does not pick up.":[null,"전화를 받지 않습니다."],"Your browser does not support WebRTC. No calls possible.":[null,"브라우저가 WebRTC를 지원하지 않습니다. 전화걸기가 불가능 합니다."],"Chat with":[null,"대화하기"],"Message from ":[null,"로 부터 메시지"],"You are now in room %s ...":[null,"당신은 현재 방%s ...에 있습니다"],"Your browser does not support file transfer.":[null,"당신의 브라우저가 회일전송을 지원하지 않습니다."],"Could not load PDF: Please make sure to select a PDF document.":[null,""],"Could not load PDF: Missing PDF file.":[null,""],"An error occurred while loading the PDF (%s).":[null,""],"An unknown error occurred while loading the PDF.":[null,""],"An error occurred while loading the PDF page (%s).":[null,""],"An unknown error occurred while loading the PDF page.":[null,""],"An error occurred while rendering the PDF page (%s).":[null,""],"An unknown error occurred while rendering the PDF page.":[null,""],"Only PDF documents and OpenDocument files can be shared at this time.":[null,""],"Failed to start screen sharing (%s).":[null,""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":[null,"화면공유가 거절되었습니다. 사용하시는 브라우저에서 화면공유를 가능하도록 하여 주십시오. chrome://flags/#enable-usermedia-screen-capture를 복사하여 브라우저에서 수행하시고 상단의 프래그를 가능으로 변경 하십시오. 브라우저를 다시 수행시키면 사용하실수 있습니다."],"Permission to start screen sharing was denied.":[null,""],"Use browser language":[null,"브라우저 언어 사용"],"Meet with me here:":[null,"나를 여기서 만납니다:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[null,""],"Error":[null,"오류"],"Hint":[null,"도움말"],"Please confirm":[null,"확인하십시오"],"More information required":[null,"더 많은 정보가 필요함"],"Ok":[null,"오케이"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[null,""],"Access code required":[null,"접속코드 필요함"],"Access denied":[null,"접속 거부"],"Please provide a valid access code.":[null,"유효한 접속코드가 필요합니다."],"Failed to verify access code. Check your Internet connection and try again.":[null,"접속코드 확인이 실패 했습니다. 인터넷 연결을 확인하고 다시 시도해 주십시오. "],"PIN for room %s is now '%s'.":[null,""],"PIN lock has been removed from room %s.":[null,""],"Enter the PIN for room %s":[null,""],"Please sign in to create rooms.":[null,""],"and %d others":[null,""],"User":[null,"사용자"],"Someone":[null,"어떤 사람"],"Me":[null,"나"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["음성크기"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["대화시작"],"Start video call":["화상회의 시작"],"Start audio conference":["음성회의 시작"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["취소"],"Set as Profile Picture":[""],"Take picture":["사진 찍음"],"Waiting for camera":["카메라 대기중"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["대화 세션"],"Room chat":["대화 방"],"Peer to peer":["일대일"],"Close chat":["대화 종료"],"Share my location":[""],"is typing...":["입력중"],"has stopped typing...":["입력 종료"],"Type here to chat...":["대화 입력"],"Send":["전송"],"Accept":[""],"Reject":["거부"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["이름"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["닫음"],"File sharing":["회일 공유"],"File is no longer available":["화일이 유효하지 않습니다"],"Download":["다운로드"],"Open":["열기"],"Unshare":["비공유"],"Retry":["재시도"],"Download failed.":["다운로드실패"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["화면 공유하기"],"Chat":["대화"],"Contacts":[""],"Mute microphone":["음성제거"],"Turn camera off":["카메라꺼짐"],"Settings":["설정"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["방 변경"],"Room":["방"],"Leave room":["방 이동"],"Main":["메인"],"Current room":["현재 방"],"Screen sharing options":["화면 공유 옵션"],"Fit screen.":["화면에 맟춤"],"Profile":[""],"Your name":["사용자 이름"],"Your picture":["사용자 사진"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["마이크"],"Camera":["카메라"],"Video quality":["영상 수준"],"Low":["낮음"],"High":["높음"],"HD":["고화질"],"Full HD":[""],"General":[""],"Language":["언어"],"Language changes become active on reload.":["언어 변경이 재로드 되고 있습니다"],"Default room":["기본 방"],"Set alternative room to join at start.":["시작시에 다른 방에 합류하도록 설정 되었습니다"],"Desktop notification":["데스크탑에 통보"],"Enable":["활성화"],"Denied - check your browser settings":["거부됨 - 브라우저 설정을 확인하세요"],"Allowed":["허락됨"],"Advanced settings":["고급 설정"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["비디오프레임 비율 최대화"],"auto":["자동"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["고급 설정 보기"],"Hide advanced settings":["고급 설정 감추기"],"Remember settings":["설정 기억"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["초기화"],"Online":["온라인"],"Calling":["전화걸기"],"Hangup":["전화끊기"],"In call with":["전화중"],"Conference with":["회의중"],"Your are offline":["오프라인 입니다"],"Go online":["온라인에 연결합니다"],"Connection interrupted":["연결이 중단"],"An error occured":["에러 발생"],"Incoming call":["전화 걸려옴"],"from":["부터"],"Accept call":["전화 받음"],"Waiting for camera/microphone access":["카메라/마이크 사용을 기다림"],"Checking camera and microphone access.":["카메라와 마이크의 사용을 확인 하세요"],"Please allow access to your camera and microphone.":["카메라와 마이크의 사용을 허용 하세요"],"Camera / microphone access required.":["카메라/마이크 사용이 필요합니다"],"Please check your browser settings and allow camera and microphone access for this site.":["이 사이트에 대하여 브라우저의 설정을 확인하고 카메라와 마이크의 사용을 허용 하세요"],"Skip check":["확인 넘어가기"],"Click here for help (Google Chrome).":["도움말을 원하면 여기를 클릭 하세요 (구글 크롬)"],"Please set your user details and settings.":["사용자의 세부상세와 설정을 지정하세요 "],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["일대일 대화 활성화"],"Peer to peer chat is now off.":["일대일 대화 꺼짐"]," is now offline.":["현재 오프라인 상태"]," is now online.":["현재 온라인 상태"],"You share file:":["공유 화일:"],"Incoming file:":["도착하는 화일:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"],"Failed to access camera/microphone.":["카메라/마이크 사용 실패"],"Failed to establish peer connection.":["상대연결 설정이 실패 하였습니다"],"We are sorry but something went wrong. Boo boo.":["죄송합니다만 현재 문제가 있습니다."],"Oops":["이런"],"Peer connection failed. Check your settings.":["상대연결이 실패 했습니다. 설정을 확인 하십시오"],"User hung up because of error.":["오류로 인해 사용자 끊어짐"]," is busy. Try again later.":["통화중. 다시 시도 하세요."]," rejected your call.":["전화가 거부 되었습니다."]," does not pick up.":["전화를 받지 않습니다."],"Your browser does not support WebRTC. No calls possible.":["브라우저가 WebRTC를 지원하지 않습니다. 전화걸기가 불가능 합니다."],"Chat with":["대화하기"],"Message from ":["로 부터 메시지"],"You are now in room %s ...":["당신은 현재 방%s ...에 있습니다"],"Your browser does not support file transfer.":["당신의 브라우저가 회일전송을 지원하지 않습니다."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["화면공유가 거절되었습니다. 사용하시는 브라우저에서 화면공유를 가능하도록 하여 주십시오. chrome://flags/#enable-usermedia-screen-capture를 복사하여 브라우저에서 수행하시고 상단의 프래그를 가능으로 변경 하십시오. 브라우저를 다시 수행시키면 사용하실수 있습니다."],"Permission to start screen sharing was denied.":[""],"Use browser language":["브라우저 언어 사용"],"Meet with me here:":["나를 여기서 만납니다:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["오류"],"Hint":["도움말"],"Please confirm":["확인하십시오"],"More information required":["더 많은 정보가 필요함"],"Ok":["오케이"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["접속코드 필요함"],"Access denied":["접속 거부"],"Please provide a valid access code.":["유효한 접속코드가 필요합니다."],"Failed to verify access code. Check your Internet connection and try again.":["접속코드 확인이 실패 했습니다. 인터넷 연결을 확인하고 다시 시도해 주십시오. "],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["사용자"],"Someone":["어떤 사람"],"Me":["나"]}}} \ No newline at end of file diff --git a/static/translation/messages-zh-cn.json b/static/translation/messages-zh-cn.json index 7cf1921d..d1770c91 100644 --- a/static/translation/messages-zh-cn.json +++ b/static/translation/messages-zh-cn.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":[null,"您的通话音量"],"Standard view":[null,""],"Large view":[null,""],"Kiosk view":[null,""],"Auditorium":[null,""],"Start chat":[null,"开始聊天"],"Start video call":[null,"开始视频通话"],"Start audio conference":[null,"开始语音会议"],"No one else here":[null,""],"Take":[null,""],"Retake":[null,""],"Cancel":[null,"取消"],"Set as Profile Picture":[null,""],"Take picture":[null,"拍照"],"Waiting for camera":[null,"等待启动摄像头"],"The file couldn't be read.":[null,""],"The file is not an image.":[null,""],"The file is too large. Max. %d MB.":[null,""],"Select file":[null,""],"Chat sessions":[null,"会话"],"Room chat":[null,"房间聊天"],"Peer to peer":[null,"P2P"],"Close chat":[null,"关闭聊天"],"Share my location":[null,""],"is typing...":[null,"正在输入..."],"has stopped typing...":[null,"停止输入..."],"Type here to chat...":[null,"在此输入开始聊天..."],"Send":[null,"发送"],"Accept":[null,""],"Reject":[null,"拒绝"],"You have no contacts.":[null,""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[null,""],"Edit contact":[null,""],"Edit":[null,""],"Name":[null,"名字"],"Remove":[null,""],"Refresh":[null,""],"Save":[null,""],"Close":[null,"关闭"],"File sharing":[null,"分享文件"],"File is no longer available":[null,"文件已不存在"],"Download":[null,"下载"],"Open":[null,"打开"],"Unshare":[null,"停止分享"],"Retry":[null,"重试"],"Download failed.":[null,"下载失败"],"Share a YouTube video":[null,""],"Share a file as presentation":[null,""],"Share your screen":[null,"共享您的屏幕"],"Chat":[null,"聊天"],"Contacts":[null,""],"Mute microphone":[null,"关闭麦克风"],"Turn camera off":[null,"关闭摄像头"],"Settings":[null,"系统设置"],"Loading presentation ...":[null,""],"Please upload a document":[null,""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[null,""],"Upload":[null,""],"You can drag files here too.":[null,""],"Presentation controls":[null,""],"Prev":[null,""],"Next":[null,""],"Change room":[null,"更换房间"],"Room":[null,"房间"],"Leave room":[null,"离开房间"],"Main":[null,"主房间"],"Current room":[null,"當前房间"],"Screen sharing options":[null,"屏幕共享设置"],"Fit screen.":[null,"适合屏幕"],"Profile":[null,""],"Your name":[null,"您的名字"],"Your picture":[null,"您的图片"],"Status message":[null,""],"What's on your mind?":[null,""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[null,""],"Your ID":[null,""],"Register":[null,""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[null,""],"Sign in":[null,""],"Create an account":[null,""],"Sign out":[null,""],"Manage account":[null,""],"Media":[null,""],"Microphone":[null,"麦克风"],"Camera":[null,"摄像头"],"Video quality":[null,"视频质量"],"Low":[null,"低"],"High":[null,"高"],"HD":[null,"高清"],"Full HD":[null,""],"General":[null,""],"Language":[null,"语言"],"Language changes become active on reload.":[null,"转换语言需重启程序"],"Default room":[null,"系统默认房间"],"Set alternative room to join at start.":[null,"重设初始默认房间"],"Desktop notification":[null,"桌面提醒"],"Enable":[null,"开启"],"Denied - check your browser settings":[null,"被拒绝--请检查浏览器设置"],"Allowed":[null,"启用"],"Advanced settings":[null,"高级设置"],"Play audio on same device as selected microphone":[null,""],"Experimental AEC":[null,""],"Experimental AGC":[null,""],"Experimental noise suppression":[null,""],"Max video frame rate":[null,"最大视频帧速率"],"auto":[null,"自动"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[null,""],"Detect CPU over use":[null,""],"Automatically reduces video quality as needed.":[null,""],"Optimize for high resolution video":[null,""],"Reduce video noise":[null,""],"Enable experiments":[null,""],"Show advanced settings":[null,"展开高级设置"],"Hide advanced settings":[null,"隐藏高级设置"],"Remember settings":[null,"记住设置"],"Your ID will still be kept - press the log out button above to delete the ID.":[null,""],"Room link":[null,""],"Invite with Facebook":[null,""],"Invite with Twitter":[null,""],"Invite with Google Plus":[null,""],"Invite with XING":[null,""],"Initializing":[null,"初始化"],"Online":[null,"在线"],"Calling":[null,"呼叫中"],"Hangup":[null,"挂断"],"In call with":[null,"正在和**通话"],"Conference with":[null,"和**会议通话"],"Your are offline":[null,"您不在线"],"Go online":[null,"上线"],"Connection interrupted":[null,"连接已中断"],"An error occured":[null,"出现错误"],"Incoming call":[null,"来电"],"from":[null,"来自"],"Accept call":[null,"接受通话"],"Waiting for camera/microphone access":[null,"等待摄像头/麦克风连接"],"Checking camera and microphone access.":[null,"正在检查摄像头及麦克风连接"],"Please allow access to your camera and microphone.":[null,"请允许连接您的摄像头及麦克风"],"Camera / microphone access required.":[null,"需连接摄像头/麦克风"],"Please check your browser settings and allow camera and microphone access for this site.":[null,"请检查浏览器设置并允许摄像头及麦克风连接此网站"],"Skip check":[null,"越过检查"],"Click here for help (Google Chrome).":[null,"点击这里获取帮助 (Google Chrome)"],"Please set your user details and settings.":[null,"请设定您的用户信息及设置"],"Enter a room name":[null,""],"Random room name":[null,""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[null,""],"Room history":[null,""],"Please sign in.":[null,""],"Videos play simultaneously for everyone in this call.":[null,""],"YouTube URL":[null,""],"Could not load YouTube player API, please check your network / firewall settings.":[null,""],"Currently playing":[null,""],"YouTube controls":[null,""],"YouTube video to share":[null,""],"Peer to peer chat active.":[null,"P2P聊天已启动"],"Peer to peer chat is now off.":[null,"P2P现在未启动"]," is now offline.":[null," 不在线"]," is now online.":[null," 现在在线"],"You share file:":[null,"分享文件:"],"Incoming file:":[null,"发来文件:"],"You shared your location:":[null,""],"Location received:":[null,""],"You accepted the contact request.":[null,""],"You rejected the contact request.":[null,""],"You sent a contact request.":[null,""],"Your contact request was accepted.":[null,""],"Incoming contact request.":[null,""],"Your contact request was rejected.":[null,""],"Edit Contact":[null,""],"Close this window and disconnect?":[null,""],"Contacts Manager":[null,""],"Restart required to apply updates. Click ok to restart now.":[null,"适用更新需重启,现在点击Ok重新启动。"],"Failed to access camera/microphone.":[null,"摄像头/麦克风连接失败"],"Failed to establish peer connection.":[null,"对等连接建立失败"],"We are sorry but something went wrong. Boo boo.":[null,"很抱歉,有错误发生。"],"Oops":[null,"Oops"],"Peer connection failed. Check your settings.":[null,"对等连接失败,请检查设置。"],"User hung up because of error.":[null,"用户因错误挂断"]," is busy. Try again later.":[null," 正在通话,请稍后再试。"]," rejected your call.":[null," 拒绝了您的呼叫。"]," does not pick up.":[null," 无人接听。"],"Your browser does not support WebRTC. No calls possible.":[null,"您的浏览器不支持WebRTC。不能进行通话。"],"Chat with":[null,"与**聊天"],"Message from ":[null,"来自于**的信息"],"You are now in room %s ...":[null,"您在 %s 房间"],"Your browser does not support file transfer.":[null,"您的浏览器不支持文件传输"],"Could not load PDF: Please make sure to select a PDF document.":[null,""],"Could not load PDF: Missing PDF file.":[null,""],"An error occurred while loading the PDF (%s).":[null,""],"An unknown error occurred while loading the PDF.":[null,""],"An error occurred while loading the PDF page (%s).":[null,""],"An unknown error occurred while loading the PDF page.":[null,""],"An error occurred while rendering the PDF page (%s).":[null,""],"An unknown error occurred while rendering the PDF page.":[null,""],"Only PDF documents and OpenDocument files can be shared at this time.":[null,""],"Failed to start screen sharing (%s).":[null,""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":[null,"启动屏幕共享许可被拒绝。请确认您已开启浏览器屏幕共享连接。请复制chrome://flags/#enable-usermedia-screen-capture并用您的浏览器打开,启用最上端的功能。然后重启浏览器,操作完成。"],"Permission to start screen sharing was denied.":[null,""],"Use browser language":[null,"使用浏览器语言"],"Meet with me here:":[null,"我们这里见:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[null,""],"Error":[null,"错误"],"Hint":[null,"提示"],"Please confirm":[null,"请确认"],"More information required":[null,"需要更多信息"],"Ok":[null,"Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[null,""],"Access code required":[null,"需要接入码"],"Access denied":[null,"连接被拒绝"],"Please provide a valid access code.":[null,"请提供有效接入码"],"Failed to verify access code. Check your Internet connection and try again.":[null,"接入码认证失败。请检查您的网络连接并重试。"],"PIN for room %s is now '%s'.":[null,""],"PIN lock has been removed from room %s.":[null,""],"Enter the PIN for room %s":[null,""],"Please sign in to create rooms.":[null,""],"and %s":[null,""],"and %d others":[null,""],"User":[null,"用户"],"Someone":[null,"某人"],"Me":[null,"我"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通话音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["开始聊天"],"Start video call":["开始视频通话"],"Start audio conference":["开始语音会议"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待启动摄像头"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["会话"],"Room chat":["房间聊天"],"Peer to peer":["P2P"],"Close chat":["关闭聊天"],"Share my location":[""],"is typing...":["正在输入..."],"has stopped typing...":["停止输入..."],"Type here to chat...":["在此输入开始聊天..."],"Send":["发送"],"Accept":[""],"Reject":["拒绝"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["关闭"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下载"],"Open":["打开"],"Unshare":["停止分享"],"Retry":["重试"],"Download failed.":["下载失败"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["关闭麦克风"],"Turn camera off":["关闭摄像头"],"Settings":["系统设置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更换房间"],"Room":["房间"],"Leave room":["离开房间"],"Main":["主房间"],"Current room":["當前房间"],"Screen sharing options":["屏幕共享设置"],"Fit screen.":["适合屏幕"],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的图片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麦克风"],"Camera":["摄像头"],"Video quality":["视频质量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["语言"],"Language changes become active on reload.":["转换语言需重启程序"],"Default room":["系统默认房间"],"Set alternative room to join at start.":["重设初始默认房间"],"Desktop notification":["桌面提醒"],"Enable":["开启"],"Denied - check your browser settings":["被拒绝--请检查浏览器设置"],"Allowed":["启用"],"Advanced settings":["高级设置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大视频帧速率"],"auto":["自动"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展开高级设置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["记住设置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在线"],"Calling":["呼叫中"],"Hangup":["挂断"],"In call with":["正在和**通话"],"Conference with":["和**会议通话"],"Your are offline":["您不在线"],"Go online":["上线"],"Connection interrupted":["连接已中断"],"An error occured":["出现错误"],"Incoming call":["来电"],"from":["来自"],"Accept call":["接受通话"],"Waiting for camera/microphone access":["等待摄像头/麦克风连接"],"Checking camera and microphone access.":["正在检查摄像头及麦克风连接"],"Please allow access to your camera and microphone.":["请允许连接您的摄像头及麦克风"],"Camera / microphone access required.":["需连接摄像头/麦克风"],"Please check your browser settings and allow camera and microphone access for this site.":["请检查浏览器设置并允许摄像头及麦克风连接此网站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["点击这里获取帮助 (Google Chrome)"],"Please set your user details and settings.":["请设定您的用户信息及设置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天已启动"],"Peer to peer chat is now off.":["P2P现在未启动"]," is now offline.":[" 不在线"]," is now online.":[" 现在在线"],"You share file:":["分享文件:"],"Incoming file:":["发来文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["适用更新需重启,现在点击Ok重新启动。"],"Failed to access camera/microphone.":["摄像头/麦克风连接失败"],"Failed to establish peer connection.":["对等连接建立失败"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有错误发生。"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["对等连接失败,请检查设置。"],"User hung up because of error.":["用户因错误挂断"]," is busy. Try again later.":[" 正在通话,请稍后再试。"]," rejected your call.":[" 拒绝了您的呼叫。"]," does not pick up.":[" 无人接听。"],"Your browser does not support WebRTC. No calls possible.":["您的浏览器不支持WebRTC。不能进行通话。"],"Chat with":["与**聊天"],"Message from ":["来自于**的信息"],"You are now in room %s ...":["您在 %s 房间"],"Your browser does not support file transfer.":["您的浏览器不支持文件传输"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["启动屏幕共享许可被拒绝。请确认您已开启浏览器屏幕共享连接。请复制chrome://flags/#enable-usermedia-screen-capture并用您的浏览器打开,启用最上端的功能。然后重启浏览器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用浏览器语言"],"Meet with me here:":["我们这里见:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["错误"],"Hint":["提示"],"Please confirm":["请确认"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入码"],"Access denied":["连接被拒绝"],"Please provide a valid access code.":["请提供有效接入码"],"Failed to verify access code. Check your Internet connection and try again.":["接入码认证失败。请检查您的网络连接并重试。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用户"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file diff --git a/static/translation/messages-zh-tw.json b/static/translation/messages-zh-tw.json index c329c070..5bc5fa81 100644 --- a/static/translation/messages-zh-tw.json +++ b/static/translation/messages-zh-tw.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":[null,"您的通話音量"],"Standard view":[null,""],"Large view":[null,""],"Kiosk view":[null,""],"Auditorium":[null,""],"Start chat":[null,"開始聊天"],"Start video call":[null,"開始視頻通話"],"Start audio conference":[null,"開始語音會議"],"No one else here":[null,""],"Take":[null,""],"Retake":[null,""],"Cancel":[null,"取消"],"Set as Profile Picture":[null,""],"Take picture":[null,"拍照"],"Waiting for camera":[null,"等待啟動攝像頭"],"The file couldn't be read.":[null,""],"The file is not an image.":[null,""],"The file is too large. Max. %d MB.":[null,""],"Select file":[null,""],"Chat sessions":[null,"會話"],"Room chat":[null,"房間聊天"],"Peer to peer":[null,"P2P"],"Close chat":[null,"關閉聊天"],"Share my location":[null,""],"is typing...":[null,"正在輸入..."],"has stopped typing...":[null,"停止輸入..."],"Type here to chat...":[null,"在此輸入開始聊天..."],"Send":[null,"發送"],"Accept":[null,""],"Reject":[null,"拒絕"],"You have no contacts.":[null,""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[null,""],"Edit contact":[null,""],"Edit":[null,""],"Name":[null,"名字"],"Remove":[null,""],"Refresh":[null,""],"Save":[null,""],"Close":[null,"關閉"],"File sharing":[null,"分享文件"],"File is no longer available":[null,"文件已不存在"],"Download":[null,"下載"],"Open":[null,"打開"],"Unshare":[null,"停止分享"],"Retry":[null,"重試"],"Download failed.":[null,"下載失敗"],"Share a YouTube video":[null,""],"Share a file as presentation":[null,""],"Share your screen":[null,"共享您的屏幕"],"Chat":[null,"聊天"],"Contacts":[null,""],"Mute microphone":[null,"關閉麥克風"],"Turn camera off":[null,"關閉攝像頭"],"Settings":[null,"系統設置"],"Loading presentation ...":[null,""],"Please upload a document":[null,""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[null,""],"Upload":[null,""],"You can drag files here too.":[null,""],"Presentation controls":[null,""],"Prev":[null,""],"Next":[null,""],"Change room":[null,"更換房間"],"Room":[null,"房間"],"Leave room":[null,"離開房間"],"Main":[null,"住房間"],"Current room":[null,"當前房間"],"Screen sharing options":[null,"屏幕共享設置"],"Fit screen.":[null,"適合屏幕"],"Profile":[null,""],"Your name":[null,"您的名字"],"Your picture":[null,"您的圖片"],"Status message":[null,""],"What's on your mind?":[null,""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[null,""],"Your ID":[null,""],"Register":[null,""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[null,""],"Sign in":[null,""],"Create an account":[null,""],"Sign out":[null,""],"Manage account":[null,""],"Media":[null,""],"Microphone":[null,"麥克風"],"Camera":[null,"攝像頭"],"Video quality":[null,"視頻質量"],"Low":[null,"低"],"High":[null,"高"],"HD":[null,"高清"],"Full HD":[null,""],"General":[null,""],"Language":[null,"語言"],"Language changes become active on reload.":[null,"轉換語言需要重啟程序"],"Default room":[null,"系統默認房間"],"Set alternative room to join at start.":[null,"重設初始默認房間"],"Desktop notification":[null,"桌面提醒"],"Enable":[null,"開啟"],"Denied - check your browser settings":[null,"被拒絕﹣請檢查瀏覽器設置"],"Allowed":[null,"啟用"],"Advanced settings":[null,"高級設置"],"Play audio on same device as selected microphone":[null,""],"Experimental AEC":[null,""],"Experimental AGC":[null,""],"Experimental noise suppression":[null,""],"Max video frame rate":[null,"最大視頻幀速率"],"auto":[null,"自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[null,""],"Detect CPU over use":[null,""],"Automatically reduces video quality as needed.":[null,""],"Optimize for high resolution video":[null,""],"Reduce video noise":[null,""],"Enable experiments":[null,""],"Show advanced settings":[null,"展開高級設置"],"Hide advanced settings":[null,"隐藏高级设置"],"Remember settings":[null,"記住設置"],"Your ID will still be kept - press the log out button above to delete the ID.":[null,""],"Room link":[null,""],"Invite with Facebook":[null,""],"Invite with Twitter":[null,""],"Invite with Google Plus":[null,""],"Invite with XING":[null,""],"Initializing":[null,"初始化"],"Online":[null,"在線"],"Calling":[null,"呼叫中"],"Hangup":[null,"掛斷"],"In call with":[null,"正在和**通電話"],"Conference with":[null,"和**會議通話"],"Your are offline":[null,"您不在線"],"Go online":[null,"上線"],"Connection interrupted":[null,"連接已終端"],"An error occured":[null,"出現錯誤"],"Incoming call":[null,"來電"],"from":[null,"來自"],"Accept call":[null,"接受通話"],"Waiting for camera/microphone access":[null,"等待攝像頭/麥克風連接"],"Checking camera and microphone access.":[null,"正在檢查攝像頭及麥克風連接"],"Please allow access to your camera and microphone.":[null,"請允許連接您的攝像頭及麥克風"],"Camera / microphone access required.":[null,"需連接攝像頭/麥克風"],"Please check your browser settings and allow camera and microphone access for this site.":[null,"請檢查瀏覽器設置並允許攝像頭及麥克風連接此網站"],"Skip check":[null,"越过检查"],"Click here for help (Google Chrome).":[null,"點擊這裡獲取幫助 (Google Chrome)"],"Please set your user details and settings.":[null,"請設定您的用戶信息及設置"],"Enter a room name":[null,""],"Random room name":[null,""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[null,""],"Room history":[null,""],"Please sign in.":[null,""],"Videos play simultaneously for everyone in this call.":[null,""],"YouTube URL":[null,""],"Could not load YouTube player API, please check your network / firewall settings.":[null,""],"Currently playing":[null,""],"YouTube controls":[null,""],"YouTube video to share":[null,""],"Peer to peer chat active.":[null,"P2P聊天啟動"],"Peer to peer chat is now off.":[null,"P2P現在未啟動"]," is now offline.":[null," 不在線"]," is now online.":[null," 現在在線"],"You share file:":[null,"分享文件:"],"Incoming file:":[null,"發來文件:"],"You shared your location:":[null,""],"Location received:":[null,""],"You accepted the contact request.":[null,""],"You rejected the contact request.":[null,""],"You sent a contact request.":[null,""],"Your contact request was accepted.":[null,""],"Incoming contact request.":[null,""],"Your contact request was rejected.":[null,""],"Edit Contact":[null,""],"Close this window and disconnect?":[null,""],"Contacts Manager":[null,""],"Restart required to apply updates. Click ok to restart now.":[null,"適用更新需重啟,現在點擊Ok重新啟動。"],"Failed to access camera/microphone.":[null,"攝像頭/麥克風連接失敗"],"Failed to establish peer connection.":[null,"對等連接建立失敗"],"We are sorry but something went wrong. Boo boo.":[null,"很抱歉,有序哦嗚發生......"],"Oops":[null,"Oops"],"Peer connection failed. Check your settings.":[null,"對等連接失敗,請檢查設置。"],"User hung up because of error.":[null,"用戶因錯誤掛斷"]," is busy. Try again later.":[null," 正在通話,請您稍後。"]," rejected your call.":[null," 拒絕了您的呼叫"]," does not pick up.":[null," 無人接聽。"],"Your browser does not support WebRTC. No calls possible.":[null,"您的遊覽器不支持WebRTC。不能進行通話。"],"Chat with":[null,"于**聊天"],"Message from ":[null,"來自於**的信息"],"You are now in room %s ...":[null,"您在 %s 房間"],"Your browser does not support file transfer.":[null,"您的遊覽器不支持文件傳輸"],"Could not load PDF: Please make sure to select a PDF document.":[null,""],"Could not load PDF: Missing PDF file.":[null,""],"An error occurred while loading the PDF (%s).":[null,""],"An unknown error occurred while loading the PDF.":[null,""],"An error occurred while loading the PDF page (%s).":[null,""],"An unknown error occurred while loading the PDF page.":[null,""],"An error occurred while rendering the PDF page (%s).":[null,""],"An unknown error occurred while rendering the PDF page.":[null,""],"Only PDF documents and OpenDocument files can be shared at this time.":[null,""],"Failed to start screen sharing (%s).":[null,""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":[null,"啟動屏幕共享許可被拒絕。請確認您已開啟瀏覽器屏幕共享連接。請復制chrome://flags/#enable-usermedia-screen-capture並用您的瀏覽器打開,啟用最上端的功能。然後重啟瀏覽器,操作完成。"],"Permission to start screen sharing was denied.":[null,""],"Use browser language":[null,"使用瀏覽器語言"],"Meet with me here:":[null,"我們這裡見:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[null,""],"Error":[null,"錯誤"],"Hint":[null,"提示"],"Please confirm":[null,"請確認"],"More information required":[null,"需要更多信息"],"Ok":[null,"Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[null,""],"Access code required":[null,"需要接入碼"],"Access denied":[null,"連接被拒絕"],"Please provide a valid access code.":[null,"請提供有效接入碼"],"Failed to verify access code. Check your Internet connection and try again.":[null,"接入碼認證錯誤。請檢查您的網絡連接并重試。"],"PIN for room %s is now '%s'.":[null,""],"PIN lock has been removed from room %s.":[null,""],"Enter the PIN for room %s":[null,""],"Please sign in to create rooms.":[null,""],"and %s":[null,""],"and %d others":[null,""],"User":[null,"用戶"],"Someone":[null,"某人"],"Me":[null,"我"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通話音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["開始聊天"],"Start video call":["開始視頻通話"],"Start audio conference":["開始語音會議"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待啟動攝像頭"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["會話"],"Room chat":["房間聊天"],"Peer to peer":["P2P"],"Close chat":["關閉聊天"],"Share my location":[""],"is typing...":["正在輸入..."],"has stopped typing...":["停止輸入..."],"Type here to chat...":["在此輸入開始聊天..."],"Send":["發送"],"Accept":[""],"Reject":["拒絕"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["關閉"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下載"],"Open":["打開"],"Unshare":["停止分享"],"Retry":["重試"],"Download failed.":["下載失敗"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["關閉麥克風"],"Turn camera off":["關閉攝像頭"],"Settings":["系統設置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更換房間"],"Room":["房間"],"Leave room":["離開房間"],"Main":["住房間"],"Current room":["當前房間"],"Screen sharing options":["屏幕共享設置"],"Fit screen.":["適合屏幕"],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的圖片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麥克風"],"Camera":["攝像頭"],"Video quality":["視頻質量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["語言"],"Language changes become active on reload.":["轉換語言需要重啟程序"],"Default room":["系統默認房間"],"Set alternative room to join at start.":["重設初始默認房間"],"Desktop notification":["桌面提醒"],"Enable":["開啟"],"Denied - check your browser settings":["被拒絕﹣請檢查瀏覽器設置"],"Allowed":["啟用"],"Advanced settings":["高級設置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大視頻幀速率"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展開高級設置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["記住設置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在線"],"Calling":["呼叫中"],"Hangup":["掛斷"],"In call with":["正在和**通電話"],"Conference with":["和**會議通話"],"Your are offline":["您不在線"],"Go online":["上線"],"Connection interrupted":["連接已終端"],"An error occured":["出現錯誤"],"Incoming call":["來電"],"from":["來自"],"Accept call":["接受通話"],"Waiting for camera/microphone access":["等待攝像頭/麥克風連接"],"Checking camera and microphone access.":["正在檢查攝像頭及麥克風連接"],"Please allow access to your camera and microphone.":["請允許連接您的攝像頭及麥克風"],"Camera / microphone access required.":["需連接攝像頭/麥克風"],"Please check your browser settings and allow camera and microphone access for this site.":["請檢查瀏覽器設置並允許攝像頭及麥克風連接此網站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["點擊這裡獲取幫助 (Google Chrome)"],"Please set your user details and settings.":["請設定您的用戶信息及設置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天啟動"],"Peer to peer chat is now off.":["P2P現在未啟動"]," is now offline.":[" 不在線"]," is now online.":[" 現在在線"],"You share file:":["分享文件:"],"Incoming file:":["發來文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["適用更新需重啟,現在點擊Ok重新啟動。"],"Failed to access camera/microphone.":["攝像頭/麥克風連接失敗"],"Failed to establish peer connection.":["對等連接建立失敗"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有序哦嗚發生......"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["對等連接失敗,請檢查設置。"],"User hung up because of error.":["用戶因錯誤掛斷"]," is busy. Try again later.":[" 正在通話,請您稍後。"]," rejected your call.":[" 拒絕了您的呼叫"]," does not pick up.":[" 無人接聽。"],"Your browser does not support WebRTC. No calls possible.":["您的遊覽器不支持WebRTC。不能進行通話。"],"Chat with":["于**聊天"],"Message from ":["來自於**的信息"],"You are now in room %s ...":["您在 %s 房間"],"Your browser does not support file transfer.":["您的遊覽器不支持文件傳輸"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["啟動屏幕共享許可被拒絕。請確認您已開啟瀏覽器屏幕共享連接。請復制chrome://flags/#enable-usermedia-screen-capture並用您的瀏覽器打開,啟用最上端的功能。然後重啟瀏覽器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用瀏覽器語言"],"Meet with me here:":["我們這裡見:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["錯誤"],"Hint":["提示"],"Please confirm":["請確認"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入碼"],"Access denied":["連接被拒絕"],"Please provide a valid access code.":["請提供有效接入碼"],"Failed to verify access code. Check your Internet connection and try again.":["接入碼認證錯誤。請檢查您的網絡連接并重試。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用戶"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file From 34fdf0b18f1cc68484b8ecfc81e9bc336bec7649 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 1 Apr 2015 14:25:27 +0200 Subject: [PATCH 008/121] Rebuilt styles. --- static/css/main.min.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/main.min.css b/static/css/main.min.css index 7b43d08f..e15483a9 100644 --- a/static/css/main.min.css +++ b/static/css/main.min.css @@ -17,4 +17,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}.withBuddylist #rightslide{right:0}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.bar .left .logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.bar .left .logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.bar .left .logo span{display:none}}.bar .left .logo span{font-style:italic;left:38px;position:relative;top:26px}.bar .left .logo span a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.bar .right .btn-mutemicrophone i:before{content:'\f130'}.bar .right .btn-mutemicrophone.active i:before{content:'\f131'}.bar .right .btn-mutecamera i:before{content:'\f06e'}.bar .right .btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddy .buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddy .buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddy .buddysessions ul li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddy .buddysessions ul li .btn-group{visibility:hidden}.buddy .buddysessions ul li:hover .btn-group{visibility:visible}.buddy .buddysessions .currentsession .buddy3{font-weight:bold}.buddy.hovered .buddysessions{max-height:999px}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.active.visible{display:block}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}@media only screen and (max-width: 400px){#help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){#help{font-size:1em;width:250px}}#help>div{margin:0 10px}#help .help-subline{color:#888;padding:20px 0}#help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;left:41px;overflow:hidden;position:absolute;right:0;top:-17px;z-index:2}.file-info .file-info-bg .fa{color:#eee;font-size:20em}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg .fa{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}.file-info.uploader .file-info-speed{bottom:6px}.file-info.uploader .actions{margin-left:30px;opacity:0}.file-info.uploader .anim{margin-left:0}.file-info.uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info.uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info.uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.mainScreenshare #screenshare{display:block}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}.screenshare .overlaybar{bottom:0;left:0;right:0}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager .table tr:first-child td{border-top:0}.contactsmanager .table .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .table .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome h1{white-space:normal}.presentationpane .welcome button{margin-top:30px}.presentationpane .welcome .progress span{text-shadow:none}.presentationpane .welcome .progress .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.mainPresentation #presentation{display:block}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.pageinfo input{display:inline;width:70px}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail .filetype{font-size:5em}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideo .overlaybar-content form .overlaybar-buttons{position:absolute;right:23px;top:6px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} + *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}.withBuddylist #rightslide{right:0}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.logo .desc{display:none}}.logo .desc{font-style:italic;left:38px;position:relative;top:26px}.logo .desc a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.btn-mutemicrophone i:before{content:'\f130'}.btn-mutemicrophone.active i:before{content:'\f131'}.btn-mutecamera i:before{content:'\f06e'}.btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddysessions li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddysessions li:hover .btn-group{visibility:visible}.buddysessions .btn-group{visibility:hidden}.buddysessions .currentsession .buddy3{font-weight:bold}.buddy.hovered .buddysessions{max-height:999px}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.active.visible{display:block}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .message.with_hoverimage .buddyPicture{overflow:visible;z-index:initial}.chat .message.with_hoverimage .buddyPicture:hover .buddyInfoActions{height:40px;opacity:1}.chat .message.with_hoverimage .buddyInfoActions{cursor:default;display:inline-block;height:0;left:0;opacity:0;overflow:hidden;position:absolute;top:48px;-webkit-transition:opacity 0.1s .1s linear, height .4s .1s ease-out;transition:opacity 0.1s .1s linear, height .4s .1s ease-out;white-space:nowrap;z-index:1}.chat .message.with_hoverimage .buddyInfoActions .btn-group{display:block;margin:0 auto;width:55px}.chat .message.with_hoverimage .buddyInfoActions .btn-primary{padding:2px 5px}.chat .message.with_hoverimage .buddyInfoActions .fa{color:#fff;line-height:24px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}@media only screen and (max-width: 400px){#help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){#help{font-size:1em;width:250px}}#help>div{margin:0 10px}#help .help-subline{color:#888;padding:20px 0}#help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;color:#eee;font-size:20em;left:41px;overflow:hidden;position:absolute;right:0;top:-82px;z-index:2}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}.file-info.uploader .file-info-speed{bottom:6px}.file-info.uploader .actions{margin-left:30px;opacity:0}.file-info.uploader .anim{margin-left:0}.file-info.uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info.uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info.uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.mainScreenshare #screenshare{display:block}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}.screenshare .overlaybar{bottom:0;left:0;right:0}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager tr:first-child td{border-top:0}.contactsmanager .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.mainPresentation #presentation{display:block}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome .btn{margin-top:30px}.presentationpane h1{white-space:normal}.presentationpane .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.pageinfo input{display:inline;width:70px}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail .filetype{font-size:5em}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideo .overlaybar-content .overlaybar-buttons{position:absolute;right:23px;top:6px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} From e967ff59070eb2dee920baeb7442eb9ab2e6eb52 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 2 Apr 2015 12:03:42 +0200 Subject: [PATCH 009/121] Fixed an issue where replaced sessions cannot receive data from contacts in other rooms. --- src/app/spreed-webrtc-server/client.go | 18 ++++-- src/app/spreed-webrtc-server/hub.go | 8 +-- src/app/spreed-webrtc-server/session.go | 73 +++++++++++++++++-------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/app/spreed-webrtc-server/client.go b/src/app/spreed-webrtc-server/client.go index c9f3bb41..b858176b 100644 --- a/src/app/spreed-webrtc-server/client.go +++ b/src/app/spreed-webrtc-server/client.go @@ -43,7 +43,7 @@ type Client interface { Session() *Session Index() uint64 Close() - ReplaceAndClose() + ReplaceAndClose(Client) } type client struct { @@ -87,9 +87,15 @@ func (client *client) Session() *Session { return client.session } -func (client *client) ReplaceAndClose() { - client.session.Close() - if client.Connection != nil { - client.Connection.Close() - } +func (client *client) ReplaceAndClose(oldClient Client) { + oldSession := oldClient.Session() + client.session.Replace(oldSession) + go func() { + // Close old session and client in another go routine, + // to avoid blocking the new client if the old one hangs or + // whatever. + log.Printf("Closing obsolete client %d (replaced with %d) with id %s\n", oldClient.Index(), client.Index(), oldSession.Id) + oldSession.Close() + oldClient.Close() + }() } diff --git a/src/app/spreed-webrtc-server/hub.go b/src/app/spreed-webrtc-server/hub.go index 963c74b9..6a7dcd26 100644 --- a/src/app/spreed-webrtc-server/hub.go +++ b/src/app/spreed-webrtc-server/hub.go @@ -154,12 +154,8 @@ func (h *hub) OnConnect(client Client, session *Session) { log.Printf("Created client %d with id %s\n", client.Index(), session.Id) // Register connection or replace existing one. if ec, ok := h.clients[session.Id]; ok { - // Clean up old client at the end and make sure to run this in another go routine, - // to avoid blocking the new client if the old one hangs or whatever. - go func() { - log.Printf("Closing obsolete client %d (replaced with %d) with id %s\n", ec.Index(), client.Index(), session.Id) - ec.ReplaceAndClose() - }() + // Clean up old client at the end outside the hub lock. + defer client.ReplaceAndClose(ec) } h.clients[session.Id] = client h.mutex.Unlock() diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index 2adcc0e2..a60a9347 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -56,6 +56,7 @@ type Session struct { subscriptions map[string]*Session subscribers map[string]*Session disconnected bool + replaced bool } func NewSession(manager SessionManager, unicaster Unicaster, broadcaster Broadcaster, rooms RoomStatusManager, buddyImages ImageCache, attestations *securecookie.SecureCookie, id, sid string) *Session { @@ -209,33 +210,38 @@ func (s *Session) Close() { return } - outgoing := &DataOutgoing{ - From: s.Id, - A: s.attestation.Token(), - Data: &DataSession{ - Type: "Left", - Id: s.Id, - Status: "hard", - }, - } + // TODO(longsleep): Verify that it is ok to not do all this when replaced is true. + if !s.replaced { - if s.Hello { - // NOTE(lcooper): If we don't check for Hello here, we could deadlock - // when implicitly creating a room while a user is reconnecting. - s.Broadcaster.Broadcast(s.Id, s.Roomid, outgoing) - s.RoomStatusManager.LeaveRoom(s.Roomid, s.Id) - } + outgoing := &DataOutgoing{ + From: s.Id, + A: s.attestation.Token(), + Data: &DataSession{ + Type: "Left", + Id: s.Id, + Status: "hard", + }, + } - for _, session := range s.subscribers { - s.Unicaster.Unicast(session.Id, outgoing) - } + if s.Hello { + // NOTE(lcooper): If we don't check for Hello here, we could deadlock + // when implicitly creating a room while a user is reconnecting. + s.Broadcaster.Broadcast(s.Id, s.Roomid, outgoing) + s.RoomStatusManager.LeaveRoom(s.Roomid, s.Id) + } - for _, session := range s.subscriptions { - session.RemoveSubscriber(s.Id) - } + for _, session := range s.subscribers { + s.Unicaster.Unicast(session.Id, outgoing) + } + + for _, session := range s.subscriptions { + session.RemoveSubscriber(s.Id) + } - s.SessionManager.DestroySession(s.Id, s.userid) - s.buddyImages.Delete(s.Id) + s.SessionManager.DestroySession(s.Id, s.userid) + s.buddyImages.Delete(s.Id) + + } s.subscriptions = make(map[string]*Session) s.subscribers = make(map[string]*Session) @@ -244,6 +250,27 @@ func (s *Session) Close() { s.mutex.Unlock() } +func (s *Session) Replace(oldSession *Session) { + + oldSession.mutex.Lock() + if oldSession.disconnected { + oldSession.mutex.Unlock() + return + } + + s.mutex.Lock() + + s.subscriptions = oldSession.subscriptions + s.subscribers = oldSession.subscribers + + s.mutex.Unlock() + + // Mark old session as replaced. + oldSession.replaced = true + oldSession.mutex.Unlock() + +} + func (s *Session) Update(update *SessionUpdate) uint64 { s.mutex.Lock() defer s.mutex.Unlock() From c188dc37554a8e238a28e48dcb6a42a25f76baf7 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 2 Apr 2015 13:27:33 +0200 Subject: [PATCH 010/121] Removed debug. --- static/js/directives/chat.js | 1 - 1 file changed, 1 deletion(-) diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index 75f06755..59698005 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -249,7 +249,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro subscope.sendChat = function(to, message, status, mid, noloop) { //console.log("send chat", to, scope.peer); if (message && message.length > maxMessageSize) { - console.log("XXXXXXX", message.length); return mid; } var peercall = mediaStream.webrtc.findTargetCall(to); From 9457c2d391a37ed91bc51fa517186f1723cdc38d Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 2 Apr 2015 14:05:34 +0200 Subject: [PATCH 011/121] Removed obsolete code. --- static/js/services/buddylist.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/static/js/services/buddylist.js b/static/js/services/buddylist.js index 07e46768..563cf9cd 100644 --- a/static/js/services/buddylist.js +++ b/static/js/services/buddylist.js @@ -675,18 +675,8 @@ define(['jquery', 'angular', 'underscore', 'modernizr', 'avltree', 'text!partial // Find session with help of contact. if (contact && contact.Token) { mediaStream.api.sendSessions(contact.Token, "contact", function(event, type, data) { - //console.log("oooooooooooooooo", type, data); var tmpSessionData = null; if (data.Users && data.Users.length > 0) { - /* - _.each(data.Users, function(s) { - buddyData.set(s.Id, scope); - // NOTE(longsleep): Not sure if its a good idea to add the retrieved sessions here. - session.add(s.Id, s); - }); - sessionData = session.get(); - deferred.resolve(sessionData.Id); - */ tmpSessionData = data.Users[0]; } // Check if we got a session in the meantime. From 369d53fef9838e1689012c1169f2faa92b2eca88 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 2 Apr 2015 16:37:54 +0200 Subject: [PATCH 012/121] Reenable chat rooms on certain conditions related to peer connectivity. --- static/js/directives/chat.js | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index 59698005..18e971a4 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -78,7 +78,7 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro if (!with_message) { return; } - // No room with this id, get one with the from id + // No room with this id, get one with the from id. $scope.$emit("startchat", from, { restore: with_message }); @@ -90,14 +90,19 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro room.peerIsTyping = "no"; room.p2p( !! p2p); if (room.firstmessage) { + // Auto show when this is the first message. $scope.showRoom(room.id, null, { restore: with_message }); } + if (!room.enabled) { + // Reenable chat room when receiving messages again. + room.enabled = true; + } } - room.$broadcast("received", from, data); safeApply(room); + room.$broadcast("received", from, data); }); @@ -108,10 +113,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro case "Left": if (data.Status !== "soft") { room.enabled = false; - room.$broadcast("received", data.Id, { - Type: "LeftOrJoined", - "LeftOrJoined": "left" - }); safeApply(room); } break; @@ -119,10 +120,6 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro if (!room.enabled) { room.enabled = true; _.delay(function() { - room.$broadcast("received", data.Id, { - Type: "LeftOrJoined", - "LeftOrJoined": "joined" - }); safeApply(room); }, 1000); } @@ -397,6 +394,22 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro } } }); + subscope.$watch("enabled", function(enabled, old) { + if (enabled === old) { + return; + } + //console.log("enabled", enabled, old); + var value; + if (enabled) { + value = "resumed"; + } else { + value = "left"; + } + subscope.$broadcast("received", subscope.id, { + Type: "LeftOrJoined", + "LeftOrJoined": value + }); + }); chat(subscope, function(clonedElement, $scope) { pane.append(clonedElement); @@ -444,6 +457,9 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro subscope.index = index; subscope.visible = true; } + if (!subscope.enabled) { + subscope.enabled = true; + } } if (options.autofocus && subscope.visible) { subscope.$broadcast("focus"); From bf516b542340d1bb2747a3ae35599825be30b630 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 2 Apr 2015 17:47:05 +0200 Subject: [PATCH 013/121] Make sure to send session close messages to subscriptions too to notify both ways. --- src/app/spreed-webrtc-server/session.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index a60a9347..c226e6c0 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -86,16 +86,13 @@ func (s *Session) authenticated() (authenticated bool) { } func (s *Session) Subscribe(session *Session) { - s.mutex.Lock() s.subscriptions[session.Id] = session s.mutex.Unlock() session.AddSubscriber(s) - } func (s *Session) Unsubscribe(id string) { - s.mutex.Lock() if session, ok := s.subscriptions[id]; ok { delete(s.subscriptions, id) @@ -104,7 +101,6 @@ func (s *Session) Unsubscribe(id string) { } else { s.mutex.Unlock() } - } func (s *Session) AddSubscriber(session *Session) { @@ -236,6 +232,7 @@ func (s *Session) Close() { for _, session := range s.subscriptions { session.RemoveSubscriber(s.Id) + s.Unicaster.Unicast(session.Id, outgoing) } s.SessionManager.DestroySession(s.Id, s.userid) From c9bc20d3dc01a350eabf7dc4799321a7dd3bb0df Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Thu, 5 Mar 2015 17:39:28 +0100 Subject: [PATCH 014/121] Fix scss-lint error MergeableSelector. --- src/styles/components/_audiovideo.scss | 263 +++---- src/styles/components/_buddylist.scss | 130 ++-- .../components/_buddypicturecapture.scss | 6 +- .../components/_buddypictureupload.scss | 15 +- src/styles/components/_chat.scss | 716 +++++++++--------- src/styles/components/_fileinfo.scss | 105 +-- src/styles/components/_presentation.scss | 301 ++++---- src/styles/components/_rightslide.scss | 12 +- src/styles/components/_roombar.scss | 13 +- src/styles/components/_screenshare.scss | 21 +- src/styles/components/_settings.scss | 37 +- src/styles/components/_usability.scss | 22 +- src/styles/components/_youtubevideo.scss | 185 ++--- src/styles/global/_overlaybar.scss | 44 +- 14 files changed, 919 insertions(+), 951 deletions(-) diff --git a/src/styles/components/_audiovideo.scss b/src/styles/components/_audiovideo.scss index 1eaea45d..d2ea565f 100644 --- a/src/styles/components/_audiovideo.scss +++ b/src/styles/components/_audiovideo.scss @@ -26,9 +26,7 @@ right: 0; top: $minbarheight; user-select: none; -} -#audiovideo { @include breakpt($breakpoint-video-small, max-width, only screen) { right: 0; } @@ -109,9 +107,7 @@ video { object-fit: cover; } -} -.audiovideo { .remoteContainer { bottom: 0; left: 0; @@ -159,132 +155,131 @@ transition-property: opacity; width: 100%; } -} - -.audiovideo .remoteVideos { - bottom: 0; - left: 0; - opacity: 0; - position: absolute; - right: 0; - top: 0; - transition-duration: 2s; - transition-property: opacity; - - video { - display: block; - height: 100%; - width: 100%; - } -} - -.audiovideo .remoteVideo { - background: $video-background; - display: inline-block; - max-height: 100%; - max-width: 100%; - overflow: hidden; - position: relative; - vertical-align: bottom; - //visibility: hidden; - width: 100%; - &.withvideo { - //visibility: visible; - } + .remoteVideos { + bottom: 0; + left: 0; + opacity: 0; + position: absolute; + right: 0; + top: 0; + transition-duration: 2s; + transition-property: opacity; - &.onlyaudio { - background: $video-onlyaudio-background; - //visibility: visible; + video { + display: block; + height: 100%; + width: 100%; + } } - .onlyaudio { - color: $video-onlyaudio; - display: none; - font-size: 80px; + .overlayActions { + background: $video-overlayactions; + bottom: 0; + height: 140px; left: 0; - margin-top: -40px; - pointer-events: auto; + margin: auto 0; + opacity: 0; + padding: 3px 0; position: absolute; - right: 0; - text-align: center; - top: 45%; - } + top: 0; + width: 40px; + z-index: 5; - &.onlyaudio video, - &.dummy video { - visibility: hidden; + .btn { + color: #ccc; + cursor: pointer; + display: block; + outline: 0; + text-shadow: 0 0 5px #000; + width: 40px; + } } - &.onlyaudio .onlyaudio { - display: block; - } + .remoteVideo { + background: $video-background; + display: inline-block; + max-height: 100%; + max-width: 100%; + overflow: hidden; + position: relative; + vertical-align: bottom; + //visibility: hidden; + width: 100%; - &.dummy .onlyaudio { - display: block; - } + &.withvideo { + //visibility: visible; + } - .peerActions { - // scss-lint:disable SelectorDepth - bottom: 5%; - left: 40px; - opacity: 0; - pointer-events: auto; - position: absolute; - right: 40px; - text-align: center; - transition-duration: .2s; - transition-property: opacity; - z-index: 10; + &.onlyaudio { + background: $video-onlyaudio-background; + //visibility: visible; + + .onlyaudio { + display: block; + } + } - &:hover { - opacity: .5; + .onlyaudio { + color: $video-onlyaudio; + display: none; + font-size: 80px; + left: 0; + margin-top: -40px; + pointer-events: auto; + position: absolute; + right: 0; + text-align: center; + top: 45%; } - i { - font-size: 3vw; + &.onlyaudio video, + &.dummy video { + visibility: hidden; } - } - .peerLabel { - bottom: 4%; - color: #fff; - font-size: 2.5vw; - left: 4%; - max-width: 30%; - opacity: .7; - overflow: hidden; - padding: 4px; - position: absolute; - text-overflow: ellipsis; - text-shadow: 0 0 4px #000; - white-space: nowrap; - z-index: 8; - } -} + &.dummy .onlyaudio { + display: block; + } -.audiovideo .overlayActions { - background: $video-overlayactions; - bottom: 0; - height: 140px; - left: 0; - margin: auto 0; - opacity: 0; - padding: 3px 0; - position: absolute; - top: 0; - width: 40px; - z-index: 5; + .peerActions { + // scss:lint:disable NestingDepth, SelectorDepth + bottom: 5%; + left: 40px; + opacity: 0; + pointer-events: auto; + position: absolute; + right: 40px; + text-align: center; + transition-duration: .2s; + transition-property: opacity; + z-index: 10; + + &:hover { + opacity: .5; + } + + i { + font-size: 3vw; + } + } - .btn { - color: #ccc; - cursor: pointer; - display: block; - outline: 0; - text-shadow: 0 0 5px #000; - width: 40px; + .peerLabel { + bottom: 4%; + color: #fff; + font-size: 2.5vw; + left: 4%; + max-width: 30%; + opacity: .7; + overflow: hidden; + padding: 4px; + position: absolute; + text-overflow: ellipsis; + text-shadow: 0 0 4px #000; + white-space: nowrap; + z-index: 8; + } } - } .remoteVideo { @@ -327,28 +322,6 @@ } } -.renderer-auditorium { - position: relative; - - span:before { - content: '\f183'; - left: 50%; - margin-left: -.8em; - margin-top: -.5em; - position: absolute; - top: 50%; - } - - span:after { - content: '\f183'; - margin-right: -.9em; - margin-top: -.5em; - position: absolute; - right: 50%; - top: 50%; - } -} - .renderer-smally { // scss-lint:disable SelectorDepth background: #000; @@ -457,6 +430,26 @@ } .renderer-auditorium { + position: relative; + + span:before { + content: '\f183'; + left: 50%; + margin-left: -.8em; + margin-top: -.5em; + position: absolute; + top: 50%; + } + + span:after { + content: '\f183'; + margin-right: -.9em; + margin-top: -.5em; + position: absolute; + right: 50%; + top: 50%; + } + .remoteContainer { border-left: 40px solid #000; } @@ -467,10 +460,6 @@ top: 180px; width: 320px; - .overlayLogo { - display: none; - } - video { height: 100%; margin-top: -9px; diff --git a/src/styles/components/_buddylist.scss b/src/styles/components/_buddylist.scss index 5cc99341..6560a5af 100644 --- a/src/styles/components/_buddylist.scss +++ b/src/styles/components/_buddylist.scss @@ -76,9 +76,7 @@ position: absolute; right: 0; top: 0; -} -.buddylist { &.loading { .buddylistloading { display: block; @@ -139,13 +137,11 @@ position: relative; text-align: left; width: 100%; -} -.buddy:hover { - background: $buddylist-action-background; -} + &:hover { + background: $buddylist-action-background; + } -.buddy { &.withSubline .buddy1, &.contact .buddy1 { top: 15px; @@ -156,8 +152,15 @@ display: block; } - &.hovered .buddyactions { - right: 0; + &.hovered { + + .buddyactions { + right: 0; + } + + .buddysessions { + max-height: 999px; + } } .fa.contact:before { @@ -249,68 +252,65 @@ white-space: nowrap; width: 120px; } -} -.buddy .buddyactions { - background: $buddylist-action-background; - height: 66px; - line-height: 66px; - padding: 0 10px; - position: absolute; - right: -125px; - text-align: right; - top: 0; - transition-duration: .3s; - transition-property: right; - white-space: nowrap; - z-index: 5; - - .btn { - font-size: $buddylist-action-font-size; - height: 40px; - line-height: 40px; - padding: 0; - text-align: center; - vertical-align: middle; - width: 42px; + .buddyactions { + background: $buddylist-action-background; + height: 66px; + line-height: 66px; + padding: 0 10px; + position: absolute; + right: -125px; + text-align: right; + top: 0; + transition-duration: .3s; + transition-property: right; + white-space: nowrap; + z-index: 5; + + .btn { + font-size: $buddylist-action-font-size; + height: 40px; + line-height: 40px; + padding: 0; + text-align: center; + vertical-align: middle; + width: 42px; + } } -} -.buddysessions { - margin-bottom: 10px; - margin-top: 56px; - max-height: 0; - transition-delay: .1s; - transition-duration: .5s; - transition-property: max-height; - - ul { - border-left: 1px dotted $bordercolor; - border-right: 1px dotted $bordercolor; - margin: 0 14px; - padding-left: 0; - padding-top: 10px; - } + .buddysessions { + margin-bottom: 10px; + margin-top: 56px; + max-height: 0; + transition-delay: .1s; + transition-duration: .5s; + transition-property: max-height; + + ul { + border-left: 1px dotted $bordercolor; + border-right: 1px dotted $bordercolor; + margin: 0 14px; + padding-left: 0; + padding-top: 10px; + } - li { - list-style-type: none; - margin-bottom: 2px; - margin-left: 0; + ul li { + // scss-lint:disable NestingDepth + list-style-type: none; + margin-bottom: 2px; + margin-left: 0; - &:hover .btn-group { - visibility: visible; - } - } + .btn-group { + visibility: hidden; + } - .btn-group { - visibility: hidden; - } + &:hover .btn-group { + visibility: visible; + } + } - .currentsession .buddy3 { - font-weight: bold; + .currentsession .buddy3 { + font-weight: bold; + } } } - -.buddy.hovered .buddysessions { - max-height: 999px; -} diff --git a/src/styles/components/_buddypicturecapture.scss b/src/styles/components/_buddypicturecapture.scss index 225e9cc1..02104c2b 100644 --- a/src/styles/components/_buddypicturecapture.scss +++ b/src/styles/components/_buddypicturecapture.scss @@ -61,10 +61,10 @@ top: 0; visibility: hidden; z-index: 5; - } - .videoFlash.flash { - visibility: visible; + &.flash { + visibility: visible; + } } .preview { diff --git a/src/styles/components/_buddypictureupload.scss b/src/styles/components/_buddypictureupload.scss index 4f9edace..dfe2ef16 100644 --- a/src/styles/components/_buddypictureupload.scss +++ b/src/styles/components/_buddypictureupload.scss @@ -39,6 +39,7 @@ } .showUploadPicture { + // scss-lint:disable NestingDepth background-color: $componentbg; border: 1px solid $bordercolor; height: 200px; @@ -52,10 +53,14 @@ &.imgData { background-color: #000; - } - &.imgData .chooseUploadPicture { - display: none; + .chooseUploadPicture { + display: none; + } + + &:hover .imageUtilites { + visibility: visible; + } } .chooseUploadPicture { @@ -95,10 +100,6 @@ } } - .showUploadPicture.imgData:hover .imageUtilites { - visibility: visible; - } - .moveHorizontal { position: relative; top: -4px; diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss index 96da661c..1b979bff 100644 --- a/src/styles/components/_chat.scss +++ b/src/styles/components/_chat.scss @@ -135,6 +135,7 @@ } .chat { + // scss-lint:disable NestingDepth background: $chat-background; bottom: 0; display: none; @@ -143,450 +144,448 @@ position: absolute; right: 0; top: 0; -} - -.chat { - &.active { - &.visible { - display: block; - } - .chatbody { - // nothing + &.newmessage { + .chatheadertitle:after { + content: '***'; + position: absolute; + right: 32px; + top: 2px; } .chatheader { - // nothing + animation: newmessage 1s ease -.3s infinite; } } -} -.chatmenu { - height: 36px; - left: 0; - padding: 2px 4px; - position: absolute; - right: 0; - top: 36px; - - @include breakpt($breakpoint-chat-small, max-height) { - display: none; + &.active.visible { + display: block; } -} - -.chatbody { - border-left: 1px solid $bordercolor; - bottom: -1px; - left: 0; - position: absolute; - right: 0; - top: 74px; - @include breakpt($breakpoint-chat-small, max-height) { - border-top: 1px solid $bordercolor; - top: 0; - top: 0; - } -} + &.with_pictures .message { + &.is_self { + padding-right: 54px; -.chatheader { - background: $chat-header; - border-bottom: 1px solid $bordercolor; - border-left: 1px solid $bordercolor; - height: 36px; - left: 0; - line-height: 34px; - padding: 0 4px 0 8px; - position: absolute; - right: 0; - top: 0; + .timestamp { + right: 58px; + } + } - @include breakpt($breakpoint-chat-small, max-height) { - display: none; + &.is_remote { + padding-left: 58px; + } } - .chatstatusicon { - cursor: pointer; - display: block; - font-size: 1.4em; - height: 36px; + .chatbodybottom { + background: $chat-bottom-background; + bottom: 1px; left: 0; + margin: 0 auto; position: absolute; - text-align: center; - top: 0; - width: 36px; - } - - .chatheadertitle { - display: inline; - padding-left: 28px; - } - - .ctrl { - color: $chat-ctrl; - position: absolute; - right: 1px; - top: 0; + right: 0; - .#{$fa-css-prefix} { - cursor: pointer; - padding: 6px; + @include breakpt($breakpoint-chat-small, max-height) { + height: auto; } } - span { - display: inline-block; - max-width: 60%; + .typinghint { + color: $chat-typing; + font-size: .8em; + height: 14px; overflow: hidden; - pointer-events: none; - text-overflow: ellipsis; - vertical-align: middle; + padding: 0 6px; white-space: nowrap; - } -} - -.chat .outputbox { - bottom: 75px; - left: 0; - position: absolute; - right: 0; - top: 0; - @include breakpt($breakpoint-chat-small, max-height) { - bottom: 45px; + @include breakpt($breakpoint-chat-small, max-height) { + display: none; + } } -} -.chat .output { - height: 100%; - overflow-x: hidden; - overflow-y: auto; - padding: .4em 0; - - > i { - clear: both; - color: $chat-meta; - display: block; - font-size: .8em; - padding: 6px 0; - text-align: center; + .inputbox { + position: relative; - &.p2p { - font-weight: bold; - padding: 6px 0; + @include breakpt($breakpoint-chat-small, max-height) { + height: auto; } - } -} - -.chat.with_pictures .message { - &.is_self { - padding-right: 54px; - .timestamp { - right: 58px; + .btn { + display: none; + padding: .5em 1em; + position: absolute; + right: 6px; + top: 1px; } - } - &.is_remote { - padding-left: 58px; + > div { + border-top: 1px solid $bordercolor; + } } -} -.chat .message { - background: $chat-msg-background; - border: 1px solid $chat-msg-border; - border-radius: 6px; - box-shadow: 0 0 2px 0 $chat-msg-shadow; - clear: both; - display: block; - margin: 0 4px 2px 18px; - padding: 8px; - position: relative; - word-wrap: break-word; - - ul { - list-style-type: none; + .input { + border-color: transparent; + border-radius: 0; + box-shadow: none; + display: block; + height: 54px; margin: 0; - padding-left: 0; - } + max-height: 54px; /* FF hack */ + resize: none; + width: 100%; - li { - line-height: 1.1em; - margin: 4px 0; - padding-left: 1.2em; - position: relative; + @include breakpt($breakpoint-chat-small, max-height) { + max-height: 2.5em; + } - &:before { - color: $chat-msg-default-icon-color; - content: '\f075'; - font-family: FontAwesome; - left: 0; - position: absolute; - text-align: center; - width: 12px; + &:active, + &:focus { + border-color: $chat-input-border-color; } } - .timestamp { - color: $chat-timestamp; - font-size: .8em; + .outputbox { + bottom: 75px; + left: 0; position: absolute; - right: 8px; - text-align: right; - top: 8px; - } + right: 0; + top: 0; - .timestamp-space { - float: right; - height: 10px; - width: 40px; + @include breakpt($breakpoint-chat-small, max-height) { + bottom: 45px; + } } - strong { - display: block; - margin-right: 40px; - overflow: hidden; - padding-bottom: 2px; - text-overflow: ellipsis; - white-space: nowrap; - } -} + .output { + height: 100%; + overflow-x: hidden; + overflow-y: auto; + padding: .4em 0; -.chat .message { - &.is_self li:before { - color: $chat-msg-default-icon-color; - transform: scale(-1, 1); - } + > i { + clear: both; + color: $chat-meta; + display: block; + font-size: .8em; + padding: 6px 0; + text-align: center; - li { - &.unread:before { - color: $chat-msg-unread-icon-color; - content: $chat-msg-unread-icon; + &.p2p { + font-weight: bold; + padding: 6px 0; + } } + } + + .message { + // scss-lint:disable DuplicateProperty + background: $chat-msg-background; + border: 1px solid $chat-msg-border; + border-radius: 6px; + box-shadow: 0 0 2px 0 $chat-msg-shadow; + clear: both; + display: block; + margin: 0 4px 2px 18px; + padding: 8px; + position: relative; + word-wrap: break-word; - &.sending:before { - color: $chat-msg-sending-icon-color; - content: $chat-msg-sending-icon; + ul { + list-style-type: none; + margin: 0; + padding-left: 0; } - &.sent:before { - color: $chat-msg-sent-icon-color; - content: $chat-msg-sent-icon; + .timestamp { + color: $chat-timestamp; + font-size: .8em; + position: absolute; + right: 8px; + text-align: right; + top: 8px; } - &.delivered:before { - color: $chat-msg-delivered-icon-color; - content: $chat-msg-delivered-icon; + .timestamp-space { + float: right; + height: 10px; + width: 40px; } - &.received:before { - color: $chat-msg-received-icon-color; - content: $chat-msg-received-icon; + strong { + display: block; + margin-right: 40px; + overflow: hidden; + padding-bottom: 2px; + text-overflow: ellipsis; + white-space: nowrap; } - &.read:before { - color: $chat-msg-read-icon-color; - content: $chat-msg-read-icon; + li { + line-height: 1.1em; + margin: 4px 0; + padding-left: 1.2em; + position: relative; + + &:before { + color: $chat-msg-default-icon-color; + content: '\f075'; + font-family: FontAwesome; + left: 0; + position: absolute; + text-align: center; + width: 12px; + } + + &.unread:before { + color: $chat-msg-unread-icon-color; + content: $chat-msg-unread-icon; + } + + &.sending:before { + color: $chat-msg-sending-icon-color; + content: $chat-msg-sending-icon; + } + + &.sent:before { + color: $chat-msg-sent-icon-color; + content: $chat-msg-sent-icon; + } + + &.delivered:before { + color: $chat-msg-delivered-icon-color; + content: $chat-msg-delivered-icon; + } + + &.received:before { + color: $chat-msg-received-icon-color; + content: $chat-msg-received-icon; + } + + &.read:before { + color: $chat-msg-read-icon-color; + content: $chat-msg-read-icon; + } } - } -} -.chat .message { - &.is_self .buddyPicture { - left: auto; - right: 4px; - } + .buddyPicture { + background: $actioncolor1; + border-radius: 2px; + height: 46px; + left: 4px; + overflow: hidden; + position: absolute; + text-align: center; + top: 4px; + width: 46px; + z-index: 0; - .buddyPicture { - background: $actioncolor1; - border-radius: 2px; - height: 46px; - left: 4px; - overflow: hidden; - position: absolute; - text-align: center; - top: 4px; - width: 46px; - z-index: 0; + .#{$fa-css-prefix} { + color: $actioncolor2; + line-height: 46px; + } - .#{$fa-css-prefix} { - color: $actioncolor2; - line-height: 46px; + img { + bottom: 0; + display: block; + left: 0; + max-height: 100%; + max-width: 100%; + position: absolute; + right: 0; + top: 0; + } } - img { - bottom: 0; + &:before, + &:after { + border-style: solid; + content: ''; display: block; - left: 0; - max-height: 100%; - max-width: 100%; position: absolute; - right: 0; - top: 0; + width: 0; } - } -} -.chat .message { - // scss-lint:disable DuplicateProperty - &:before, - &:after { - border-style: solid; - content: ''; - display: block; - position: absolute; - width: 0; - } + &.is_remote { + background: $chat-msg-remote-background; - &.is_remote { - background: $chat-msg-remote-background; + &:before { // arrow border + border-color: transparent $chat-arrow-border; + border-width: 7px 11px 7px 0; + bottom: auto; + left: -12px; + top: 4px; + } - &:before { // arrow border - border-color: transparent $chat-arrow-border; - border-width: 7px 11px 7px 0; - bottom: auto; - left: -12px; - top: 4px; + &:after { // arrow background + border-color: transparent $chat-msg-remote-background; + border-width: 6px 10px 6px 0; + bottom: auto; + left: -11px; + top: 5px; + } } - &:after { // arrow background - border-color: transparent $chat-msg-remote-background; - border-width: 6px 10px 6px 0; - bottom: auto; - left: -11px; - top: 5px; - } - } + &.is_self { + background: $chat-msg-self-background; + margin-left: 4px; + margin-right: 18px; + padding-right: 0; - &.is_self { - background: $chat-msg-self-background; - margin-left: 4px; - margin-right: 18px; - padding-right: 0; - - &:before { // arrow border - border-color: transparent $chat-arrow-border; - border-width: 7px 0 7px 11px; - bottom: 4px; - bottom: auto; - right: -12px; - } + &:before { // arrow border + border-color: transparent $chat-arrow-border; + border-width: 7px 0 7px 11px; + bottom: 4px; + bottom: auto; + right: -12px; + } - &:after { // arrow background - border-color: transparent $chat-msg-self-background; - border-width: 6px 0 6px 10px; - bottom: 5px; - bottom: auto; - right: -11px; - } - } + &:after { // arrow background + border-color: transparent $chat-msg-self-background; + border-width: 6px 0 6px 10px; + bottom: 5px; + bottom: auto; + right: -11px; + } - &.with_name { - // none - } - &.with_hoverimage { - .buddyPicture { - overflow: visible; - z-index: initial; - &:hover .buddyInfoActions { - height: 40px; - opacity: 1; + li:before { + color: $chat-msg-default-icon-color; + transform: scale(-1, 1); } - } - .buddyInfoActions { - cursor: default; - display: inline-block; - height: 0; - left: 0; - opacity: 0; - overflow: hidden; - position: absolute; - top: 48px; - transition: opacity 0.1s .1s linear, height .4s .1s ease-out; - white-space: nowrap; - z-index: 1; - .btn-group { - display: block; - margin: 0 auto; - width: 55px; + + .buddyPicture { + left: auto; + right: 4px; } - .btn-primary { - padding: 2px 5px; + } + + &.with_name { + // none + } + + &.with_hoverimage { + + .buddyPicture { + overflow: visible; + z-index: initial; + + &:hover .buddyInfoActions { + height: 40px; + opacity: 1; + } } - .fa { - color: #fff; - line-height: 24px; + + .buddyInfoActions { + cursor: default; + display: inline-block; + height: 0; + left: 0; + opacity: 0; + overflow: hidden; + position: absolute; + top: 48px; + transition: opacity 0.1s .1s linear, height .4s .1s ease-out; + white-space: nowrap; + z-index: 1; + + .btn-group { + display: block; + margin: 0 auto; + width: 55px; + } + + .btn-primary { + padding: 2px 5px; + } + + .fa { + color: #fff; + line-height: 24px; + } } } } } -.chat { - .chatbodybottom { - background: $chat-bottom-background; - bottom: 1px; - left: 0; - margin: 0 auto; - position: absolute; - right: 0; +.chatmenu { + height: 36px; + left: 0; + padding: 2px 4px; + position: absolute; + right: 0; + top: 36px; - @include breakpt($breakpoint-chat-small, max-height) { - height: auto; - } + @include breakpt($breakpoint-chat-small, max-height) { + display: none; } +} - .typinghint { - color: $chat-typing; - font-size: .8em; - height: 14px; - overflow: hidden; - padding: 0 6px; - white-space: nowrap; +.chatbody { + border-left: 1px solid $bordercolor; + bottom: -1px; + left: 0; + position: absolute; + right: 0; + top: 74px; - @include breakpt($breakpoint-chat-small, max-height) { - display: none; - } + @include breakpt($breakpoint-chat-small, max-height) { + border-top: 1px solid $bordercolor; + top: 0; + top: 0; } +} - .inputbox { - position: relative; +.chatheader { + background: $chat-header; + border-bottom: 1px solid $bordercolor; + border-left: 1px solid $bordercolor; + height: 36px; + left: 0; + line-height: 34px; + padding: 0 4px 0 8px; + position: absolute; + right: 0; + top: 0; - @include breakpt($breakpoint-chat-small, max-height) { - height: auto; - } + @include breakpt($breakpoint-chat-small, max-height) { + display: none; + } - .btn { - display: none; - padding: .5em 1em; - position: absolute; - right: 6px; - top: 1px; - } + .chatstatusicon { + cursor: pointer; + display: block; + font-size: 1.4em; + height: 36px; + left: 0; + position: absolute; + text-align: center; + top: 0; + width: 36px; + } - > div { - border-top: 1px solid $bordercolor; - } + .chatheadertitle { + display: inline; + padding-left: 28px; } - .input { - border-color: transparent; - border-radius: 0; - box-shadow: none; - display: block; - height: 54px; - margin: 0; - max-height: 54px; /* FF hack */ - resize: none; - width: 100%; + .ctrl { + color: $chat-ctrl; + position: absolute; + right: 1px; + top: 0; - @include breakpt($breakpoint-chat-small, max-height) { - max-height: 2.5em; + .#{$fa-css-prefix} { + cursor: pointer; + padding: 6px; } + } - &:active, - &:focus { - border-color: $chat-input-border-color; - } + span { + display: inline-block; + max-width: 60%; + overflow: hidden; + pointer-events: none; + text-overflow: ellipsis; + vertical-align: middle; + white-space: nowrap; } } @@ -595,16 +594,3 @@ 50% {background-color: $componentbg;} 100% {background-color: $actioncolor1;} } - -.chat.newmessage { - .chatheadertitle:after { - content: '***'; - position: absolute; - right: 32px; - top: 2px; - } - - .chatheader { - animation: newmessage 1s ease -.3s infinite; - } -} diff --git a/src/styles/components/_fileinfo.scss b/src/styles/components/_fileinfo.scss index c11a5a57..778ab375 100644 --- a/src/styles/components/_fileinfo.scss +++ b/src/styles/components/_fileinfo.scss @@ -27,9 +27,23 @@ padding: 1em; position: relative; text-align: center; -} -.file-info { + &.downloader { + .anim { + margin-left: -40px; + } + + .file-info-size { + margin-bottom: 10px; + } + } + + &.downloading { + .file-info-size { + border-color: $fileinfo-downloading-size-border; + } + } + > div { position: relative; z-index: 3; @@ -54,6 +68,37 @@ text-align: left; top: 14px; } + + .uploader { + // scss-lint:disable NestingDepth + .file-info-speed { + bottom: 6px; + } + + .actions { + margin-left: 30px; + opacity: 0; + } + + .anim { + margin-left: 0; + } + + .hovercontrol { + &:hover .anim { + margin-left: -50px; + } + + &:hover .actions { + margin-left: 0; + opacity: 1; + } + + > div { + transition: all .2s ease-in-out; + } + } + } } .is_remote .file-info { @@ -91,6 +136,7 @@ } > div { + //scss-lint:disable NestingDepth bottom: 0; box-shadow: none !important; left: 0; @@ -101,12 +147,13 @@ &.progress-bar { opacity: .5; - } - &.progress-bar.download { - opacity: 1; - z-index: 1; + &.download { + opacity: 1; + z-index: 1; + } } + } } @@ -118,49 +165,3 @@ right: 0; text-align: center; } - -.file-info.uploader { - .file-info-speed { - bottom: 6px; - } - - .actions { - margin-left: 30px; - opacity: 0; - } - - .anim { - margin-left: 0; - } - - .hovercontrol { - &:hover .anim { - margin-left: -50px; - } - - &:hover .actions { - margin-left: 0; - opacity: 1; - } - - > div { - transition: all .2s ease-in-out; - } - } -} - -.file-info.downloader { - .anim { - margin-left: -40px; - } - - .file-info-size { - margin-bottom: 10px; - } -} - -.file-info.downloading { - .file-info-size { - border-color: $fileinfo-downloading-size-border; - } -} diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index ffe8ad56..a0101fa5 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -19,16 +19,146 @@ * */ +.mainPresentation #presentation { + display: block; +} + .presentation { bottom: 0; left: 0; position: absolute; right: 0; top: 0; -} -.mainPresentation #presentation { - display: block; + .overlaybar { + bottom: 0; + left: 0; + right: 0; + text-align: center; + + .overlaybar-content { + // scss-lint:disable NestingDepth + max-width: 100%; + + .pagecontrol { + height: 30px; + } + } + + .btn-prev { + left: 40px; + } + + .btn-next { + left: auto; + right: 0; + } + + .overlaybar-button { + font-size: 20px; + line-height: 28px; + padding: 4px 6px; + position: absolute; + top: 0; + } + } + + .thumbnail { + color: #333; + display: inline-block; + height: 122px; + margin-left: 20px; + margin-top: 20px; + position: relative; + text-shadow: none; + vertical-align: middle; + width: 160px; + + &:first-child { + margin-left: 0; + } + + &.presentable { + cursor: pointer; + } + + &:hover .presentation-action { + display: block; + } + + &:hover .notavailable { + display: block; + } + + .caption { + // scss-lint:disable NestingDepth + overflow: hidden; + padding-bottom: 0; + text-overflow: ellipsis; + + .size { + font-size: 10px; + } + + .progress { + position: relative; + } + + .download-info { + bottom: 0; + color: $text-color; + left: 0; + line-height: 20px; + position: absolute; + right: 0; + text-shadow: 1px 1px 1px #fff; + top: 0; + } + } + + .active { + bottom: 0; + color: #84b819; + font-size: 10em; + left: 0; + opacity: .7; + position: absolute; + right: 0; + text-align: center; + top: 0; + } + + .notavailable { + bottom: 0; + color: #d2322d; + display: none; + font-size: 10em; + left: 0; + opacity: .25; + position: absolute; + right: 0; + text-align: center; + top: 0; + } + + .presentation-action { + display: none; + position: absolute; + top: 1px; + } + + .download { + left: 1px; + } + + .delete { + right: 1px; + } + + .filetype { + font-size: 5em; + } + } } .presentationpane { @@ -42,25 +172,27 @@ .welcome { padding: 0; + h1 { + white-space: normal; + } + .btn { margin-top: 30px; } - } - h1 { - white-space: normal; - } + .progress span { + text-shadow: none; + } - .download-info { - color: $text-color; - left: 0; - position: absolute; - text-shadow: 1px 1px 1px #fff; - width: 100%; + .progress .download-info { + color: $text-color; + left: 0; + position: absolute; + text-shadow: 1px 1px 1px #fff; + width: 100%; + } } -} -.presentationpane { .canvasContainer { height: 100%; width: 100%; @@ -89,150 +221,19 @@ display: none; margin: 0; padding: 0; - } - .odfcontainer.showonepage { - overflow: hidden; - text-align: center; + &.showonepage { + overflow: hidden; + text-align: center; + } } } -.presentation .overlaybar { - bottom: 0; - left: 0; - right: 0; - text-align: center; -} - -.presentation .overlaybar .overlaybar-content { - max-width: 100%; -} - -.presentation .overlaybar .overlaybar-button { - font-size: 20px; - line-height: 28px; - padding: 4px 6px; - position: absolute; - top: 0; -} - -.overlaybar-content .pagecontrol { - height: 30px; -} - -.presentation .overlaybar .btn-prev { - left: 40px; -} - -.presentation .overlaybar .btn-next { - left: auto; - right: 0; -} - .pageinfo input { display: inline; width: 70px; } -.presentation .thumbnail { - color: #333; - display: inline-block; - height: 122px; - margin-left: 20px; - margin-top: 20px; - position: relative; - text-shadow: none; - vertical-align: middle; - width: 160px; -} - -.presentation .thumbnail.presentable { - cursor: pointer; -} - -.presentation .thumbnail:first-child { - margin-left: 0; -} - -.presentation .thumbnail .caption { - overflow: hidden; - padding-bottom: 0; - text-overflow: ellipsis; -} - -.presentation .thumbnail .caption .size { - // scss-lint:disable SelectorDepth - font-size: 10px; -} - -.presentation .thumbnail .caption .progress { - // scss-lint:disable SelectorDepth - position: relative; -} - -.presentation .thumbnail .caption .download-info { - // scss-lint:disable SelectorDepth - bottom: 0; - color: $text-color; - left: 0; - line-height: 20px; - position: absolute; - right: 0; - text-shadow: 1px 1px 1px #fff; - top: 0; -} - -.presentation .thumbnail .active { - bottom: 0; - color: #84b819; - font-size: 10em; - left: 0; - opacity: .7; - position: absolute; - right: 0; - text-align: center; - top: 0; -} - -.presentation .thumbnail .notavailable { - bottom: 0; - color: #d2322d; - display: none; - font-size: 10em; - left: 0; - opacity: .25; - position: absolute; - right: 0; - text-align: center; - top: 0; -} - -.presentation .thumbnail:hover .notavailable { - display: block; -} - -.presentation .thumbnail .presentation-action { - display: none; - position: absolute; - top: 1px; -} - -.presentation .thumbnail .download { - left: 1px; -} - -.presentation .thumbnail .delete { - right: 1px; -} - -.presentation .thumbnail:hover .presentation-action { - display: block; -} - -.presentation .thumbnail .filetype { - font-size: 5em; -} - .presentations { height: 156px; margin-left: -25px; diff --git a/src/styles/components/_rightslide.scss b/src/styles/components/_rightslide.scss index 28b24f69..a7c2b9c3 100644 --- a/src/styles/components/_rightslide.scss +++ b/src/styles/components/_rightslide.scss @@ -28,14 +28,14 @@ top: $minbarheight; transition: right 200ms ease-in-out; z-index: 5; + + .rightslidepane { + height: 100%; + position: relative; + width: 100%; + } } .withBuddylist #rightslide { right: 0; } - -#rightslide .rightslidepane { - height: 100%; - position: relative; - width: 100%; -} diff --git a/src/styles/components/_roombar.scss b/src/styles/components/_roombar.scss index 3c2ec41b..b182d44c 100644 --- a/src/styles/components/_roombar.scss +++ b/src/styles/components/_roombar.scss @@ -26,12 +26,11 @@ right: 0; top: $minbarheight; z-index: 4; -} -#roombar .roombar { - left: 0; - position: absolute; - right: 0; - top: 0; + .roombar { + left: 0; + position: absolute; + right: 0; + top: 0; + } } - diff --git a/src/styles/components/_screenshare.scss b/src/styles/components/_screenshare.scss index ad19392f..838bae41 100644 --- a/src/styles/components/_screenshare.scss +++ b/src/styles/components/_screenshare.scss @@ -19,16 +19,22 @@ * */ +.mainScreenshare #screenshare { + display: block; +} + .screenshare { bottom: 0; left: 0; position: absolute; right: 0; top: 0; -} -.mainScreenshare #screenshare { - display: block; + .overlaybar { + bottom: 0; + left: 0; + right: 0; + } } .screensharepane { @@ -39,9 +45,6 @@ position: absolute; right: 0; top: 0; -} - -.screensharepane { .remotescreen { position: relative; } @@ -56,9 +59,3 @@ max-height: none; width: auto; } - -.screenshare .overlaybar { - bottom: 0; - left: 0; - right: 0; -} diff --git a/src/styles/components/_settings.scss b/src/styles/components/_settings.scss index ae6f3ed3..3b874c8a 100644 --- a/src/styles/components/_settings.scss +++ b/src/styles/components/_settings.scss @@ -20,6 +20,7 @@ */ #settings { + // scss-lint:disable NestingDepth background: $settings-background; border-left: 1px solid $bordercolor; bottom: 0; @@ -30,27 +31,27 @@ transition: right 200ms ease-in-out; width: 520px; z-index: 50; -} -#settings.show { - right: 0; - - @include breakpt($breakpoint-settings-medium, max-width, only screen) { - background: $settings-background; - left: 0; - width: auto; - } - - .form-actions { + &.show { + right: 0; @include breakpt($breakpoint-settings-medium, max-width, only screen) { - bottom: 0; - height: 60px; + background: $settings-background; left: 0; - margin-bottom: 0; - padding: 6px 0 6px 120px; - position: fixed; - right: 0; + width: auto; + } + + .form-actions { + + @include breakpt($breakpoint-settings-medium, max-width, only screen) { + bottom: 0; + height: 60px; + left: 0; + margin-bottom: 0; + padding: 6px 0 6px 120px; + position: fixed; + right: 0; + } } } } @@ -65,9 +66,7 @@ position: absolute; right: 0; top: 0; -} -.settings { @include breakpt($breakpoint-settings-medium, max-width, only screen) { padding-bottom: 10px; } diff --git a/src/styles/components/_usability.scss b/src/styles/components/_usability.scss index 62c72463..20c87055 100644 --- a/src/styles/components/_usability.scss +++ b/src/styles/components/_usability.scss @@ -19,6 +19,16 @@ * */ +.withChat #help, +.withBuddylist #help { + right: 260px; +} + +.withChat.withBuddylist #help, +.withSettings #help { + right: 520px; +} + #help { bottom: 10px; color: #aaa; @@ -32,19 +42,7 @@ transition: right 200ms ease-in-out; user-select: none; width: 350px; -} -.withChat #help, -.withBuddylist #help { - right: 260px; -} - -.withChat.withBuddylist #help, -.withSettings #help { - right: 520px; -} - -#help { @include breakpt($breakpoint-useability-small, max-width, only screen) { display: none; } diff --git a/src/styles/components/_youtubevideo.scss b/src/styles/components/_youtubevideo.scss index 452cf135..0221154e 100644 --- a/src/styles/components/_youtubevideo.scss +++ b/src/styles/components/_youtubevideo.scss @@ -19,12 +19,66 @@ * */ +.mainYoutubevideo #youtubevideo { + display: block; +} + .youtubevideo { bottom: 0; left: 0; position: absolute; right: 0; top: 0; + + .click-container { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 5; + } + + .welcome { + max-width: 700px; + + h1 { + margin-top: 10px; + } + + .welcome-container { + max-width: 700px; + } + + .welcome-logo { + background: transparent; + font-size: 10em; + } + } + + .overlaybar { + bottom: 0; + left: 0; + right: 0; + } + + .overlaybar-content { + max-width: 100%; + width: 100%; + + form .overlaybar-buttons { + position: absolute; + right: 23px; + top: 6px; + } + } + + .overlaybar-input { + padding-right: 15px; + position: relative; + width: 100%; + } + } .youtubevideopane { @@ -55,67 +109,14 @@ &:hover { opacity: .8; } -} - -#youtubeplayerinfo div { - background-color: #f9f2f4; - border-radius: 10px; - display: inline-block; - font-size: 2em; - padding: 20px 40px; -} - -.youtubevideo .click-container { - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 5; -} - -.youtubevideo .welcome { - max-width: 700px; -} -.youtubevideo .welcome h1 { - margin-top: 10px; -} - -.youtubevideo .welcome .welcome-container { - max-width: 700px; -} - -.youtubevideo .welcome .welcome-logo { - background: transparent; - font-size: 10em; -} - -.mainYoutubevideo #youtubevideo { - display: block; -} - -.youtubevideo .overlaybar { - bottom: 0; - left: 0; - right: 0; -} - -.youtubevideo .overlaybar-content { - max-width: 100%; - width: 100%; -} - -.youtubevideo .overlaybar-input { - padding-right: 15px; - position: relative; - width: 100%; -} - -.youtubevideo .overlaybar-content .overlaybar-buttons { - position: absolute; - right: 23px; - top: 6px; + div { + background-color: #f9f2f4; + border-radius: 10px; + display: inline-block; + font-size: 2em; + padding: 20px 40px; + } } .volumecontrol { @@ -143,37 +144,37 @@ display: inline-block; padding: 6px 8px; vertical-align: middle; -} - -.volumebar .bar { - -webkit-appearance: none; - background-color: #aaa; - border: 1px solid #aaa; - height: 3px; - outline: 0; - width: 100px; -} - -.volumebar .bar::-webkit-slider-thumb { - -webkit-appearance: none; - background-color: #fff; - height: 20px; - width: 6px; -} - -.volumebar .bar::-moz-range-track { - background: #aaa; - border: 0; -} - -.volumebar .bar::-moz-range-thumb { - background-color: #fff; - border-radius: 0; - height: 20px; - width: 6px; -} -.volumebar .bar::-moz-focusring { - outline: 1px solid #aaa; - outline-offset: -1px; + .bar { + -webkit-appearance: none; + background-color: #aaa; + border: 1px solid #aaa; + height: 3px; + outline: 0; + width: 100px; + + &::-webkit-slider-thumb { + -webkit-appearance: none; + background-color: #fff; + height: 20px; + width: 6px; + } + + &::-moz-range-track { + background: #aaa; + border: 0; + } + + &::-moz-range-thumb { + background-color: #fff; + border-radius: 0; + height: 20px; + width: 6px; + } + + &::-moz-focusring { + outline: 1px solid #aaa; + outline-offset: -1px; + } + } } diff --git a/src/styles/global/_overlaybar.scss b/src/styles/global/_overlaybar.scss index 12d0a03d..3ba9d41d 100644 --- a/src/styles/global/_overlaybar.scss +++ b/src/styles/global/_overlaybar.scss @@ -20,6 +20,7 @@ */ .overlaybar { + // scss-lint:disable QualifyingElement background: $overlaybar-background; border-bottom: 1px solid #222; border-top: 1px solid #222; @@ -30,14 +31,30 @@ text-shadow: 0 0 5px #000; user-select: none; vertical-align: middle; -} -.overlaybar { - // scss-lint:disable QualifyingElement &:hover { background: $componentfg2; } + &.notvisible { + background: transparent; + border-bottom: 1px solid transparent; + border-top: 1px solid transparent; + pointer-events: none; + + &:hover { + background: transparent; + } + + .overlaybar-content { + display: none; + } + + .overlaybar-overlay { + display: block; + } + } + .btn { text-shadow: none; } @@ -59,27 +76,6 @@ label { padding-top: 6px !important; } -} - -.overlaybar { - &.notvisible { - background: transparent; - border-bottom: 1px solid transparent; - border-top: 1px solid transparent; - pointer-events: none; - - &:hover { - background: transparent; - } - - .overlaybar-content { - display: none; - } - - .overlaybar-overlay { - display: block; - } - } .overlaybar-button { color: $overlaybar-btn; From 971452716197f9c726d7fc2f206fba9cb1de5de9 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 7 Apr 2015 13:08:58 +0200 Subject: [PATCH 015/121] Rebuilt styles. --- static/css/main.min.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/main.min.css b/static/css/main.min.css index e15483a9..578b89a5 100644 --- a/static/css/main.min.css +++ b/static/css/main.min.css @@ -17,4 +17,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}.withBuddylist #rightslide{right:0}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.logo .desc{display:none}}.logo .desc{font-style:italic;left:38px;position:relative;top:26px}.logo .desc a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.btn-mutemicrophone i:before{content:'\f130'}.btn-mutemicrophone.active i:before{content:'\f131'}.btn-mutecamera i:before{content:'\f06e'}.btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddysessions li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddysessions li:hover .btn-group{visibility:visible}.buddysessions .btn-group{visibility:hidden}.buddysessions .currentsession .buddy3{font-weight:bold}.buddy.hovered .buddysessions{max-height:999px}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.active.visible{display:block}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .message.with_hoverimage .buddyPicture{overflow:visible;z-index:initial}.chat .message.with_hoverimage .buddyPicture:hover .buddyInfoActions{height:40px;opacity:1}.chat .message.with_hoverimage .buddyInfoActions{cursor:default;display:inline-block;height:0;left:0;opacity:0;overflow:hidden;position:absolute;top:48px;-webkit-transition:opacity 0.1s .1s linear, height .4s .1s ease-out;transition:opacity 0.1s .1s linear, height .4s .1s ease-out;white-space:nowrap;z-index:1}.chat .message.with_hoverimage .buddyInfoActions .btn-group{display:block;margin:0 auto;width:55px}.chat .message.with_hoverimage .buddyInfoActions .btn-primary{padding:2px 5px}.chat .message.with_hoverimage .buddyInfoActions .fa{color:#fff;line-height:24px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}@media only screen and (max-width: 400px){#help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){#help{font-size:1em;width:250px}}#help>div{margin:0 10px}#help .help-subline{color:#888;padding:20px 0}#help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;color:#eee;font-size:20em;left:41px;overflow:hidden;position:absolute;right:0;top:-82px;z-index:2}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}.file-info.uploader .file-info-speed{bottom:6px}.file-info.uploader .actions{margin-left:30px;opacity:0}.file-info.uploader .anim{margin-left:0}.file-info.uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info.uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info.uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.mainScreenshare #screenshare{display:block}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}.screenshare .overlaybar{bottom:0;left:0;right:0}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager tr:first-child td{border-top:0}.contactsmanager .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.mainPresentation #presentation{display:block}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome .btn{margin-top:30px}.presentationpane h1{white-space:normal}.presentationpane .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.pageinfo input{display:inline;width:70px}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail .filetype{font-size:5em}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideo .overlaybar-content .overlaybar-buttons{position:absolute;right:23px;top:6px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} + *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.withBuddylist #rightslide{right:0}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.logo .desc{display:none}}.logo .desc{font-style:italic;left:38px;position:relative;top:26px}.logo .desc a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.btn-mutemicrophone i:before{content:'\f130'}.btn-mutemicrophone.active i:before{content:'\f131'}.btn-mutecamera i:before{content:'\f06e'}.btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy.hovered .buddysessions{max-height:999px}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddy .buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddy .buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddy .buddysessions ul li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddy .buddysessions ul li .btn-group{visibility:hidden}.buddy .buddysessions ul li:hover .btn-group{visibility:visible}.buddy .buddysessions .currentsession .buddy3{font-weight:bold}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chat.active.visible{display:block}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message.with_hoverimage .buddyPicture{overflow:visible;z-index:initial}.chat .message.with_hoverimage .buddyPicture:hover .buddyInfoActions{height:40px;opacity:1}.chat .message.with_hoverimage .buddyInfoActions{cursor:default;display:inline-block;height:0;left:0;opacity:0;overflow:hidden;position:absolute;top:48px;-webkit-transition:opacity 0.1s .1s linear, height .4s .1s ease-out;transition:opacity 0.1s .1s linear, height .4s .1s ease-out;white-space:nowrap;z-index:1}.chat .message.with_hoverimage .buddyInfoActions .btn-group{display:block;margin:0 auto;width:55px}.chat .message.with_hoverimage .buddyInfoActions .btn-primary{padding:2px 5px}.chat .message.with_hoverimage .buddyInfoActions .fa{color:#fff;line-height:24px}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}@media only screen and (max-width: 400px){#help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){#help{font-size:1em;width:250px}}#help>div{margin:0 10px}#help .help-subline{color:#888;padding:20px 0}#help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;color:#eee;font-size:20em;left:41px;overflow:hidden;position:absolute;right:0;top:-82px;z-index:2}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.file-info .uploader .file-info-speed{bottom:6px}.file-info .uploader .actions{margin-left:30px;opacity:0}.file-info .uploader .anim{margin-left:0}.file-info .uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info .uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info .uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.mainScreenshare #screenshare{display:block}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.screenshare .overlaybar{bottom:0;left:0;right:0}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager tr:first-child td{border-top:0}.contactsmanager .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.mainPresentation #presentation{display:block}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail .filetype{font-size:5em}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome h1{white-space:normal}.presentationpane .welcome .btn{margin-top:30px}.presentationpane .welcome .progress span{text-shadow:none}.presentationpane .welcome .progress .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.pageinfo input{display:inline;width:70px}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-content form .overlaybar-buttons{position:absolute;right:23px;top:6px}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} From 56aa603293f70f99c832feeef47c254ea7edde04 Mon Sep 17 00:00:00 2001 From: Lance Cooper Date: Tue, 7 Apr 2015 21:38:18 -0500 Subject: [PATCH 016/121] Add guards for NPE's when processing channelling API messages. This also refactors the channelling API for better clarity as well as introducing the following functional changes: * All Hello requests will now receive a Welcome or Error return. * The message sent in response to a successful authentication request now uses the Iid provided with the originating request. * Responses to requests for the Self document now use the Iid provided with the originating request. * Failed authentication requests now receive an error return. * Malformed requests for the Hello, Authentication, Sessions, and Rooms documents will now receive an error return. * Requests for the Sessions document which cannot be processed now receive an error return. * Requests for the Users document will receive an error return if the requesting session has not joined a room. --- doc/CHANNELING-API.txt | 37 ++- .../spreed-webrtc-server/channelling_api.go | 313 +++++++++++------- .../channelling_api_test.go | 81 ++--- src/app/spreed-webrtc-server/client.go | 31 +- src/app/spreed-webrtc-server/session.go | 16 +- 5 files changed, 280 insertions(+), 198 deletions(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index 4427ec7a..0d328ad9 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -98,6 +98,13 @@ Error returns "Message": "A description of the error condition" } + The following predefined error codes may implicitly be returned by any call + which returns an error document: + + unknown: An internal server error, the message may provide more information. + bad_request: The structure or content of the client's request was invalid, + the message may contain specifics. + Special purpose documents for channling Self @@ -427,9 +434,10 @@ Additional types for session listing and notifications Rev is the status update sequence for this status update entry. It is a positive integer. Higher numbers are later status updates. - When the current session is in a room (means sent Hello), a Users request - can be sent, to receive a list of sessions in that particular room. This - always returns the sessions in the same room as the calling session. + When the current session has successfully joined a room (see Hello for more + details), a Users request will return a Users document containing session + details for the current room. An Error document will be returned if no room + has been joined or session information cannot be retrieved. Users (Request uses empty data) @@ -470,6 +478,10 @@ Additional types for session listing and notifications Note: The Userid field is only present, if that session belongs to a known user. + Error codes: + + not_in_room: Clients must join a room before requesting users. + Alive { @@ -506,12 +518,19 @@ User authorization and session authentication The Authentication document binds a userid to the current session. The Nonce and Userid need to be validateable by the server. If Authentication - was successfull, a new Self document will be sent. The Nonce value can - be generated by using the REST API (sessions end point). + was successful, a new Self document will be sent. Otherwise an Error + document will be returned describing why authentication failed. Note that + the Nonce value can be generated by using the REST API (sessions end point). There is no way to undo authentication for a session. For log out, close the session (disconnect) and forget the token. + Error codes: + + already_authenticated: This session has already authenticated, follow + the reauthentication procedure above. + invalid_session_token: The provided session token information is invalid, + the error message may contain more information. Information retrieval @@ -532,6 +551,9 @@ Information retrieval Token data retrieved on incoming messages as A field (attestation token). + If session information retrieval fails, an Error document with one of the + listed codes will be returned. + Sessions (Response with Id, Token and Type from request and populated Session list). @@ -558,6 +580,11 @@ Information retrieval ] } + Error codes: + + contacts_not_enabled: Requests with subtype `contact` are not enabled. + bad_attestation: The requested session attestation is invalid. + no_such_session: The requested session could not be found. Chat messages and status information diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index 8c42dab1..200b1daa 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -31,9 +31,9 @@ const ( ) type ChannellingAPI interface { - OnConnect(Client, *Session) + OnConnect(Client, *Session) (interface{}, error) OnDisconnect(Client, *Session) - OnIncoming(ResponseSender, *Session, *DataIncoming) + OnIncoming(Sender, *Session, *DataIncoming) (interface{}, error) } type channellingAPI struct { @@ -60,169 +60,113 @@ func NewChannellingAPI(config *Config, roomStatus RoomStatusManager, sessionEnco } } -func (api *channellingAPI) OnConnect(client Client, session *Session) { +func (api *channellingAPI) OnConnect(client Client, session *Session) (interface{}, error) { api.Unicaster.OnConnect(client, session) - api.SendSelf(client, session) + return api.MakeSelf(session) } func (api *channellingAPI) OnDisconnect(client Client, session *Session) { api.Unicaster.OnDisconnect(client, session) } -func (api *channellingAPI) OnIncoming(c ResponseSender, session *Session, msg *DataIncoming) { +func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *DataIncoming) (interface{}, error) { switch msg.Type { case "Self": - api.SendSelf(c, session) + return api.MakeSelf(session) case "Hello": - //log.Println("Hello", msg.Hello, c.Index()) - // TODO(longsleep): Filter room id and user agent. - session.Update(&SessionUpdate{Types: []string{"Ua"}, Ua: msg.Hello.Ua}) - - room, err := session.JoinRoom(msg.Hello.Id, msg.Hello.Credentials, c) - // NOTE(lcooper): Iid filtered for compatibility's sake. - // Evaluate sending unconditionally when supported by all clients. - if msg.Iid != "" { - if err == nil { - c.Reply(msg.Iid, &DataWelcome{ - Type: "Welcome", - Room: room, - Users: api.RoomUsers(session), - }) - } else { - c.Reply(msg.Iid, err) - } + if msg.Hello == nil { + return nil, NewDataError("bad_request", "message did not contain Hello") } + + return api.HandleHello(session, msg.Hello, sender) case "Offer": + if msg.Offer == nil { + log.Println("Received invalid offer message.", msg) + break + } + // TODO(longsleep): Validate offer session.Unicast(msg.Offer.To, msg.Offer) case "Candidate": + if msg.Candidate == nil { + log.Println("Received invalid candidate message.", msg) + break + } + // TODO(longsleep): Validate candidate session.Unicast(msg.Candidate.To, msg.Candidate) case "Answer": + if msg.Answer == nil { + log.Println("Received invalid answer message.", msg) + break + } + // TODO(longsleep): Validate Answer session.Unicast(msg.Answer.To, msg.Answer) case "Users": - if session.Hello { - sessions := &DataSessions{Type: "Users", Users: api.RoomUsers(session)} - c.Reply(msg.Iid, sessions) - } + return api.HandleUsers(session) case "Authentication": - st := msg.Authentication.Authentication - if st == nil { - return + if msg.Authentication == nil || msg.Authentication.Authentication == nil { + return nil, NewDataError("bad_request", "message did not contain Authentication") } - if err := api.Authenticate(session, st, ""); err == nil { - log.Println("Authentication success", session.Userid()) - api.SendSelf(c, session) - session.BroadcastStatus() - } else { - log.Println("Authentication failed", err, st.Userid, st.Nonce) - } + return api.HandleAuthentication(session, msg.Authentication.Authentication) case "Bye": + if msg.Bye == nil { + log.Println("Received invalid bye message.", msg) + break + } + session.Unicast(msg.Bye.To, msg.Bye) case "Status": + if msg.Status == nil { + log.Println("Received invalid status message.", msg) + break + } + //log.Println("Status", msg.Status) session.Update(&SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status}) session.BroadcastStatus() case "Chat": - // TODO(longsleep): Limit sent chat messages per incoming connection. - if !msg.Chat.Chat.NoEcho { - session.Unicast(session.Id, msg.Chat) - } - msg.Chat.Chat.Time = time.Now().Format(time.RFC3339) - if msg.Chat.To == "" { - // TODO(longsleep): Check if chat broadcast is allowed. - if session.Hello { - api.CountBroadcastChat() - session.Broadcast(msg.Chat) - } - } else { - if msg.Chat.Chat.Status != nil && msg.Chat.Chat.Status.ContactRequest != nil { - if !api.Config.WithModule("contacts") { - return - } - if err := api.contactrequestHandler(session, msg.Chat.To, msg.Chat.Chat.Status.ContactRequest); err != nil { - log.Println("Ignoring invalid contact request.", err) - return - } - msg.Chat.Chat.Status.ContactRequest.Userid = session.Userid() - } - if msg.Chat.Chat.Status == nil { - api.CountUnicastChat() - } - - session.Unicast(msg.Chat.To, msg.Chat) - if msg.Chat.Chat.Mid != "" { - // Send out delivery confirmation status chat message. - session.Unicast(session.Id, &DataChat{To: msg.Chat.To, Type: "Chat", Chat: &DataChatMessage{Mid: msg.Chat.Chat.Mid, Status: &DataChatStatus{State: "sent"}}}) - } + if msg.Chat == nil || msg.Chat.Chat == nil { + log.Println("Received invalid chat message.", msg) + break } + + api.HandleChat(session, msg.Chat.To, msg.Chat.Chat) case "Conference": - // Check conference maximum size. - if len(msg.Conference.Conference) > maxConferenceSize { - log.Println("Refusing to create conference above limit.", len(msg.Conference.Conference)) - } else { - // Send conference update to anyone. - for _, id := range msg.Conference.Conference { - if id != session.Id { - session.Unicast(id, msg.Conference) - } - } + if msg.Conference == nil { + log.Println("Received invalid conference message.", msg) + break } + + api.HandleConference(session, msg.Conference) case "Alive": - c.Reply(msg.Iid, msg.Alive) + return msg.Alive, nil case "Sessions": - var users []*DataSession - switch msg.Sessions.Sessions.Type { - case "contact": - if api.Config.WithModule("contacts") { - if userID, err := api.getContactID(session, msg.Sessions.Sessions.Token); err == nil { - users = api.GetUserSessions(session, userID) - } else { - log.Printf(err.Error()) - } - } else { - log.Printf("Incoming contacts session request with contacts disabled") - } - case "session": - id, err := session.attestation.Decode(msg.Sessions.Sessions.Token) - if err != nil { - log.Printf("Failed to decode incoming attestation", err, msg.Sessions.Sessions.Token) - break - } - session, ok := api.GetSession(id) - if !ok { - log.Printf("Cannot retrieve session for id %s", id) - break - } - users = make([]*DataSession, 1, 1) - users[0] = session.Data() - default: - log.Printf("Unkown incoming sessions request type %s", msg.Sessions.Sessions.Type) + if msg.Sessions == nil || msg.Sessions.Sessions == nil { + return nil, NewDataError("bad_request", "message did not contain Sessions") } - // TODO(lcooper): We ought to reply with a *DataError here if failed. - if users != nil { - c.Reply(msg.Iid, &DataSessions{Type: "Sessions", Users: users, Sessions: msg.Sessions.Sessions}) - } + return api.HandleSessions(session, msg.Sessions.Sessions) case "Room": - if room, err := api.UpdateRoom(session, msg.Room); err == nil { - session.Broadcast(room) - c.Reply(msg.Iid, room) - } else { - c.Reply(msg.Iid, err) + if msg.Room == nil { + return nil, NewDataError("bad_request", "message did not contain Room") } + + return api.HandleRoom(session, msg.Room) default: log.Println("OnText unhandled message type", msg.Type) } + + return nil, nil } -func (api *channellingAPI) SendSelf(c Responder, session *Session) { +func (api *channellingAPI) MakeSelf(session *Session) (*DataSelf, error) { token, err := api.EncodeSessionToken(session) if err != nil { log.Println("Error in OnRegister", err) - return + return nil, err } log.Println("Created new session token", len(token), token) @@ -237,5 +181,138 @@ func (api *channellingAPI) SendSelf(c Responder, session *Session) { Turn: api.CreateTurnData(session), Stun: api.StunURIs, } - c.Reply("", self) + + return self, nil +} + +func (api *channellingAPI) HandleHello(session *Session, hello *DataHello, sender Sender) (*DataWelcome, error) { + // TODO(longsleep): Filter room id and user agent. + session.Update(&SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua}) + + room, err := session.JoinRoom(hello.Id, hello.Credentials, sender) + if err != nil { + return nil, err + } + return &DataWelcome{ + Type: "Welcome", + Room: room, + Users: api.RoomUsers(session), + }, nil +} + +func (api *channellingAPI) HandleUsers(session *Session) (sessions *DataSessions, err error) { + if session.Hello { + sessions = &DataSessions{Type: "Users", Users: api.RoomUsers(session)} + } else { + err = NewDataError("not_in_room", "Cannot list users without a current room") + } + return +} + +func (api *channellingAPI) HandleAuthentication(session *Session, st *SessionToken) (*DataSelf, error) { + if err := api.Authenticate(session, st, ""); err != nil { + log.Println("Authentication failed", err, st.Userid, st.Nonce) + return nil, err + } + + log.Println("Authentication success", session.Userid()) + self, err := api.MakeSelf(session) + if err == nil { + session.BroadcastStatus() + } + + return self, err +} + +func (api *channellingAPI) HandleChat(session *Session, to string, chat *DataChatMessage) { + // TODO(longsleep): Limit sent chat messages per incoming connection. + if !chat.NoEcho { + session.Unicast(session.Id, chat) + } + chat.Time = time.Now().Format(time.RFC3339) + if to == "" { + // TODO(longsleep): Check if chat broadcast is allowed. + if session.Hello { + api.CountBroadcastChat() + session.Broadcast(chat) + } + } else { + if chat.Status != nil { + if chat.Status.ContactRequest != nil { + if !api.Config.WithModule("contacts") { + return + } + if err := api.contactrequestHandler(session, to, chat.Status.ContactRequest); err != nil { + log.Println("Ignoring invalid contact request.", err) + return + } + chat.Status.ContactRequest.Userid = session.Userid() + } + } else { + api.CountUnicastChat() + } + + session.Unicast(to, chat) + if chat.Mid != "" { + // Send out delivery confirmation status chat message. + session.Unicast(session.Id, &DataChat{To: to, Type: "Chat", Chat: &DataChatMessage{Mid: chat.Mid, Status: &DataChatStatus{State: "sent"}}}) + } + } +} + +func (api *channellingAPI) HandleConference(session *Session, conference *DataConference) { + // Check conference maximum size. + if len(conference.Conference) > maxConferenceSize { + log.Println("Refusing to create conference above limit.", len(conference.Conference)) + return + } + + // Send conference update to anyone. + for _, id := range conference.Conference { + if id != session.Id { + session.Unicast(id, conference) + } + } +} + +func (api *channellingAPI) HandleSessions(session *Session, sessions *DataSessionsRequest) (*DataSessions, error) { + switch sessions.Type { + case "contact": + if !api.Config.WithModule("contacts") { + return nil, NewDataError("contacts_not_enabled", "incoming contacts session request with contacts disabled") + } + userID, err := api.getContactID(session, sessions.Token) + if err != nil { + return nil, err + } + return &DataSessions{ + Type: "Sessions", + Users: api.GetUserSessions(session, userID), + Sessions: sessions, + }, nil + case "session": + id, err := session.attestation.Decode(sessions.Token) + if err != nil { + return nil, NewDataError("bad_attestation", err.Error()) + } + session, ok := api.GetSession(id) + if !ok { + return nil, NewDataError("no_such_session", "cannot retrieve session") + } + return &DataSessions{ + Type: "Sessions", + Users: []*DataSession{session.Data()}, + Sessions: sessions, + }, nil + default: + return nil, NewDataError("bad_request", "unknown sessions request type") + } +} + +func (api *channellingAPI) HandleRoom(session *Session, room *DataRoom) (*DataRoom, error) { + room, err := api.UpdateRoom(session, room) + if err == nil { + session.Broadcast(room) + } + return room, err } diff --git a/src/app/spreed-webrtc-server/channelling_api_test.go b/src/app/spreed-webrtc-server/channelling_api_test.go index ebf004fd..df91e779 100644 --- a/src/app/spreed-webrtc-server/channelling_api_test.go +++ b/src/app/spreed-webrtc-server/channelling_api_test.go @@ -27,20 +27,11 @@ import ( ) type fakeClient struct { - replies map[string]interface{} } func (fake *fakeClient) Send(_ Buffer) { } -func (fake *fakeClient) Reply(iid string, msg interface{}) { - if fake.replies == nil { - fake.replies = make(map[string]interface{}) - } - - fake.replies[iid] = msg -} - type fakeRoomManager struct { joinedRoomID string leftRoomID string @@ -74,29 +65,6 @@ func (fake *fakeRoomManager) UpdateRoom(_ *Session, _ *DataRoom) (*DataRoom, err return fake.updatedRoom, fake.updateError } -func assertReply(t *testing.T, client *fakeClient, iid string) interface{} { - msg, ok := client.replies[iid] - if !ok { - t.Fatalf("No response received for Iid %v", iid) - } - return msg -} - -func assertErrorReply(t *testing.T, client *fakeClient, iid, code string) { - err, ok := assertReply(t, client, iid).(*DataError) - if !ok { - t.Fatalf("Expected response message to be an Error") - } - - if err.Type != "Error" { - t.Error("Message did not have the correct type") - } - - if err.Code != code { - t.Errorf("Expected error code to be %v, but was %v", code, err.Code) - } -} - func NewTestChannellingAPI() (ChannellingAPI, *fakeClient, *Session, *fakeRoomManager) { client, roomManager := &fakeClient{}, &fakeRoomManager{} session := &Session{ @@ -168,21 +136,19 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_DoesNotJoinIfNotPermitted(t *te } } -func Test_ChannellingAPI_OnIncoming_HelloMessageWithAnIid_RespondsWithAWelcome(t *testing.T) { - iid, roomID := "foo", "a-room" +func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAWelcome(t *testing.T) { + roomID := "a-room" api, client, session, roomManager := NewTestChannellingAPI() roomManager.roomUsers = []*DataSession{&DataSession{}} - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Iid: iid, Hello: &DataHello{Id: roomID}}) - - msg, ok := client.replies[iid] - if !ok { - t.Fatalf("No response received for Iid %v", iid) + reply, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomID}}) + if err != nil { + t.Fatalf("Unexpected error %v", err) } - welcome, ok := msg.(*DataWelcome) + welcome, ok := reply.(*DataWelcome) if !ok { - t.Fatalf("Expected response message %#v to be a Welcome", msg) + t.Fatalf("Expected response %#v to be a Welcome", reply) } if welcome.Type != "Welcome" { @@ -198,25 +164,31 @@ func Test_ChannellingAPI_OnIncoming_HelloMessageWithAnIid_RespondsWithAWelcome(t } } -func Test_ChannellingAPI_OnIncoming_HelloMessageWithAnIid_RespondsWithAnErrorIfTheRoomCannotBeJoined(t *testing.T) { - iid := "foo" +func Test_ChannellingAPI_OnIncoming_HelloMessage_RespondsWithAnErrorIfTheRoomCannotBeJoined(t *testing.T) { api, client, session, roomManager := NewTestChannellingAPI() roomManager.joinError = NewDataError("bad_join", "") - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Iid: iid, Hello: &DataHello{}}) + _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{}}) - assertErrorReply(t, client, iid, "bad_join") + assertDataError(t, err, "bad_join") } func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAndBroadcastsTheUpdatedRoom(t *testing.T) { - iid, roomName := "123", "foo" + roomName := "foo" api, client, session, roomManager := NewTestChannellingAPI() roomManager.updatedRoom = &DataRoom{Name: "FOO"} - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Iid: "0", Hello: &DataHello{Id: roomName}}) - api.OnIncoming(client, session, &DataIncoming{Type: "Room", Iid: iid, Room: &DataRoom{Name: roomName}}) + _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}}) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } - room, ok := assertReply(t, client, iid).(*DataRoom) + reply, err := api.OnIncoming(client, session, &DataIncoming{Type: "Room", Room: &DataRoom{Name: roomName}}) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + + room, ok := reply.(*DataRoom) if !ok { t.Fatalf("Expected response message to be a Room") } @@ -235,12 +207,15 @@ func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAndBroadcastsTheUpda } func Test_ChannellingAPI_OnIncoming_RoomMessage_RespondsWithAnErrorIfUpdatingTheRoomFails(t *testing.T) { - iid, roomName := "123", "foo" + roomName := "foo" api, client, session, roomManager := NewTestChannellingAPI() roomManager.updateError = NewDataError("a_room_error", "") - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Iid: "0", Hello: &DataHello{Id: roomName}}) - api.OnIncoming(client, session, &DataIncoming{Type: "Room", Iid: iid, Room: &DataRoom{Name: roomName}}) + _, err := api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}}) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + _, err = api.OnIncoming(client, session, &DataIncoming{Type: "Room", Room: &DataRoom{Name: roomName}}) - assertErrorReply(t, client, iid, "a_room_error") + assertDataError(t, err, "a_room_error") } diff --git a/src/app/spreed-webrtc-server/client.go b/src/app/spreed-webrtc-server/client.go index b858176b..85c0f062 100644 --- a/src/app/spreed-webrtc-server/client.go +++ b/src/app/spreed-webrtc-server/client.go @@ -29,17 +29,8 @@ type Sender interface { Send(Buffer) } -type ResponseSender interface { - Sender - Responder -} - -type Responder interface { - Reply(iid string, m interface{}) -} - type Client interface { - ResponseSender + Sender Session() *Session Index() uint64 Close() @@ -59,7 +50,11 @@ func NewClient(codec Codec, api ChannellingAPI, session *Session) *client { func (client *client) OnConnect(conn Connection) { client.Connection = conn - client.ChannellingAPI.OnConnect(client, client.session) + if reply, err := client.ChannellingAPI.OnConnect(client, client.session); err == nil { + client.reply("", reply) + } else { + log.Println("OnConnect error", err) + } } func (client *client) OnDisconnect() { @@ -68,14 +63,20 @@ func (client *client) OnDisconnect() { } func (client *client) OnText(b Buffer) { - if incoming, err := client.DecodeIncoming(b); err == nil { - client.OnIncoming(client, client.session, incoming) - } else { + incoming, err := client.DecodeIncoming(b) + if err != nil { log.Println("OnText error while processing incoming message", err) + return + } + + if reply, err := client.OnIncoming(client, client.session, incoming); err != nil { + client.reply(incoming.Iid, err) + } else if reply != nil { + client.reply(incoming.Iid, reply) } } -func (client *client) Reply(iid string, m interface{}) { +func (client *client) reply(iid string, m interface{}) { outgoing := &DataOutgoing{From: client.session.Id, Iid: iid, Data: m} if b, err := client.EncodeOutgoing(outgoing); err == nil { client.Send(b) diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index c226e6c0..aa07e332 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -22,7 +22,6 @@ package main import ( - "errors" "fmt" "github.com/gorilla/securecookie" "strings" @@ -310,15 +309,18 @@ func (s *Session) Authorize(realm string, st *SessionToken) (string, error) { defer s.mutex.Unlock() if s.Id != st.Id || s.Sid != st.Sid { - return "", errors.New("session id mismatch") + return "", NewDataError("invalid_session_token", "session id mismatch") } if s.userid != "" { - return "", errors.New("session already authenticated") + return "", NewDataError("already_authenticated", "session already authenticated") } // Create authentication nonce. var err error s.Nonce, err = sessionNonces.Encode(fmt.Sprintf("%s@%s", s.Sid, realm), st.Userid) + if err != nil { + err = NewDataError("unknown", err.Error()) + } return s.Nonce, err @@ -330,18 +332,18 @@ func (s *Session) Authenticate(realm string, st *SessionToken, userid string) er defer s.mutex.Unlock() if s.userid != "" { - return errors.New("session already authenticated") + return NewDataError("already_authenticated", "session already authenticated") } if userid == "" { if s.Nonce == "" || s.Nonce != st.Nonce { - return errors.New("nonce validation failed") + return NewDataError("invalid_session_token", "nonce validation failed") } err := sessionNonces.Decode(fmt.Sprintf("%s@%s", s.Sid, realm), st.Nonce, &userid) if err != nil { - return err + return NewDataError("invalid_session_token", err.Error()) } if st.Userid != userid { - return errors.New("user id mismatch") + return NewDataError("invalid_session_token", "user id mismatch") } s.Nonce = "" } From dcf1cc687a2e20e980ce2e0248826fc431951b0d Mon Sep 17 00:00:00 2001 From: Lance Cooper Date: Wed, 8 Apr 2015 10:34:39 -0500 Subject: [PATCH 017/121] Rename MakeSelf to HandleSelf as it now conforms to handler usage. --- src/app/spreed-webrtc-server/channelling_api.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index 200b1daa..f16bb7e1 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -62,7 +62,7 @@ func NewChannellingAPI(config *Config, roomStatus RoomStatusManager, sessionEnco func (api *channellingAPI) OnConnect(client Client, session *Session) (interface{}, error) { api.Unicaster.OnConnect(client, session) - return api.MakeSelf(session) + return api.HandleSelf(session) } func (api *channellingAPI) OnDisconnect(client Client, session *Session) { @@ -72,7 +72,7 @@ func (api *channellingAPI) OnDisconnect(client Client, session *Session) { func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *DataIncoming) (interface{}, error) { switch msg.Type { case "Self": - return api.MakeSelf(session) + return api.HandleSelf(session) case "Hello": if msg.Hello == nil { return nil, NewDataError("bad_request", "message did not contain Hello") @@ -162,7 +162,7 @@ func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *Data return nil, nil } -func (api *channellingAPI) MakeSelf(session *Session) (*DataSelf, error) { +func (api *channellingAPI) HandleSelf(session *Session) (*DataSelf, error) { token, err := api.EncodeSessionToken(session) if err != nil { log.Println("Error in OnRegister", err) @@ -216,7 +216,7 @@ func (api *channellingAPI) HandleAuthentication(session *Session, st *SessionTok } log.Println("Authentication success", session.Userid()) - self, err := api.MakeSelf(session) + self, err := api.HandleSelf(session) if err == nil { session.BroadcastStatus() } From 9fd382689765102f2f953bf292c916a699c18b3f Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 9 Apr 2015 14:11:21 +0200 Subject: [PATCH 018/121] Use constraints service for TURN and STUN data. --- .../js/controllers/mediastreamcontroller.js | 49 ++++++------------- static/js/services/constraints.js | 27 +++++++++- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index e652cf62..04fbe58d 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -97,12 +97,14 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder var displayName = safeDisplayName; - // Init STUN and TURN servers. - $scope.stun = mediaStream.config.StunURIs || []; - if (!$scope.stun.length) { - $scope.stun.push("stun:stun.l.google.com:19302") - } - $scope.turn = {}; // TURN servers are set on received.self. + // Init STUN. + (function() { + var stun = mediaStream.config.StunURIs || []; + if (!stun.length) { + stun.push("stun:stun.l.google.com:19302"); + } + constraints.stun(stun); + })(); // Add browser details for easy access. $scope.isChrome = $window.webrtcDetectedBrowser === "chrome"; @@ -201,34 +203,8 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder }; $scope.refreshWebrtcSettings = function() { - - if (!$window.webrtcDetectedBrowser) { - console.warn("This is not a WebRTC capable browser."); - return; - } - - var settings = $scope.master.settings; - - // Create iceServers from scope. - var iceServers = []; - var iceServer; - if ($scope.stun.length) { - iceServer = $window.createIceServers($scope.stun); - if (iceServer.length) { - iceServers.push.apply(iceServers, iceServer); - } - } - if ($scope.turn.urls && $scope.turn.urls.length) { - iceServer = $window.createIceServers($scope.turn.urls, $scope.turn.username, $scope.turn.password); - if (iceServer.length) { - iceServers.push.apply(iceServers, iceServer); - } - } - mediaStream.webrtc.settings.pcConfig.iceServers = iceServers; - // Refresh constraints. constraints.refresh($scope.master.settings); - }; $scope.refreshWebrtcSettings(); // Call once for bootstrap. @@ -341,10 +317,13 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder scope.id = scope.myid = data.Id; scope.userid = scope.myuserid = data.Userid ? data.Userid : null; scope.suserid = data.Suserid ? data.Suserid : null; - scope.turn = data.Turn; - scope.stun = data.Stun; - scope.refreshWebrtcSettings(); }); + + // Set TURN and STUN data and refresh webrtc settings. + constraints.turn(data.Turn); + constraints.stun(data.Stun); + $scope.refreshWebrtcSettings(); + if (data.Version !== mediaStream.version) { console.info("Server was upgraded. Reload required."); if (!reloadDialog) { diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 6dbecefb..09d5009d 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -20,7 +20,7 @@ */ "use strict"; - define(["jquery", "underscore"], function($, _) { + define(["jquery", "underscore", "webrtc.adapter"], function($, _) { // constraints return ["webrtc", "$window", "$q", function(webrtc, $window, $q) { @@ -99,6 +99,8 @@ // Define our service helpers service.e = $({}); // events + service.stun = []; + service.turn = {}; // Create as WebRTC data structure. service.mediaConstraints = function(constraints) { @@ -125,6 +127,26 @@ webrtc.settings.pcConstraints.optional = constraints.pc; }; + service.iceServers = function(constraints) { + + var iceServers = []; + var iceServer; + if (service.stun && service.stun.length) { + iceServer = $window.createIceServers(service.stun); + if (iceServer.length) { + iceServers.push.apply(iceServers, iceServer) + } + } + if (service.turn && service.turn.urls && service.turn.urls.length) { + iceServer = $window.createIceServers(service.turn.urls, service.turn.username, service.turn.password); + if (iceServer.length) { + iceServers.push.apply(iceServers, iceServer) + } + } + webrtc.settings.pcConfig.iceServers = iceServers; + + }; + // Some default constraints. service.e.on("refresh", function(event, constraints) { @@ -156,10 +178,11 @@ return $q.all(constraints.promises).then(function() { service.mediaConstraints(constraints); service.pcConstraints(constraints); + service.iceServers(constraints); }); }, + // Setters for TURN and STUN data. turn: function(turnData) { - // Set TURN server details. service.turn = turnData; }, stun: function(stunData) { From e2dcbef0d5667d0cf329193dfca544ce854a7ea3 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Thu, 9 Apr 2015 14:16:21 +0200 Subject: [PATCH 019/121] No longer include Google STUN as default in client. This allows setups without a STUN server. --- static/js/controllers/mediastreamcontroller.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index 04fbe58d..313ffadf 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -97,12 +97,9 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder var displayName = safeDisplayName; - // Init STUN. + // Init STUN from server config. (function() { var stun = mediaStream.config.StunURIs || []; - if (!stun.length) { - stun.push("stun:stun.l.google.com:19302"); - } constraints.stun(stun); })(); From 5d2b7432dac3fd9675335f86b7ad029434246674 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Wed, 8 Apr 2015 16:46:47 +0200 Subject: [PATCH 020/121] Revert incorrect changes made in 6332450 to the translation api. --- static/js/services/translation.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/static/js/services/translation.js b/static/js/services/translation.js index 9bb7d3ee..2641e85d 100644 --- a/static/js/services/translation.js +++ b/static/js/services/translation.js @@ -30,25 +30,25 @@ define(["jed", "underscore"], function(Jed, _) { this._ = _.bind(function() { if (domain && context) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 0); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).onDomain(domain).withContext(context); return r.fetch.apply(r, vars); }, this); } else if (domain) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 0); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).onDomain(domain); return r.fetch.apply(r, vars); }, this); } else if (context) { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 0); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular).withContext(context); return r.fetch.apply(r, vars); }, this); } else { return _.bind(function(singular) { - var vars = Array.prototype.slice.call(arguments, 0); + var vars = Array.prototype.slice.call(arguments, 1); var r = i18n.translate(singular); return r.fetch.apply(r, vars); }, this); @@ -59,25 +59,25 @@ define(["jed", "underscore"], function(Jed, _) { this._n = _.bind(function() { if (domain && context) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 2); var r = i18n.translate(singular).onDomain(domain).withContext(context).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else if (domain) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 2); var r = i18n.translate(singular).onDomain(domain).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else if (context) { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 2); var r = i18n.translate(singular).withContext(context).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }); } else { return _.bind(function(singular, plural) { - var vars = Array.prototype.slice.call(arguments, 1); + var vars = Array.prototype.slice.call(arguments, 2); var r = i18n.translate(singular).ifPlural(vars[0], plural); return r.fetch.apply(r, vars); }) From b5f48931735c0a768ca8d0cd19fca8a2de6da393 Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 3 Mar 2015 14:33:43 +0100 Subject: [PATCH 021/121] Do not let globally set scss-lint IdSelectors affect display of errors in other files. --- src/styles/Makefile.am | 4 +++- src/styles/scss.yml | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/styles/Makefile.am b/src/styles/Makefile.am index 1a8f2980..469271d9 100644 --- a/src/styles/Makefile.am +++ b/src/styles/Makefile.am @@ -46,4 +46,6 @@ styleshint: styleslint: @if [ "$(SCSS_LINT)" = "" ]; then echo "Command 'scss-lint' not found, required when linting styles"; exit 1; fi - $(SCSS_LINT) -c scss.yml + @echo "Please be patient, this takes a while..." + @files=`find . -not -path "*/libs/*" -name "*.scss"|sort -u`; \ + for f in $$files; do $(SCSS_LINT) -c scss.yml $$f; done diff --git a/src/styles/scss.yml b/src/styles/scss.yml index 80c15e53..1af0bd0b 100644 --- a/src/styles/scss.yml +++ b/src/styles/scss.yml @@ -1,7 +1,3 @@ -scss_files: "**/*.scss" - -exclude: "libs/**" - linters: BangFormat: enabled: true From 3da4f7947097215c47f7125c3413b264ebcd47ea Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 13 Apr 2015 10:52:58 +0200 Subject: [PATCH 022/121] Improved bash fu. --- src/styles/Makefile.am | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/styles/Makefile.am b/src/styles/Makefile.am index 469271d9..9e0b73c5 100644 --- a/src/styles/Makefile.am +++ b/src/styles/Makefile.am @@ -46,6 +46,4 @@ styleshint: styleslint: @if [ "$(SCSS_LINT)" = "" ]; then echo "Command 'scss-lint' not found, required when linting styles"; exit 1; fi - @echo "Please be patient, this takes a while..." - @files=`find . -not -path "*/libs/*" -name "*.scss"|sort -u`; \ - for f in $$files; do $(SCSS_LINT) -c scss.yml $$f; done + $(FIND) ./ -not -path "./libs/*" -name "*.scss" -print0 | xargs -0 -n1 $(SCSS_LINT) -c scss.yml From ccdd51fd7457811454bfb888842202bb9d0395c7 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 6 Apr 2015 00:19:07 +0200 Subject: [PATCH 023/121] Worked to get screen sharing to FF. Use new mediaDevices service. Prepare to support video constraints in FF>=38. Disable HD constraints for Firefox. --- .../js/controllers/mediastreamcontroller.js | 2 +- static/js/directives/buddypicturecapture.js | 8 +- static/js/directives/settings.js | 58 +++++------ static/js/mediastream/usermedia.js | 98 ++++++++++++++++++- static/js/services/constraints.js | 18 +++- static/js/services/mediadevices.js | 62 ++++++++++++ static/js/services/screensharing.js | 23 ++++- static/js/services/services.js | 9 +- static/partials/settings.html | 28 +++--- 9 files changed, 249 insertions(+), 57 deletions(-) create mode 100644 static/js/services/mediadevices.js diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index 313ffadf..c8e931ee 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -111,7 +111,7 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder // Add support status. $scope.supported = { screensharing: screensharing.supported, - renderToAssociatedSink: $window.navigator.platform.indexOf("Win") === 0 + constraints: constraints.supported } // Default scope data. diff --git a/static/js/directives/buddypicturecapture.js b/static/js/directives/buddypicturecapture.js index 7d09ccce..09a21951 100644 --- a/static/js/directives/buddypicturecapture.js +++ b/static/js/directives/buddypicturecapture.js @@ -25,7 +25,7 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct // buddyPictureCapture return ["$compile", "$window", function($compile, $window) { - var controller = ['$scope', 'safeApply', '$timeout', '$q', function($scope, safeApply, $timeout, $q) { + var controller = ['$scope', 'safeApply', '$timeout', '$q', "mediaDevices", function($scope, safeApply, $timeout, $q, mediaDevices) { // Buddy picutre capture size. $scope.captureSize = { @@ -126,16 +126,16 @@ define(['jquery', 'underscore', 'text!partials/buddypicturecapture.html'], funct }] }; } - $window.getUserMedia({ + mediaDevices.getUserMedia({ video: videoConstraints - }, function(stream) { + }).then(function(stream) { $scope.showTakePicture = true; localStream = stream; $scope.waitingForPermission = false; $window.attachMediaStream($scope.video, stream); safeApply($scope); videoAllowed.resolve(true); - }, function(error) { + }).catch(function(error) { console.error('Failed to get access to local media. Error code was ' + error.code); $scope.waitingForPermission = false; safeApply($scope); diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index 26d2cb0e..925b03ad 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -171,29 +171,29 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t $timeout($scope.maybeShowSettings); }); - constraints.e.on("refresh", function(event, constraints) { + constraints.e.on("refresh", function(event, c) { var settings = $scope.master.settings; // Assert that selected devices are there. (function() { - var deferred = constraints.defer(); + var deferred = c.defer(); mediaSources.refresh(function() { $scope.checkDefaultMediaSources(); // Select microphone device by id. if (settings.microphoneId) { - constraints.add("audio", "sourceId", settings.microphoneId); + c.add("audio", "sourceId", settings.microphoneId); } // Select camera by device id. if (settings.cameraId) { - constraints.add("video", "sourceId", settings.cameraId); + c.add("video", "sourceId", settings.cameraId); } if (!mediaSources.hasAudio()) { - constraints.disable('audio'); + c.disable('audio'); console.info("Disabled audio input as no audio source was found."); } if (!mediaSources.hasVideo()) { - constraints.disable('video'); + c.disable('video'); console.info("Disabled video input as no video source was found."); } deferred.resolve("complete"); @@ -201,7 +201,7 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t })(); // Chrome only constraints. - if ($scope.isChrome) { + if (constraints.supported.chrome) { // Chrome specific constraints overview: // https://code.google.com/p/webrtc/source/browse/trunk/talk/app/webrtc/mediaconstraintsinterface.cc @@ -211,24 +211,24 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t // Experimental audio settings. if (settings.experimental.enabled) { - constraints.add("audio", "googEchoCancellation", true); // defaults to true - constraints.add("audio", "googEchoCancellation2", settings.experimental.audioEchoCancellation2 && true); // defaults to false in Chrome - constraints.add("audio", "googAutoGainControl", true); // defaults to true - constraints.add("audio", "googAutoGainControl2", settings.experimental.audioAutoGainControl2 && true); // defaults to false in Chrome - constraints.add("audio", "googNoiseSuppression", true); // defaults to true - constraints.add("audio", "googgNoiseSuppression2", settings.experimental.audioNoiseSuppression2 && true); // defaults to false in Chrome - constraints.add("audio", "googHighpassFilter", true); // defaults to true - constraints.add("audio", "googTypingNoiseDetection", settings.experimental.audioTypingNoiseDetection && true); // defaults to true in Chrome + c.add("audio", "googEchoCancellation", true); // defaults to true + c.add("audio", "googEchoCancellation2", settings.experimental.audioEchoCancellation2 && true); // defaults to false in Chrome + c.add("audio", "googAutoGainControl", true); // defaults to true + c.add("audio", "googAutoGainControl2", settings.experimental.audioAutoGainControl2 && true); // defaults to false in Chrome + c.add("audio", "googNoiseSuppression", true); // defaults to true + c.add("audio", "googgNoiseSuppression2", settings.experimental.audioNoiseSuppression2 && true); // defaults to false in Chrome + c.add("audio", "googHighpassFilter", true); // defaults to true + c.add("audio", "googTypingNoiseDetection", settings.experimental.audioTypingNoiseDetection && true); // defaults to true in Chrome } - if ($scope.supported.renderToAssociatedSink) { + if (constraints.supported.renderToAssociatedSink) { // When true uses the default communications device on Windows. // https://codereview.chromium.org/155863003 - constraints.add("audio", "googDucking", true); // defaults to true on Windows. + c.add("audio", "googDucking", true); // defaults to true on Windows. // Chrome will start rendering mediastream output to an output device that's associated with // the input stream that was opened via getUserMedia. // https://chromiumcodereview.appspot.com/23558010 - constraints.add("audio", "chromeRenderToAssociatedSink", settings.audioRenderToAssociatedSkin && true); // defaults to false in Chrome + c.add("audio", "chromeRenderToAssociatedSink", settings.audioRenderToAssociatedSkin && true); // defaults to false in Chrome } // Experimental video settings. @@ -236,44 +236,44 @@ define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, t // Changes the way the video encoding adapts to the available bandwidth. // https://code.google.com/p/webrtc/issues/detail?id=3351 - constraints.add(["video", "screensharing"], "googLeakyBucket", settings.experimental.videoLeakyBucket && true); // defaults to false in Chrome + c.add(["video", "screensharing"], "googLeakyBucket", settings.experimental.videoLeakyBucket && true); // defaults to false in Chrome // Removes the noise in the captured video stream at the expense of CPU. - constraints.add(["video", "screensharing"], "googNoiseReduction", settings.experimental.videoNoiseReduction && true); // defaults to false in Chrome - constraints.add("pc", "googCpuOveruseDetection", settings.experimental.videoCpuOveruseDetection && true); // defaults to true in Chrome + c.add(["video", "screensharing"], "googNoiseReduction", settings.experimental.videoNoiseReduction && true); // defaults to false in Chrome + c.add("pc", "googCpuOveruseDetection", settings.experimental.videoCpuOveruseDetection && true); // defaults to true in Chrome } + } + + if (constraints.supported.audioVideo) { + // Set video quality. var videoQuality = videoQualityMap[settings.videoQuality]; if (videoQuality) { var mandatory = videoQuality.mandatory; _.forEach(videoQuality, function(v, k) { if (k !== "mandatory") { - constraints.add("video", k, v, mandatory ? false : true); + c.add("video", k, v, mandatory ? false : true); } }); if (mandatory) { _.forEach(mandatory, function(v, k) { - constraints.add("video", k, v, true); + c.add("video", k, v, true); }); } } // Set max frame rate if any was selected. if (settings.maxFrameRate && settings.maxFrameRate != "auto") { - constraints.add("video", "maxFrameRate", parseInt(settings.maxFrameRate, 10), true); + c.add("video", "maxFrameRate", parseInt(settings.maxFrameRate, 10), true); } // Disable AEC if stereo. // https://github.com/webrtc/apprtc/issues/23 if (settings.sendStereo) { - constraints.add("audio", "echoCancellation", false); + c.add("audio", "echoCancellation", false); } - } else { - - // Other browsers constraints (there are none as of now.); - } }); diff --git a/static/js/mediastream/usermedia.js b/static/js/mediastream/usermedia.js index ebc7dc17..0761fbce 100644 --- a/static/js/mediastream/usermedia.js +++ b/static/js/mediastream/usermedia.js @@ -30,6 +30,100 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _ // Firefox and Chrome with Firefox interop. var enableRenegotiationSupport = false; + // Converter helpers to convert media constraints to new API. + var mergeConstraints = function(constraints, k, v, mandatory) { + var prefix = k.substring(0, 3); + switch (prefix) { + case "min": + case "max": + var suffix = k[3].toLowerCase()+k.substring(4); + if (!constraints.hasOwnProperty(suffix)) { + constraints[suffix]={}; + } + if (mandatory && prefix === "min" && constraints[suffix].hasOwnProperty(prefix)) { + // Use existing min constraint as ideal. + constraints[suffix].ideal = constraints[suffix].min; + } + constraints[suffix][prefix]=v; + break; + default: + constraints[k] = v; + break; + } + }; + var convertConstraints = function(constraints) { + if (!constraints) { + return false; + } + if (!constraints.hasOwnProperty("optional") && !constraints.hasOwnProperty("mandatory")) { + // No old style members. + return constraints; + } + var c = {}; + // Process optional constraints. + if (constraints.optional) { + _.each(constraints.optional, function(o) { + _.each(o, function(v, k) { + mergeConstraints(c, k, v); + }) + }); + } + // Process mandatory constraints. + if (constraints.mandatory) { + _.each(constraints.mandatory, function(v, k) { + mergeConstraints(c, k, v, true); + }); + } + // Fastpath. + if (_.isEmpty(c)) { + return true; + } + // Use ideal if there is only one value set. + _.each(c, function(v, k) { + if (_.isObject(v)) { + var values = _.values(v); + if (values.length === 1) { + // Use as ideal value if only one given. + c[k] = {ideal: values[0]}; + } + } + }); + if (window.webrtcDetectedBrowser === "firefox" && window.webrtcDetectedVersion < 38) { + // Firefox < 38 needs a extra require field. + var r = []; + if (c.height) { + r.push("height"); + } + if (c.width) { + r.push("width"); + } + if (r.length) { + c.require = r; + } + } + return c; + }; + // Adapter to support navigator.mediaDevices API. + // http://w3c.github.io/mediacapture-main/getusermedia.html#mediadevices + var getUserMedia = (function() { + if (window.navigator.mediaDevices) { + console.info("Enabled mediaDevices adapter ..."); + return function(constraints, success, error) { + // Full constraints syntax with plain values and ideal-algorithm supported in FF38+. + // Note on FF32-37: Plain values and ideal are not supported. + // See https://wiki.mozilla.org/Media/getUserMedia for details. + // Examples here: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia + var c = {audio: convertConstraints(constraints.audio), video: convertConstraints(constraints.video)}; + // mediaDevices API returns a promise. + console.log("Constraints for mediaDevices", c); + window.navigator.mediaDevices.getUserMedia(c).then(success).catch(error); + } + } else { + // Use existing adapter. + return window.getUserMedia; + } + })(); + var UserMedia = function(options) { this.options = $.extend({}, options); @@ -128,7 +222,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _ error_cb.apply(this, args); }; try { - window.getUserMedia({ + getUserMedia({ video: true, audio: true }, success_helper, error_helper); @@ -173,7 +267,7 @@ define(['jquery', 'underscore', 'audiocontext', 'webrtc.adapter'], function($, _ try { console.log('Requesting access to local media with mediaConstraints:\n' + ' \'' + JSON.stringify(constraints) + '\'', constraints); - window.getUserMedia(constraints, _.bind(this.onUserMediaSuccess, this), _.bind(this.onUserMediaError, this)); + getUserMedia(constraints, _.bind(this.onUserMediaSuccess, this), _.bind(this.onUserMediaError, this)); this.started = true; return true; } catch (e) { diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 09d5009d..6394a886 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -187,7 +187,23 @@ }, stun: function(stunData) { service.stun = stunData; - } + }, + supported: (function() { + var isChrome = $window.webrtcDetectedBrowser === "chrome"; + var isFirefox = $window.webrtcDetectedBrowser === "firefox"; + var version = $window.webrtcDetectedVersion; + // Constraints support table. + return { + // Chrome supports it. See https://wiki.mozilla.org/Media/getUserMedia for FF details. + audioVideo: isChrome || (isFirefox && version >= 38), + // Disable FF HD constraints for now (see https://bugzilla.mozilla.org/show_bug.cgi?id=1150539) + hdVideo: isChrome, + // Chrome supports this on Windows only. + renderToAssociatedSink: isChrome && $window.navigator.platform.indexOf("Win") === 0, + chrome: isChrome, + firefox: isFirefox + }; + })() }; }]; diff --git a/static/js/services/mediadevices.js b/static/js/services/mediadevices.js new file mode 100644 index 00000000..5680aa1a --- /dev/null +++ b/static/js/services/mediadevices.js @@ -0,0 +1,62 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +/* global Promise */ +"use strict"; +define(['webrtc.adapter'], function() { + + // mediaDevices + return ["$window", function($window) { + + var mediaDevices = $window.navigator.mediaDevices || {}; + var getUserMedia = (function() { + // Implement a Promise based wrapper around getUserMedia. + if (mediaDevices.getUserMedia) { + // mediaDevices calls return Promise native. + return mediaDevices.getUserMedia.bind(mediaDevices); + } else { + return function getUserMedia(constraints) { + return new Promise(function(resolve, reject) { + var onSuccess = function(stream) { + resolve(stream) + }; + var onError = function(error) { + reject(error); + }; + try { + $window.getUserMedia(constraints, onSuccess, onError); + } catch(err) { + onError(err); + } + }); + } + } + })(); + + // Public api. + return { + shim: mediaDevices.getUserMedia ? false : true, + getUserMedia: getUserMedia + } + + }]; + +}); \ No newline at end of file diff --git a/static/js/services/screensharing.js b/static/js/services/screensharing.js index 515c5a43..722b7bc4 100644 --- a/static/js/services/screensharing.js +++ b/static/js/services/screensharing.js @@ -121,10 +121,27 @@ define(['underscore', 'webrtc.adapter'], function(_) { } - } else { - // Currently Chrome only - sorry. - // Firefox 33 might get screen sharing support. + } else if ($window.webrtcDetectedBrowser === "firefox") { + + // Firefox 36 got screen sharing support. // See https://bugzilla.mozilla.org/show_bug.cgi?id=923225 + if ($window.webrtcDetectedVersion >= 36) { + this.supported = true; + this.prepare = function(options) { + // To work, the current domain must be whitelisted in + // media.getusermedia.screensharing.allowed_domains (about:config). + // See https://wiki.mozilla.org/Screensharing for reference. + var d = $q.defer() + var opts = _.extend({ + mediaSource: "screen" + }, options); + d.resolve(opts); + return d.promise; + }; + } + + } else { + // No support for screen sharing. } // Auto install support. diff --git a/static/js/services/services.js b/static/js/services/services.js index 18c5eeec..b0fb7d02 100644 --- a/static/js/services/services.js +++ b/static/js/services/services.js @@ -66,7 +66,8 @@ define([ 'services/resturl', 'services/roompin', 'services/constraints', - 'services/modules'], function(_, + 'services/modules', + 'services/mediadevices'], function(_, desktopNotify, playSound, safeApply, @@ -110,7 +111,8 @@ rooms, restURL, roompin, constraints, -modules) { +modules, +mediaDevices) { var services = { desktopNotify: desktopNotify, @@ -156,7 +158,8 @@ modules) { restURL: restURL, roompin: roompin, constraints: constraints, - modules: modules + modules: modules, + mediaDevices: mediaDevices }; var initialize = function(angModule) { diff --git a/static/partials/settings.html b/static/partials/settings.html index 341ee594..c894303e 100644 --- a/static/partials/settings.html +++ b/static/partials/settings.html @@ -66,7 +66,7 @@
- + {{_('Media')}}
@@ -82,14 +82,14 @@
-
+
- - + +
@@ -130,7 +130,7 @@
-
+
@@ -143,7 +143,7 @@
-
+
@@ -154,7 +154,7 @@
-
+
@@ -165,7 +165,7 @@
-
+
@@ -178,7 +178,7 @@
-
+
@@ -191,7 +191,7 @@
-
+
@@ -203,7 +203,7 @@
-
+
@@ -217,7 +217,7 @@
-
+
@@ -228,7 +228,7 @@
-
+
@@ -241,7 +241,7 @@
-
+
From 0c6d47b38cfee5bf85cb4aefbf33075478949bba Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 7 Apr 2015 19:23:54 +0200 Subject: [PATCH 024/121] Enable HD constraints for FF >= 38 as https://bugzilla.mozilla.org/show_bug.cgi?id=1151628 was fixed. Lets hope it will land in 38. --- static/js/services/constraints.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 6394a886..99d94bc0 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -196,8 +196,8 @@ return { // Chrome supports it. See https://wiki.mozilla.org/Media/getUserMedia for FF details. audioVideo: isChrome || (isFirefox && version >= 38), - // Disable FF HD constraints for now (see https://bugzilla.mozilla.org/show_bug.cgi?id=1150539) - hdVideo: isChrome, + // HD constraints in Chrome no issue. In FF we just assume MJPEG is fixed with FF 38 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1151628). + hdVideo: isChrome || (isFirefox && version >= 38), // Chrome supports this on Windows only. renderToAssociatedSink: isChrome && $window.navigator.platform.indexOf("Win") === 0, chrome: isChrome, From 4f9e0abb363156bea36845cd7d17339d4e6842ca Mon Sep 17 00:00:00 2001 From: Evan Theurer Date: Tue, 3 Mar 2015 11:02:42 +0100 Subject: [PATCH 025/121] Fix scss-lint error IdSelector. --- src/styles/components/_audiolevel.scss | 2 +- src/styles/components/_audiovideo.scss | 40 ++++++++++++++---------- src/styles/components/_buddylist.scss | 8 ++--- src/styles/components/_chat.scss | 3 +- src/styles/components/_presentation.scss | 3 +- src/styles/components/_rightslide.scss | 11 ++++--- src/styles/components/_roombar.scss | 2 +- src/styles/components/_screenshare.scss | 3 +- src/styles/components/_settings.scss | 2 +- src/styles/components/_usability.scss | 23 +++++++++----- src/styles/components/_youtubevideo.scss | 6 ++-- src/styles/global/_base.scss | 4 +-- src/styles/global/_loader.scss | 2 +- src/styles/global/_pages.scss | 2 +- static/partials/usability.html | 2 +- 15 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/styles/components/_audiolevel.scss b/src/styles/components/_audiolevel.scss index 81d2f253..b1dc4239 100644 --- a/src/styles/components/_audiolevel.scss +++ b/src/styles/components/_audiolevel.scss @@ -19,7 +19,7 @@ * */ -#audiolevel { +#audiolevel { // scss-lint:disable IdSelector left: 0; margin: 0 auto; position: fixed; diff --git a/src/styles/components/_audiovideo.scss b/src/styles/components/_audiovideo.scss index d2ea565f..9481bfe4 100644 --- a/src/styles/components/_audiovideo.scss +++ b/src/styles/components/_audiovideo.scss @@ -19,7 +19,29 @@ * */ -#audiovideo { +.mainScreenshare, +.mainPresentation { + // scss-lint:disable IdSelector + #audiovideo { + @include breakpt($breakpoint-video-medium, max-width, only screen) { + display: none; + } + } +} + +.withChat, +.withBuddylist { + // scss-lint:disable IdSelector + #audiovideo { + right: 260px; + } +} + +.withBuddylist.withChat #audiovideo { // scss-lint:disable IdSelector + right: 520px; +} + +#audiovideo { // scss-lint:disable IdSelector bottom: 0; left: 0; position: absolute; @@ -43,22 +65,6 @@ } } -.mainScreenshare #audiovideo, -.mainPresentation #audiovideo { - @include breakpt($breakpoint-video-medium, max-width, only screen) { - display: none; - } -} - -.withChat #audiovideo, -.withBuddylist #audiovideo { - right: 260px; -} - -.withBuddylist.withChat #audiovideo { - right: 520px; -} - .audiovideo { bottom: 0; left: 0; diff --git a/src/styles/components/_buddylist.scss b/src/styles/components/_buddylist.scss index 6560a5af..8cac6628 100644 --- a/src/styles/components/_buddylist.scss +++ b/src/styles/components/_buddylist.scss @@ -19,7 +19,7 @@ * */ -#buddylist { +#buddylist { // scss-lint:disable IdSelector bottom: 0; position: absolute; right: 0; @@ -28,7 +28,7 @@ z-index: 50; } -#buddylist:before { +#buddylist:before { // scss-lint:disable IdSelector background: $buddylist-tab-background; border-bottom: 1px solid $bordercolor; border-bottom-left-radius: 6px; @@ -55,12 +55,12 @@ z-index: 1; } -.withBuddylist #buddylist:before { +.withBuddylist #buddylist:before { // scss-lint:disable IdSelector content: '\f101'; padding-right: 0; } -.withBuddylistAutoHide #buddylist:before { +.withBuddylistAutoHide #buddylist:before { // scss-lint:disable IdSelector display: block; } diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss index 1b979bff..a9f4c9fb 100644 --- a/src/styles/components/_chat.scss +++ b/src/styles/components/_chat.scss @@ -19,7 +19,7 @@ * */ -#chat { +#chat { // scss-lint:disable IdSelector bottom: 0; min-width: $chat-width; opacity: 0; @@ -32,6 +32,7 @@ } .withChat { + // scss-lint:disable IdSelector #chat { opacity: 1; } diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index a0101fa5..487a1f94 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -19,7 +19,8 @@ * */ -.mainPresentation #presentation { + +.mainPresentation #presentation { // scss-lint:disable IdSelector display: block; } diff --git a/src/styles/components/_rightslide.scss b/src/styles/components/_rightslide.scss index a7c2b9c3..9fd0eb82 100644 --- a/src/styles/components/_rightslide.scss +++ b/src/styles/components/_rightslide.scss @@ -19,7 +19,12 @@ * */ -#rightslide { + +.withBuddylist #rightslide { // scss-lint:disable IdSelector + right: 0; +} + +#rightslide { // scss-lint:disable IdSelector bottom: 0; left: 0; pointer-events: none; @@ -35,7 +40,3 @@ width: 100%; } } - -.withBuddylist #rightslide { - right: 0; -} diff --git a/src/styles/components/_roombar.scss b/src/styles/components/_roombar.scss index b182d44c..1d7c499c 100644 --- a/src/styles/components/_roombar.scss +++ b/src/styles/components/_roombar.scss @@ -19,7 +19,7 @@ * */ -#roombar { +#roombar { // scss-lint:disable IdSelector left: 0; min-width: 260px; position: absolute; diff --git a/src/styles/components/_screenshare.scss b/src/styles/components/_screenshare.scss index 838bae41..c5028d60 100644 --- a/src/styles/components/_screenshare.scss +++ b/src/styles/components/_screenshare.scss @@ -19,7 +19,8 @@ * */ -.mainScreenshare #screenshare { + +.mainScreenshare #screenshare { // scss-lint:disable IdSelector display: block; } diff --git a/src/styles/components/_settings.scss b/src/styles/components/_settings.scss index 3b874c8a..55d1fcac 100644 --- a/src/styles/components/_settings.scss +++ b/src/styles/components/_settings.scss @@ -19,7 +19,7 @@ * */ -#settings { +#settings { // scss-lint:disable IdSelector // scss-lint:disable NestingDepth background: $settings-background; border-left: 1px solid $bordercolor; diff --git a/src/styles/components/_usability.scss b/src/styles/components/_usability.scss index 20c87055..3db56ef4 100644 --- a/src/styles/components/_usability.scss +++ b/src/styles/components/_usability.scss @@ -19,17 +19,24 @@ * */ -.withChat #help, -.withBuddylist #help { - right: 260px; + +.withChat, +.withBuddylist { + // scss-lint:disable IdSelector + #help { + right: 260px; + } } -.withChat.withBuddylist #help, -.withSettings #help { - right: 520px; +.withChat.withBuddylist, +.withSettings { + // scss-lint:disable IdSelector + #help { + right: 520px; + } } -#help { +#help { // scss-lint:disable IdSelector bottom: 10px; color: #aaa; font-size: 1.1em; @@ -42,7 +49,9 @@ transition: right 200ms ease-in-out; user-select: none; width: 350px; +} +.help { @include breakpt($breakpoint-useability-small, max-width, only screen) { display: none; } diff --git a/src/styles/components/_youtubevideo.scss b/src/styles/components/_youtubevideo.scss index 0221154e..8d122f72 100644 --- a/src/styles/components/_youtubevideo.scss +++ b/src/styles/components/_youtubevideo.scss @@ -19,7 +19,7 @@ * */ -.mainYoutubevideo #youtubevideo { +.mainYoutubevideo #youtubevideo { // scss-lint:disable IdSelector display: block; } @@ -90,11 +90,11 @@ top: 0; } -#youtubecontainer { +#youtubecontainer { // scss-lint:disable IdSelector position: relative; } -#youtubeplayerinfo { +#youtubeplayerinfo { // scss-lint:disable IdSelector bottom: 10%; left: 0; opacity: 0; diff --git a/src/styles/global/_base.scss b/src/styles/global/_base.scss index 42d2305e..e1db99f7 100644 --- a/src/styles/global/_base.scss +++ b/src/styles/global/_base.scss @@ -38,7 +38,7 @@ a { cursor: pointer; } -#background { +#background { // scss-lint:disable IdSelector background: $main-background; bottom: 0; left: 0; @@ -68,4 +68,4 @@ a { :fullscreen { background: #000; -} \ No newline at end of file +} diff --git a/src/styles/global/_loader.scss b/src/styles/global/_loader.scss index 9f2e9ad4..20d89f8f 100644 --- a/src/styles/global/_loader.scss +++ b/src/styles/global/_loader.scss @@ -19,7 +19,7 @@ * */ -#loader { +#loader { // scss-lint:disable IdSelector background: $load-logo no-repeat center; background-size: contain; bottom: 15%; diff --git a/src/styles/global/_pages.scss b/src/styles/global/_pages.scss index f10f2f63..487d7f8f 100644 --- a/src/styles/global/_pages.scss +++ b/src/styles/global/_pages.scss @@ -19,7 +19,7 @@ * */ -#page { +#page { // scss-lint:disable IdSelector bottom: 0; left: 0; position: absolute; diff --git a/static/partials/usability.html b/static/partials/usability.html index 8f57cd65..9c5e9002 100644 --- a/static/partials/usability.html +++ b/static/partials/usability.html @@ -1,4 +1,4 @@ -
+
{{_("Checking camera and microphone access.")}}
From 5bea610568f3b0de046d80d00fa0e3387a7c9a72 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 13 Apr 2015 18:32:27 +0200 Subject: [PATCH 026/121] Bumped constraints support for HD to FF 40 to make sure MJPEG works fine. --- static/js/services/constraints.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 99d94bc0..99224615 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -194,10 +194,10 @@ var version = $window.webrtcDetectedVersion; // Constraints support table. return { - // Chrome supports it. See https://wiki.mozilla.org/Media/getUserMedia for FF details. + // Chrome supports it. FF supports new spec starting 38. See https://wiki.mozilla.org/Media/getUserMedia for FF details. audioVideo: isChrome || (isFirefox && version >= 38), - // HD constraints in Chrome no issue. In FF we just assume MJPEG is fixed with FF 38 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1151628). - hdVideo: isChrome || (isFirefox && version >= 38), + // HD constraints in Chrome no issue. In FF we MJPEG is fixed with 40 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1151628). + hdVideo: isChrome || (isFirefox && version >= 40), // Chrome supports this on Windows only. renderToAssociatedSink: isChrome && $window.navigator.platform.indexOf("Win") === 0, chrome: isChrome, From c5a91562fcdc1bf44e1d7862724364e75020a7b3 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 14 Apr 2015 12:50:27 +0200 Subject: [PATCH 027/121] Added selection to make screen, window and application possible in Firefox. --- static/js/services/screensharing.js | 35 +++++++++++++++++++----- static/partials/screensharedialogff.html | 22 +++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 static/partials/screensharedialogff.html diff --git a/static/js/services/screensharing.js b/static/js/services/screensharing.js index 722b7bc4..5a5f572b 100644 --- a/static/js/services/screensharing.js +++ b/static/js/services/screensharing.js @@ -20,10 +20,22 @@ */ "use strict"; -define(['underscore', 'webrtc.adapter'], function(_) { +define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'], function(_, screenshareDialogFF) { + + var screenshareDialogFFController = ["$scope", "$modalInstance", "data", function($scope, $modalInstance, data) { + $scope.data = data; + $scope.cancel = function() { + $modalInstance.close(null); + }; + $scope.ok = function() { + $modalInstance.close($scope.data.selection); + }; + }]; // screensharing - return ["$window", "$q", "$timeout", "chromeExtension", function($window, $q, $timeout, chromeExtension) { + return ["$window", "$q", "$timeout", "chromeExtension", "dialogs", "$templateCache", function($window, $q, $timeout, chromeExtension, dialogs, $templateCache) { + + $templateCache.put('/dialogs/screensharedialogff.html', screenshareDialogFF); var Screensharing = function() { this.autoinstall = false; @@ -131,11 +143,20 @@ define(['underscore', 'webrtc.adapter'], function(_) { // To work, the current domain must be whitelisted in // media.getusermedia.screensharing.allowed_domains (about:config). // See https://wiki.mozilla.org/Screensharing for reference. - var d = $q.defer() - var opts = _.extend({ - mediaSource: "screen" - }, options); - d.resolve(opts); + var d = $q.defer(); + var dlg = dialogs.create('/dialogs/screensharedialogff.html', screenshareDialogFFController, {selection: "screen"}, {}); + dlg.result.then(function(source) { + if (source) { + var opts = _.extend({ + mediaSource: source + }, options); + d.resolve(opts); + } else { + d.resolve(null); + } + }, function(err) { + d.resolve(null); + }); return d.promise; }; } diff --git a/static/partials/screensharedialogff.html b/static/partials/screensharedialogff.html new file mode 100644 index 00000000..86a56687 --- /dev/null +++ b/static/partials/screensharedialogff.html @@ -0,0 +1,22 @@ +
+ + + +
\ No newline at end of file From 2c0892f0097ce04a6833ec8da1ff33871e13cd36 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 14 Apr 2015 13:50:20 +0200 Subject: [PATCH 028/121] Rebuilt styles. --- static/css/main.min.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/main.min.css b/static/css/main.min.css index 578b89a5..ee62d102 100644 --- a/static/css/main.min.css +++ b/static/css/main.min.css @@ -17,4 +17,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.withBuddylist #rightslide{right:0}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.logo .desc{display:none}}.logo .desc{font-style:italic;left:38px;position:relative;top:26px}.logo .desc a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.btn-mutemicrophone i:before{content:'\f130'}.btn-mutemicrophone.active i:before{content:'\f131'}.btn-mutecamera i:before{content:'\f06e'}.btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy.hovered .buddysessions{max-height:999px}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddy .buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddy .buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddy .buddysessions ul li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddy .buddysessions ul li .btn-group{visibility:hidden}.buddy .buddysessions ul li:hover .btn-group{visibility:visible}.buddy .buddysessions .currentsession .buddy3{font-weight:bold}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chat.active.visible{display:block}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message.with_hoverimage .buddyPicture{overflow:visible;z-index:initial}.chat .message.with_hoverimage .buddyPicture:hover .buddyInfoActions{height:40px;opacity:1}.chat .message.with_hoverimage .buddyInfoActions{cursor:default;display:inline-block;height:0;left:0;opacity:0;overflow:hidden;position:absolute;top:48px;-webkit-transition:opacity 0.1s .1s linear, height .4s .1s ease-out;transition:opacity 0.1s .1s linear, height .4s .1s ease-out;white-space:nowrap;z-index:1}.chat .message.with_hoverimage .buddyInfoActions .btn-group{display:block;margin:0 auto;width:55px}.chat .message.with_hoverimage .buddyInfoActions .btn-primary{padding:2px 5px}.chat .message.with_hoverimage .buddyInfoActions .fa{color:#fff;line-height:24px}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}@media only screen and (max-width: 400px){#help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){#help{font-size:1em;width:250px}}#help>div{margin:0 10px}#help .help-subline{color:#888;padding:20px 0}#help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;color:#eee;font-size:20em;left:41px;overflow:hidden;position:absolute;right:0;top:-82px;z-index:2}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.file-info .uploader .file-info-speed{bottom:6px}.file-info .uploader .actions{margin-left:30px;opacity:0}.file-info .uploader .anim{margin-left:0}.file-info .uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info .uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info .uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.mainScreenshare #screenshare{display:block}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.screenshare .overlaybar{bottom:0;left:0;right:0}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager tr:first-child td{border-top:0}.contactsmanager .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.mainPresentation #presentation{display:block}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail .filetype{font-size:5em}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome h1{white-space:normal}.presentationpane .welcome .btn{margin-top:30px}.presentationpane .welcome .progress span{text-shadow:none}.presentationpane .welcome .progress .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.pageinfo input{display:inline;width:70px}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-content form .overlaybar-buttons{position:absolute;right:23px;top:6px}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} + *//*! HiDPI v2.0.1 | MIT License | git.io/hidpi */.toast-title{font-weight:bold}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#ffffff}.toast-message a:hover{color:#cccccc;text-decoration:none}.toast-close-button{position:relative;right:-0.3em;top:-0.3em;float:right;font-size:20px;font-weight:bold;color:#ffffff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:hover,.toast-close-button:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-webkit-box-shadow:0 0 12px #999999;box-shadow:0 0 12px #999999;color:#ffffff;opacity:0.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-webkit-box-shadow:0 0 12px #000000;box-shadow:0 0 12px #000000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important}#toast-container>.toast-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important}#toast-container>.toast-success{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important}#toast-container>.toast-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000000;opacity:0.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-0.2em;top:-0.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}.dialog-header-error{background-color:#d2322d}.dialog-header-wait{background-color:#428bca}.dialog-header-notify{background-color:#eee}.dialog-header-confirm{background-color:#eee}.dialog-header-error span,.dialog-header-error h4,.dialog-header-wait span,.dialog-header-wait h4{color:#fff}.modal-content{overflow:hidden}.modal-content .modal-body{min-height:160px}[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important}html,body{-webkit-background-clip:padding-box;background-clip:padding-box;background-color:#e5e5e5;height:100%}body{margin:0;max-height:100%;max-width:100%;overflow:hidden;padding:0}a{cursor:pointer}#background{background:url("../img/bg-tiles.jpg");bottom:0;left:0;position:fixed;right:0;top:0;z-index:0}@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){#background{background-image:url("../img/bg-tiles_x2.jpg");-webkit-background-size:198px 200px;background-size:198px 200px}}.help-block{color:#737373}.dialog-header-notify,.dialog-header-confirm{background-color:#eee}.desktopnotify-icon{background-image:url("../img/logo-48x48.png")}:-webkit-full-screen{background:#000}:-moz-full-screen{background:#000}:-ms-fullscreen{background:#000}:fullscreen{background:#000}#loader{background:url("../img/logo.svg") no-repeat center;-webkit-background-size:contain;background-size:contain;bottom:15%;left:15%;margin:auto;max-height:150px;max-width:200px;opacity:1;pointer-events:none;position:fixed;right:15%;top:15%;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:20000}#loader.done{opacity:0}#loader>div{bottom:0;color:#ddd;display:block;font-size:2em;left:0;margin:0 auto;margin-bottom:-40px;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000}#loader .loader-message{font-size:.5em}.mainview{bottom:0;display:none;left:0;position:absolute;right:0;top:51px}@media (max-width: 700px){.mainview{left:0;left:0}}.videolayoutSmally .mainview{left:150px}.videolayoutClassroom .mainview{left:360px}.withChat .mainview,.withBuddylist .mainview{right:260px}.withBuddylist.withChat .mainview{right:520px}#page{bottom:0;left:0;position:absolute;right:0;top:51px}.welcome{color:#aaa;font-size:1.1em;margin-top:80px;max-width:600px;min-height:160px;padding-left:105px;padding-right:0;position:relative;text-shadow:0 0 5px #000}@media (max-width: 700px){.welcome{margin:0 auto;padding-left:10px;padding-right:20px}}.welcome h1{margin-top:0;white-space:nowrap}@media (max-width: 700px){.welcome h1{white-space:normal}}.welcome .welcome-container{margin:0 auto}.welcome .welcome-logo{background:url("../img/logo.svg") no-repeat left top;-webkit-background-size:contain;background-size:contain;bottom:0;left:0;position:absolute;top:1px;width:90px}@media (max-width: 700px){.welcome .welcome-logo{height:70px;margin-bottom:20px;margin-top:30px;position:relative;width:70px}}.welcome .welcome-input{position:relative}.welcome .welcome-input input{padding-right:105px}.welcome .welcome-input-buttons{position:absolute;right:8px;text-shadow:none;top:6px}.welcome .welcome-input-buttons a{color:#000;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.welcome .room-link{margin-top:-10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.welcome .room-link a{color:#aaa}.welcome .rooms-history{margin-top:3em}.welcome .rooms-history a{display:inline-block;margin-right:.5em}.welcome .rooms-history a:hover{text-decoration:none}.nicescroll::-webkit-scrollbar{background-color:#e5e5e5;border:solid transparent;height:8px;width:8px}.nicescroll::-webkit-scrollbar:hover{background-color:#e5e5e5;border-left:1px solid rgba(0,0,0,0.12);border-right:1px solid rgba(0,0,0,0.12)}.nicescroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,0.2)}.nicescroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.4)}.fadetogglecontainer>div{position:absolute;width:100%}.animate-show.ng-hide-add{display:block !important;opacity:1;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-add.ng-hide-add-active{opacity:0}.animate-show.ng-hide-remove{display:block !important;opacity:0;-webkit-transition:all linear .5s;transition:all linear .5s}.animate-show.ng-hide-remove.ng-hide-remove-active{opacity:1}.overlaybar{background:rgba(0,0,0,0.2);border-bottom:1px solid #222;border-top:1px solid #222;color:#e7e7e7;min-height:36px;padding:3px 8px 0 30px;position:absolute;text-shadow:0 0 5px #000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.overlaybar:hover{background:rgba(0,0,0,0.5)}.overlaybar.notvisible{background:transparent;border-bottom:1px solid transparent;border-top:1px solid transparent;pointer-events:none}.overlaybar.notvisible:hover{background:transparent}.overlaybar.notvisible .overlaybar-content{display:none}.overlaybar.notvisible .overlaybar-overlay{display:block}.overlaybar .btn{text-shadow:none}.overlaybar .btn-link{text-shadow:0 0 5px #000}.overlaybar .form-group>*{float:left;padding-top:0}.overlaybar input[type="radio"],.overlaybar input[type="checkbox"]{margin-top:2px}.overlaybar label{padding-top:6px !important}.overlaybar .overlaybar-button{color:#e7e7e7;display:block;font-size:20px;left:3px;opacity:.7;padding:4px 6px;pointer-events:auto;position:absolute;top:0;vertical-align:middle;z-index:15}.overlaybar .overlaybar-content{display:inline-block;margin-bottom:0;margin-left:.5em;max-width:60%}.overlaybar .overlaybar-content>*{padding-right:.5em}.overlaybar .overlaybar-content .input-group{max-width:160px}.overlaybar .overlaybar-overlay{display:none;margin-left:.5em;opacity:.7;padding-top:2px;text-align:left}.visible-with-contacts,.visible-with-contacts-inline{display:none}.with-contacts .visible-with-contacts{display:block}.with-contacts .visible-with-contacts-inline{display:inline-block}.with-contacts .hidden-with-contacts{display:none}.withBuddylist #rightslide{right:0}#rightslide{bottom:0;left:0;pointer-events:none;position:absolute;right:-260px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;z-index:5}#rightslide .rightslidepane{height:100%;position:relative;width:100%}.bar{background:#f8f8f8;color:#262626;font:bold 1em/50px "Helvetica Neue",Helvetica,Arial,sans-serif;text-align:center;touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:60}.bar .left{padding:5px 5px 5px 15px}@media (max-width: 700px){.bar .left{padding:2px 5px 0 11px;padding:2px 5px 0 11px}}.logo{background:url("../img/logo-small.png") no-repeat;-webkit-background-size:100%;background-size:100%;color:#000;display:inline-block;font:normal 11px/11px "Helvetica Neue",Helvetica,Arial,sans-serif;height:32px;text-align:left;vertical-align:middle;width:90px}@media (max-width: 700px){.logo{background:url("../img/logo.svg") no-repeat center;height:46px;width:46px}.logo .desc{display:none}}.logo .desc{font-style:italic;left:38px;position:relative;top:26px}.logo .desc a{color:#222}.bar .middle{left:0;pointer-events:none;position:absolute;right:60px;text-align:center;top:0}.bar .middle>span{background:#f8f8f8;display:inline-block;min-height:50px;pointer-events:auto}.bar .middle .userpicture{border-radius:2px;display:inline-block;height:46px;margin:-1px .5em 0;width:46px}@media (max-width: 700px){.bar .middle .userpicture{display:none}}@media (max-width: 700px){.bar .middle .status-connected,.bar .middle .status-conference,.bar .middle .status-connecting,.bar .middle .status-closed,.bar .middle .status-reconnecting,.bar .middle .status-error,.bar .middle .status-ringing{left:0;max-width:100%;position:absolute;right:0}}.bar .right{margin-top:-1px;padding-right:4px}.bar .right .badge{background-color:#84b819;border:1px solid #fff;font-size:.4em;position:absolute;right:0;top:2px}.bar .right .btn{background:#e9e9e9;border-color:#e2e2e2;color:#333;font:24px/40px "Helvetica Neue",Helvetica,Arial,sans-serif;height:42px;margin-left:-2px;padding:0;position:relative;text-align:center;width:42px}.bar .right .btn:focus{border:0;-webkit-box-shadow:0;box-shadow:0;outline:none}.bar .right .btn:hover{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active{background-color:transparent;border-color:#e7e7e7;color:#666}.bar .right .btn.active.amutebtn{background-color:#db4f39;border-color:#db4f39;color:#fff}.bar .right .btn.active.aenablebtn{background-color:#84b819;border-color:#84b819;color:#fff}.btn-mutemicrophone i:before{content:'\f130'}.btn-mutemicrophone.active i:before{content:'\f131'}.btn-mutecamera i:before{content:'\f06e'}.btn-mutecamera.active i:before{content:'\f070'}@-webkit-keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}@keyframes shakeityeah{0%{-webkit-transform:translate(2px, 1px) rotate(0deg);transform:translate(2px, 1px) rotate(0deg)}2%{-webkit-transform:translate(-1px, -2px) rotate(-1deg);transform:translate(-1px, -2px) rotate(-1deg)}4%{-webkit-transform:translate(-3px, 0) rotate(1deg);transform:translate(-3px, 0) rotate(1deg)}8%{-webkit-transform:translate(0, 2px) rotate(0deg);transform:translate(0, 2px) rotate(0deg)}10%{-webkit-transform:translate(1px, -1px) rotate(1deg);transform:translate(1px, -1px) rotate(1deg)}12%{-webkit-transform:translate(-1px, 2px) rotate(-1deg);transform:translate(-1px, 2px) rotate(-1deg)}14%{-webkit-transform:translate(-3px, 1px) rotate(0deg);transform:translate(-3px, 1px) rotate(0deg)}16%{-webkit-transform:translate(2px, 1px) rotate(-1deg);transform:translate(2px, 1px) rotate(-1deg)}18%{-webkit-transform:translate(-1px, -1px) rotate(1deg);transform:translate(-1px, -1px) rotate(1deg)}20%{-webkit-transform:translate(2px, 2px) rotate(0deg);transform:translate(2px, 2px) rotate(0deg)}22%{-webkit-transform:translate(1px, -2px) rotate(-1deg);transform:translate(1px, -2px) rotate(-1deg)}24%{-webkit-transform:translate(0, 0) rotate(0deg);transform:translate(0, 0) rotate(0deg)}}.btn-shakeityeah{-webkit-animation-duration:4s;animation-duration:4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shakeityeah;animation-name:shakeityeah;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}#buddylist{bottom:0;position:absolute;right:0;top:0;width:285px;z-index:50}#buddylist:before{background:#f8f8f8;border-bottom:1px solid #e7e7e7;border-bottom-left-radius:6px;border-left:1px solid #e7e7e7;border-top:1px solid #e7e7e7;border-top-left-radius:6px;bottom:0;color:rgba(0,0,0,0.3);content:'\f100';cursor:pointer;display:none;font-family:FontAwesome;font-size:1.8em;height:55px;left:0;line-height:55px;margin:auto;padding-right:4px;pointer-events:auto;position:absolute;text-align:center;top:0;width:26px;z-index:1}.withBuddylist #buddylist:before{content:'\f101';padding-right:0}.withBuddylistAutoHide #buddylist:before{display:block}.buddylist{background:#f8f8f8;border-left:1px solid #e7e7e7;bottom:0;left:25px;overflow-x:hidden;overflow-y:auto;pointer-events:auto;position:absolute;right:0;top:0}.buddylist.loading .buddylistloading{display:block}.buddylist.empty .buddylistempty{display:block}.buddylist .buddycontainer{pointer-events:auto;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.buddylist .buddylistempty{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;left:0;margin:auto;padding:.4em;position:absolute;right:0;text-align:center;top:0}.buddylist .buddylistloading{bottom:0;color:#b3b3b3;display:none;font-size:1.4em;height:2em;margin:auto;padding:.4em;position:absolute;right:0;text-align:center}.buddy{-webkit-tap-highlight-color:transparent;background:#fff;border-bottom:1px solid #e7e7e7;cursor:pointer;display:block;font-size:13px;min-height:66px;overflow:hidden;position:relative;text-align:left;width:100%}.buddy:hover{background:rgba(255,255,255,0.5)}.buddy.withSubline .buddy1,.buddy.contact .buddy1{top:15px}.buddy.withSubline .buddy2,.buddy.contact .buddy2{display:block}.buddy.hovered .buddyactions{right:0}.buddy.hovered .buddysessions{max-height:999px}.buddy .fa.contact:before{content:'\f006'}.buddy.contact .fa.contact:before{content:'\f005'}.buddy.isself .fa.contact:before{content:'\f192'}.buddy .buddyPicture{background:#84b819;border-radius:2px;float:left;height:46px;margin:10px;overflow:hidden;position:relative;text-align:center;width:46px}.buddy .buddyPicture .fa{color:#009534;font-size:3em;line-height:46px}.buddy .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.buddy .buddyPictureSmall{height:30px;margin:0;margin-left:0;margin-right:0;width:30px}.buddy .buddyPictureSmall .fa{font-size:2em;line-height:30px}.buddy .buddy1{color:#262626;font-size:14px;font-weight:bold;height:28px;left:65px;overflow:hidden;position:absolute;right:4px;text-overflow:ellipsis;top:24px;white-space:nowrap}.buddy .buddy2{color:rgba(0,0,0,0.5);display:none;left:65px;overflow:hidden;position:absolute;right:0;top:33px;white-space:nowrap}.buddy .buddy3{display:inline-block;overflow:hidden;padding:0 6px;text-align:left;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;width:120px}.buddy .buddyactions{background:rgba(255,255,255,0.5);height:66px;line-height:66px;padding:0 10px;position:absolute;right:-125px;text-align:right;top:0;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:right;transition-property:right;white-space:nowrap;z-index:5}.buddy .buddyactions .btn{font-size:1.6em;height:40px;line-height:40px;padding:0;text-align:center;vertical-align:middle;width:42px}.buddy .buddysessions{margin-bottom:10px;margin-top:56px;max-height:0;-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:max-height;transition-property:max-height}.buddy .buddysessions ul{border-left:1px dotted #e7e7e7;border-right:1px dotted #e7e7e7;margin:0 14px;padding-left:0;padding-top:10px}.buddy .buddysessions ul li{list-style-type:none;margin-bottom:2px;margin-left:0}.buddy .buddysessions ul li .btn-group{visibility:hidden}.buddy .buddysessions ul li:hover .btn-group{visibility:visible}.buddy .buddysessions .currentsession .buddy3{font-weight:bold}.buddyPictureCapture .picture{display:block;margin-bottom:5px}.buddyPictureCapture .videoPicture{margin-bottom:4px}.buddyPictureCapture .videoPicture .videoPictureVideo{background-color:#000;overflow:hidden;position:relative}.buddyPictureCapture .videoPicture video{object-fit:cover}.buddyPictureCapture .videoPictureVideo{height:200px;width:200px}.buddyPictureCapture .videoPictureVideo .videoPrev,.buddyPictureCapture .videoPictureVideo video,.buddyPictureCapture .videoPictureVideo .preview{height:100%;width:100%}.buddyPictureCapture .videoFlash{background-color:#fff;border:1px dotted #e7e7e7;bottom:0;left:0;position:absolute;right:0;top:0;visibility:hidden;z-index:5}.buddyPictureCapture .videoFlash.flash{visibility:visible}.buddyPictureCapture .preview{left:0;position:absolute;top:0}.buddyPictureCapture .preview.previewPicture{position:relative}.buddyPictureCapture .btn-takePicture,.buddyPictureCapture .btn-retakePicture{left:0;margin:0 auto;max-width:40%;position:absolute;right:0;top:50%}.buddyPictureCapture .btn-retakePicture{visibility:hidden}.buddyPictureCapture .videoPictureVideo:hover .btn-retakePicture{visibility:visible}.buddyPictureCapture .countdownPicture{color:#f8f8f8;font-size:45px;left:0;margin:0 auto;opacity:.8;position:absolute;right:0;text-align:center;text-shadow:0 0 5px #000;top:75px}.buddyPictureUpload{position:relative}.buddyPictureUpload .loader{left:90px;position:absolute;z-index:1}.buddyPictureUpload .loader .fa-spin{color:#737373}.buddyPictureUpload>p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.buddyPictureUpload .showUploadPicture{background-color:#f8f8f8;border:1px solid #e7e7e7;height:200px;line-height:200px;margin-bottom:10px;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:200px}.buddyPictureUpload .showUploadPicture.imgData{background-color:#000}.buddyPictureUpload .showUploadPicture.imgData .chooseUploadPicture{display:none}.buddyPictureUpload .showUploadPicture.imgData:hover .imageUtilites{visibility:visible}.buddyPictureUpload .showUploadPicture .chooseUploadPicture{color:#737373;left:0;margin:0 auto;position:absolute;right:0;z-index:1}.buddyPictureUpload .showUploadPicture .fa{color:#f8f8f8;opacity:.8;text-shadow:0 0 5px #000}.buddyPictureUpload .preview{left:0;position:relative;top:0}.buddyPictureUpload .imageUtilites{line-height:30px;position:absolute;visibility:hidden;width:200px;z-index:1}.buddyPictureUpload .imageUtilites .fa{cursor:pointer;font-size:40px;height:50px;width:50px}.buddyPictureUpload .moveHorizontal{position:relative;top:-4px}.buddyPictureUpload .moveVertical{left:158px;position:absolute}.buddyPictureUpload .resize{position:relative;top:108px}#settings{background:#fff;border-left:1px solid #e7e7e7;bottom:0;padding-right:20px;position:fixed;right:-520px;top:51px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;width:520px;z-index:50}#settings.show{right:0}@media only screen and (max-width: 630px){#settings.show{background:#fff;left:0;width:auto}}@media only screen and (max-width: 630px){#settings.show .form-actions{bottom:0;height:60px;left:0;margin-bottom:0;padding:6px 0 6px 120px;position:fixed;right:0}}.settings{background:#fff;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;padding:10px;position:absolute;right:0;top:0}@media only screen and (max-width: 630px){.settings{padding-bottom:10px}}.settings .version{color:#ccc;font-size:10px;position:absolute;right:10px;top:10px}@media only screen and (max-width: 630px){.settings .form-horizontal .controls{margin-left:110px}}@media only screen and (max-width: 630px){.settings .form-horizontal .control-label{width:100px;word-wrap:break-word}}settings-advanced{display:block;padding-top:15px}#chat{bottom:0;min-width:260px;opacity:0;pointer-events:none;position:absolute;right:260px;top:0;width:260px;z-index:45}.withChat #chat{opacity:1}.withChat.withChatMaximized #chat{left:0;width:auto}.withChat .chat{pointer-events:auto}.chatcontainer{background:#f8f8f8;bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.showchatlist .chatpane{right:100%}.showchatlist .chatlist{left:0}.chatlist{background:#f8f8f8;bottom:0;left:100%;position:absolute;top:0;width:100%}.chatlist .list-group{margin-bottom:-1px;margin-top:-1px;max-height:100%;overflow-x:hidden;overflow-y:auto}.chatlist .list-group-item{border-left:0;border-radius:0;border-right:0;line-height:26px;min-height:51px;padding-right:70px;position:relative}.chatlist .list-group-item.newmessage{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chatlist .list-group-item.disabled{color:#aaa}.chatlist .list-group-item:hover button{display:inline}.chatlist .list-group-item .fa-lg{display:inline-block;text-align:center;width:18px}.chatlist .list-group-item .badge{background:#84b819;border:1px solid #fff;position:absolute;right:50px;top:14px}.chatlist .list-group-item button{display:none;position:absolute;right:10px}.chatpane{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:0;position:absolute;right:0;top:0;width:100%}.chat{background:#f8f8f8;bottom:0;display:none;left:0;overflow:hidden;position:absolute;right:0;top:0}.chat.newmessage .chatheadertitle:after{content:'***';position:absolute;right:32px;top:2px}.chat.newmessage .chatheader{-webkit-animation:newmessage 1s ease -.3s infinite;animation:newmessage 1s ease -.3s infinite}.chat.active.visible{display:block}.chat.with_pictures .message.is_self{padding-right:54px}.chat.with_pictures .message.is_self .timestamp{right:58px}.chat.with_pictures .message.is_remote{padding-left:58px}.chat .chatbodybottom{background:#f8f8f8;bottom:1px;left:0;margin:0 auto;position:absolute;right:0}@media (max-height: 210px){.chat .chatbodybottom{height:auto}}.chat .typinghint{color:#aaa;font-size:.8em;height:14px;overflow:hidden;padding:0 6px;white-space:nowrap}@media (max-height: 210px){.chat .typinghint{display:none}}.chat .inputbox{position:relative}@media (max-height: 210px){.chat .inputbox{height:auto}}.chat .inputbox .btn{display:none;padding:.5em 1em;position:absolute;right:6px;top:1px}.chat .inputbox>div{border-top:1px solid #e7e7e7}.chat .input{border-color:transparent;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;height:54px;margin:0;max-height:54px;resize:none;width:100%}@media (max-height: 210px){.chat .input{max-height:2.5em}}.chat .input:active,.chat .input:focus{border-color:#66afe9}.chat .outputbox{bottom:75px;left:0;position:absolute;right:0;top:0}@media (max-height: 210px){.chat .outputbox{bottom:45px}}.chat .output{height:100%;overflow-x:hidden;overflow-y:auto;padding:.4em 0}.chat .output>i{clear:both;color:#aaa;display:block;font-size:.8em;padding:6px 0;text-align:center}.chat .output>i.p2p{font-weight:bold;padding:6px 0}.chat .message{background:#fff;border:1px solid transparent;border-radius:6px;-webkit-box-shadow:0 0 2px 0 rgba(0,0,0,0.03);box-shadow:0 0 2px 0 rgba(0,0,0,0.03);clear:both;display:block;margin:0 4px 2px 18px;padding:8px;position:relative;word-wrap:break-word}.chat .message ul{list-style-type:none;margin:0;padding-left:0}.chat .message .timestamp{color:#aaa;font-size:.8em;position:absolute;right:8px;text-align:right;top:8px}.chat .message .timestamp-space{float:right;height:10px;width:40px}.chat .message strong{display:block;margin-right:40px;overflow:hidden;padding-bottom:2px;text-overflow:ellipsis;white-space:nowrap}.chat .message li{line-height:1.1em;margin:4px 0;padding-left:1.2em;position:relative}.chat .message li:before{color:#ccc;content:'\f075';font-family:FontAwesome;left:0;position:absolute;text-align:center;width:12px}.chat .message li.unread:before{color:#fe9a2e;content:""}.chat .message li.sending:before{color:#ccc;content:""}.chat .message li.sent:before{color:#5882fa;content:""}.chat .message li.delivered:before{color:#5882fa;content:""}.chat .message li.received:before{color:#84b819;content:""}.chat .message li.read:before{color:#ccc;content:""}.chat .message .buddyPicture{background:#84b819;border-radius:2px;height:46px;left:4px;overflow:hidden;position:absolute;text-align:center;top:4px;width:46px;z-index:0}.chat .message .buddyPicture .fa{color:#009534;line-height:46px}.chat .message .buddyPicture img{bottom:0;display:block;left:0;max-height:100%;max-width:100%;position:absolute;right:0;top:0}.chat .message:before,.chat .message:after{border-style:solid;content:'';display:block;position:absolute;width:0}.chat .message.is_remote{background:#fff}.chat .message.is_remote:before{border-color:transparent #eee;border-width:7px 11px 7px 0;bottom:auto;left:-12px;top:4px}.chat .message.is_remote:after{border-color:transparent #fff;border-width:6px 10px 6px 0;bottom:auto;left:-11px;top:5px}.chat .message.is_self{background:#fff;margin-left:4px;margin-right:18px;padding-right:0}.chat .message.is_self:before{border-color:transparent #eee;border-width:7px 0 7px 11px;bottom:4px;bottom:auto;right:-12px}.chat .message.is_self:after{border-color:transparent #fff;border-width:6px 0 6px 10px;bottom:5px;bottom:auto;right:-11px}.chat .message.is_self li:before{color:#ccc;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.chat .message.is_self .buddyPicture{left:auto;right:4px}.chat .message.with_hoverimage .buddyPicture{overflow:visible;z-index:initial}.chat .message.with_hoverimage .buddyPicture:hover .buddyInfoActions{height:40px;opacity:1}.chat .message.with_hoverimage .buddyInfoActions{cursor:default;display:inline-block;height:0;left:0;opacity:0;overflow:hidden;position:absolute;top:48px;-webkit-transition:opacity 0.1s .1s linear, height .4s .1s ease-out;transition:opacity 0.1s .1s linear, height .4s .1s ease-out;white-space:nowrap;z-index:1}.chat .message.with_hoverimage .buddyInfoActions .btn-group{display:block;margin:0 auto;width:55px}.chat .message.with_hoverimage .buddyInfoActions .btn-primary{padding:2px 5px}.chat .message.with_hoverimage .buddyInfoActions .fa{color:#fff;line-height:24px}.chatmenu{height:36px;left:0;padding:2px 4px;position:absolute;right:0;top:36px}@media (max-height: 210px){.chatmenu{display:none}}.chatbody{border-left:1px solid #e7e7e7;bottom:-1px;left:0;position:absolute;right:0;top:74px}@media (max-height: 210px){.chatbody{border-top:1px solid #e7e7e7;top:0;top:0}}.chatheader{background:rgba(255,255,255,0.9);border-bottom:1px solid #e7e7e7;border-left:1px solid #e7e7e7;height:36px;left:0;line-height:34px;padding:0 4px 0 8px;position:absolute;right:0;top:0}@media (max-height: 210px){.chatheader{display:none}}.chatheader .chatstatusicon{cursor:pointer;display:block;font-size:1.4em;height:36px;left:0;position:absolute;text-align:center;top:0;width:36px}.chatheader .chatheadertitle{display:inline;padding-left:28px}.chatheader .ctrl{color:rgba(0,0,0,0.3);position:absolute;right:1px;top:0}.chatheader .ctrl .fa{cursor:pointer;padding:6px}.chatheader span{display:inline-block;max-width:60%;overflow:hidden;pointer-events:none;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}@-webkit-keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}@keyframes newmessage{0%{background-color:#84b819}50%{background-color:#f8f8f8}100%{background-color:#84b819}}.withChat #help,.withBuddylist #help{right:260px}.withChat.withBuddylist #help,.withSettings #help{right:520px}#help{bottom:10px;color:#aaa;font-size:1.1em;left:0;margin:0 auto;position:absolute;right:0;text-shadow:0 0 5px #000;top:80px;-webkit-transition:right 200ms ease-in-out;transition:right 200ms ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:350px}@media only screen and (max-width: 400px){.help{display:none}}@media only screen and (min-width: 400px) and (max-width: 1020px){.help{font-size:1em;width:250px}}.help>div{margin:0 10px}.help .help-subline{color:#888;padding:20px 0}.help .btn{text-shadow:none}#audiolevel{left:0;margin:0 auto;position:fixed;right:0;top:43px;width:400px;z-index:60}#audiolevel .audio-level{background:#84b819;background:gradient(linear, left top, left bottom, color-stop(0%, #84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), color-stop(100%, #7cbc0a));background:-webkit-gradient(linear, left top, left bottom, from(#84b819), color-stop(50%, #a1d54f), color-stop(51%, #80c217), to(#7cbc0a));background:-webkit-linear-gradient(top, #84b819 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%);background:linear-gradient(to bottom, #84b819 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);border-radius:0 0 2px 2px;height:4px;left:0;margin:0 auto;position:absolute;right:0;-webkit-transition:width .05s ease-in-out;transition:width .05s ease-in-out;width:0}.file-info{background:#fff;border:1px solid #ddd;border-radius:4px;max-width:170px;padding:1em;position:relative;text-align:center}.file-info.downloader .anim{margin-left:-40px}.file-info.downloader .file-info-size{margin-bottom:10px}.file-info.downloading .file-info-size{border-color:#ddd}.file-info>div{position:relative;z-index:3}.file-info .file-info-bg{bottom:0;color:#eee;font-size:20em;left:41px;overflow:hidden;position:absolute;right:0;top:-82px;z-index:2}.file-info .actions{left:50%;margin-left:10px;position:absolute;text-align:left;top:14px}.file-info .uploader .file-info-speed{bottom:6px}.file-info .uploader .actions{margin-left:30px;opacity:0}.file-info .uploader .anim{margin-left:0}.file-info .uploader .hovercontrol:hover .anim{margin-left:-50px}.file-info .uploader .hovercontrol:hover .actions{margin-left:0;opacity:1}.file-info .uploader .hovercontrol>div{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.is_remote .file-info{background:#fff;border:1px solid #ddd}.is_remote .file-info .file-info-bg{color:#eee;font-size:20em}.file-info-name{font-size:1.1em;margin:.2em 0;min-width:140px;padding:0 .2em}.file-info-size{font-size:.8em;height:20px;position:relative}.file-info-size>span{display:block;left:0;margin:0 auto;padding:3px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0;z-index:5}.file-info-size>div{bottom:0;-webkit-box-shadow:none !important;box-shadow:none !important;left:0;position:absolute;top:0;width:0;z-index:0}.file-info-size>div.progress-bar{opacity:.5}.file-info-size>div.progress-bar.download{opacity:1;z-index:1}.file-info-speed{bottom:8px;font-size:.8em;left:0;position:absolute;right:0;text-align:center}@media only screen and (max-width: 630px){.mainScreenshare #audiovideo,.mainPresentation #audiovideo{display:none}}.withChat #audiovideo,.withBuddylist #audiovideo{right:260px}.withBuddylist.withChat #audiovideo{right:520px}#audiovideo{bottom:0;left:0;position:absolute;right:0;top:51px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}@media only screen and (max-width: 590px){#audiovideo{right:0}}#audiovideo.fullscreen{bottom:0 !important;left:0 !important;right:0 !important;top:0 !important}#audiovideo.fullscreen .remoteVideo .peerActions{display:none}.audiovideo{bottom:0;left:0;position:absolute;right:0;top:0}.audiovideo.active{-webkit-perspective:1000;perspective:1000}.audiovideo.active:hover .overlayActions{opacity:.3}.audiovideo.active .overlayActions:hover{opacity:.6}.audiovideo.active .audiovideoBase{-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg)}.audiovideo .audiovideoBase{height:100%;position:relative;-webkit-transform:rotateY(0deg);-ms-transform:rotateY(0deg);transform:rotateY(0deg);-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:-webkit-transform;transition-property:transform;width:100%;z-index:2}.audiovideo .localContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);z-index:2;overflow:hidden}.audiovideo video{object-fit:cover}.audiovideo .remoteContainer{bottom:0;left:0;pointer-events:none;position:absolute;right:0;top:0;-webkit-transform:rotateY(180deg);-ms-transform:rotateY(180deg);transform:rotateY(180deg);z-index:2}.audiovideo .miniContainer{background:#000;bottom:2px;height:100%;max-height:18%;opacity:0;position:absolute;right:2px;-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:opacity;transition-property:opacity;z-index:25;overflow:hidden}.audiovideo .miniContainer.visible{opacity:1}.audiovideo .miniVideo{display:block;height:100%;max-height:100%;max-width:100%;width:100%}.audiovideo .localVideo{background:rgba(0,0,0,0.4);display:block;max-height:100%;opacity:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity;width:100%}.audiovideo .remoteVideos{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.audiovideo .remoteVideos video{display:block;height:100%;width:100%}.audiovideo .overlayActions{background:rgba(0,0,0,0.9);bottom:0;height:140px;left:0;margin:auto 0;opacity:0;padding:3px 0;position:absolute;top:0;width:40px;z-index:5}.audiovideo .overlayActions .btn{color:#ccc;cursor:pointer;display:block;outline:0;text-shadow:0 0 5px #000;width:40px}.audiovideo .remoteVideo{background:rgba(0,0,0,0.4);display:inline-block;max-height:100%;max-width:100%;overflow:hidden;position:relative;vertical-align:bottom;width:100%}.audiovideo .remoteVideo.onlyaudio{background:#666}.audiovideo .remoteVideo.onlyaudio .onlyaudio{display:block}.audiovideo .remoteVideo .onlyaudio{color:rgba(255,255,255,0.3);display:none;font-size:80px;left:0;margin-top:-40px;pointer-events:auto;position:absolute;right:0;text-align:center;top:45%}.audiovideo .remoteVideo.onlyaudio video,.audiovideo .remoteVideo.dummy video{visibility:hidden}.audiovideo .remoteVideo.dummy .onlyaudio{display:block}.audiovideo .remoteVideo .peerActions{bottom:5%;left:40px;opacity:0;pointer-events:auto;position:absolute;right:40px;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}.audiovideo .remoteVideo .peerActions:hover{opacity:.5}.audiovideo .remoteVideo .peerActions i{font-size:3vw}.audiovideo .remoteVideo .peerLabel{bottom:4%;color:#fff;font-size:2.5vw;left:4%;max-width:30%;opacity:.7;overflow:hidden;padding:4px;position:absolute;text-overflow:ellipsis;text-shadow:0 0 4px #000;white-space:nowrap;z-index:8}.remoteVideo.talking .peerLabel{color:#84b819}.remoteVideo .peerLabel{-webkit-transition:color 500ms ease-out;transition:color 500ms ease-out}.remoteVideo .overlayLogo{background:url("../img/logo-overlay.png") no-repeat center;-webkit-background-size:100%;background-size:100%;height:20%;max-height:40px;max-width:111px;opacity:.5;pointer-events:none;position:absolute;right:2.5%;top:4%;width:20%;z-index:2}.miniContainer.talking:after{bottom:2px;-webkit-box-shadow:0 0 20px #84b819 inset;box-shadow:0 0 20px #84b819 inset;content:'';left:2px;position:absolute;right:2px;top:2px}.renderer-smally{background:#000;border-right:0;border-top:0;width:150px}.renderer-smally .remoteVideos{padding-bottom:85px}.renderer-smally .remoteVideo .peerLabel{font-size:.9em;font-weight:bold}.renderer-smally .remoteVideo .peerActions i{font-size:1em}.renderer-smally .miniContainer{bottom:0;height:85px;left:0;max-height:none;right:0}.renderer-democrazy .remoteVideos .miniContainer{bottom:auto;display:inline-block;max-height:100%;max-width:100%;position:relative;right:auto;vertical-align:bottom}.renderer-democrazy .active .miniContainer{opacity:1}.renderer-conferencekiosk .remoteVideos{background:rgba(0,0,0,0.4);bottom:2px;min-height:108px;pointer-events:auto;text-align:center;top:auto;white-space:nowrap}.renderer-conferencekiosk .remoteVideos>div{cursor:pointer;height:108px;width:192px}.renderer-conferencekiosk .remoteVideos .overlayLogo{display:none}.renderer-conferencekiosk .remoteVideos .peerLabel,.renderer-conferencekiosk .remoteVideos .peerActions i{font-size:1.1em}.renderer-conferencekiosk .remoteVideos .peerLabel{background:rgba(0,0,0,0.9)}.renderer-conferencekiosk .miniContainer{height:108px;max-height:none;width:192px}.renderer-conferencekiosk .bigVideo{bottom:112px;left:0;margin:auto;opacity:0;position:absolute;right:0;top:2px;-webkit-transition-duration:2s;transition-duration:2s;-webkit-transition-property:opacity;transition-property:opacity}.renderer-conferencekiosk .bigVideo video{height:100%;width:100%}.renderer-auditorium{position:relative}.renderer-auditorium span:before{content:'\f183';left:50%;margin-left:-.8em;margin-top:-.5em;position:absolute;top:50%}.renderer-auditorium span:after{content:'\f183';margin-right:-.9em;margin-top:-.5em;position:absolute;right:50%;top:50%}.renderer-auditorium .remoteContainer{border-left:40px solid #000}.renderer-auditorium .remoteVideos{background:rgba(0,0,0,0.4);pointer-events:auto;top:180px;width:320px}.renderer-auditorium .remoteVideos video{height:100%;margin-top:-9px;object-fit:cover;width:100%}.renderer-auditorium .remoteVideos>div{cursor:pointer;display:inline-block;height:60px;width:80px}.renderer-auditorium .remoteVideos .overlayLogo{display:none}.renderer-auditorium .remoteVideos .peerLabel{background:rgba(0,0,0,0.9);bottom:0;font-size:.6em;left:0;line-height:9px;max-width:100%;padding:0 4px;right:0}.renderer-auditorium .remoteVideos .peerActions{display:none}.renderer-auditorium .remoteVideos .miniContainer{max-height:auto;right:auto}.renderer-auditorium .bigVideo{height:180px;width:320px}.renderer-auditorium .bigVideo video{height:100%;width:100%}.renderer-auditorium .bigVideo .peerLabel{bottom:8%;font-size:1vw;max-width:40%}.mainScreenshare #screenshare{display:block}.screenshare{bottom:0;left:0;position:absolute;right:0;top:0}.screenshare .overlaybar{bottom:0;left:0;right:0}.screensharepane{background:#000;bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.screensharepane .remotescreen{position:relative}.screensharepane video{max-height:99%;width:100%}.remotesize .screensharepane video{max-height:none;width:auto}#roombar{left:0;min-width:260px;position:absolute;right:0;top:51px;z-index:4}#roombar .roombar{left:0;position:absolute;right:0;top:0}.fa.link{color:#aaa}.fa.email{color:#aaa}.fa.facebook{color:#45619d}.fa.google{color:#dd4b39}.fa.twitter{color:#00aced}.fa.xing{color:#fff}.contactsmanager .desc{font-size:20px;font-weight:normal;text-align:baseline}.contactsmanager .addbtn{font-size:14px}.contactsmanager .addbtn .fa-users{font-size:22px}.contactsmanager .addbtn .fa-plus{font-size:15px}.contactsmanager .editpicture{float:left;margin-right:20px;vertical-align:middle}.contactsmanager .uploadbtn{margin-top:7px}.contactsmanager .editlist{max-height:250px;overflow-y:auto}.contactsmanager .picture{border-bottom:0;cursor:auto;display:table-cell;min-height:46px;position:static;width:auto}.contactsmanager .picture .buddyPicture{margin:0 0 0 10px}.contactsmanager .table{margin-bottom:0}.contactsmanager tr:first-child td{border-top:0}.contactsmanager .name{text-align:left;vertical-align:middle;width:40%}.contactsmanager .action{padding-right:15px;text-align:right;vertical-align:middle}.contactsmanageredit .buddy .buddyPicture{margin:0}.search:before{content:'\f002';font-family:'fontAwesome';font-size:14px;left:22px;opacity:.4;position:absolute;top:6px}.search ~ input{padding-left:25px}.mainPresentation #presentation{display:block}.presentation{bottom:0;left:0;position:absolute;right:0;top:0}.presentation .overlaybar{bottom:0;left:0;right:0;text-align:center}.presentation .overlaybar .overlaybar-content{max-width:100%}.presentation .overlaybar .overlaybar-content .pagecontrol{height:30px}.presentation .overlaybar .btn-prev{left:40px}.presentation .overlaybar .btn-next{left:auto;right:0}.presentation .overlaybar .overlaybar-button{font-size:20px;line-height:28px;padding:4px 6px;position:absolute;top:0}.presentation .thumbnail{color:#333;display:inline-block;height:122px;margin-left:20px;margin-top:20px;position:relative;text-shadow:none;vertical-align:middle;width:160px}.presentation .thumbnail:first-child{margin-left:0}.presentation .thumbnail.presentable{cursor:pointer}.presentation .thumbnail:hover .presentation-action{display:block}.presentation .thumbnail:hover .notavailable{display:block}.presentation .thumbnail .caption{overflow:hidden;padding-bottom:0;text-overflow:ellipsis}.presentation .thumbnail .caption .size{font-size:10px}.presentation .thumbnail .caption .progress{position:relative}.presentation .thumbnail .caption .download-info{bottom:0;color:#333;left:0;line-height:20px;position:absolute;right:0;text-shadow:1px 1px 1px #fff;top:0}.presentation .thumbnail .active{bottom:0;color:#84b819;font-size:10em;left:0;opacity:.7;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .notavailable{bottom:0;color:#d2322d;display:none;font-size:10em;left:0;opacity:.25;position:absolute;right:0;text-align:center;top:0}.presentation .thumbnail .presentation-action{display:none;position:absolute;top:1px}.presentation .thumbnail .download{left:1px}.presentation .thumbnail .delete{right:1px}.presentation .thumbnail .filetype{font-size:5em}.presentationpane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}.presentationpane .welcome{padding:0}.presentationpane .welcome h1{white-space:normal}.presentationpane .welcome .btn{margin-top:30px}.presentationpane .welcome .progress span{text-shadow:none}.presentationpane .welcome .progress .download-info{color:#333;left:0;position:absolute;text-shadow:1px 1px 1px #fff;width:100%}.presentationpane .canvasContainer{height:100%;width:100%}.presentationpane canvas{display:block;margin:0 auto;position:relative}.presentationpane .odfcanvas{cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.presentationpane .odfcanvas body{background-color:transparent}.presentationpane .odfcanvas document{display:block}.presentationpane .odfcontainer{display:none;margin:0;padding:0}.presentationpane .odfcontainer.showonepage{overflow:hidden;text-align:center}.pageinfo input{display:inline;width:70px}.presentations{height:156px;margin-left:-25px;margin-right:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.mainYoutubevideo #youtubevideo{display:block}.youtubevideo{bottom:0;left:0;position:absolute;right:0;top:0}.youtubevideo .click-container{bottom:0;left:0;position:absolute;right:0;top:0;z-index:5}.youtubevideo .welcome{max-width:700px}.youtubevideo .welcome h1{margin-top:10px}.youtubevideo .welcome .welcome-container{max-width:700px}.youtubevideo .welcome .welcome-logo{background:transparent;font-size:10em}.youtubevideo .overlaybar{bottom:0;left:0;right:0}.youtubevideo .overlaybar-content{max-width:100%;width:100%}.youtubevideo .overlaybar-content form .overlaybar-buttons{position:absolute;right:23px;top:6px}.youtubevideo .overlaybar-input{padding-right:15px;position:relative;width:100%}.youtubevideopane{bottom:0;left:0;overflow:auto;position:absolute;right:0;top:0}#youtubecontainer{position:relative}#youtubeplayerinfo{bottom:10%;left:0;opacity:0;pointer-events:auto;position:absolute;right:0;text-align:center;-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:opacity;transition-property:opacity;z-index:10}#youtubeplayerinfo:hover{opacity:.8}#youtubeplayerinfo div{background-color:#f9f2f4;border-radius:10px;display:inline-block;font-size:2em;padding:20px 40px}.volumecontrol{background:rgba(0,0,0,0.6);bottom:0;left:0;opacity:0;padding:4px;pointer-events:auto;position:absolute;right:0;z-index:10}.volumecontrol:hover{opacity:1}.volume-button{display:inline;min-width:38px}.volumebar{display:inline-block;padding:6px 8px;vertical-align:middle}.volumebar .bar{-webkit-appearance:none;background-color:#aaa;border:1px solid #aaa;height:3px;outline:0;width:100px}.volumebar .bar::-webkit-slider-thumb{-webkit-appearance:none;background-color:#fff;height:20px;width:6px}.volumebar .bar::-moz-range-track{background:#aaa;border:0}.volumebar .bar::-moz-range-thumb{background-color:#fff;border-radius:0;height:20px;width:6px}.volumebar .bar::-moz-focusring{outline:1px solid #aaa;outline-offset:-1px}.modal{overflow-y:auto}#toast-container>.toast{background-image:none !important}#toast-container>.toast:before{color:#fff;float:left;font-family:FontAwesome;font-size:20px;line-height:20px;margin:auto .5em auto -1.5em;padding-right:.5em;position:fixed}#toast-container>.toast-warning:before{content:'\f05a'}#toast-container>.toast-error:before{content:'\f05a'}#toast-container>.toast-info:before{content:'\f05a'}#toast-container>.toast-success:before{content:'\f05a'}#toast-container>:hover,#toast-container>div{-webkit-box-shadow:none !important;box-shadow:none !important}.toast-info{background-color:#5bc0de}.toast-close-button{font-size:1em;top:-.6em}#toast-container>div{filter:alpha(opacity=100);opacity:1} From 84abb28cbe509704f5b81e12459fb2d8045e72d5 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 14 Apr 2015 14:13:28 +0200 Subject: [PATCH 029/121] Rebuilt translations and completed German translation. --- src/i18n/messages-de.po | 43 +++++++++++++++++++++--- src/i18n/messages-ja.po | 38 ++++++++++++++++++--- src/i18n/messages-ko.po | 38 ++++++++++++++++++--- src/i18n/messages-zh-cn.po | 38 ++++++++++++++++++--- src/i18n/messages-zh-tw.po | 38 ++++++++++++++++++--- src/i18n/messages.pot | 34 ++++++++++++++++--- static/partials/screensharedialogff.html | 6 ++-- static/translation/messages-de.json | 2 +- static/translation/messages-ja.json | 2 +- static/translation/messages-ko.json | 2 +- static/translation/messages-zh-cn.json | 2 +- static/translation/messages-zh-tw.json | 2 +- 12 files changed, 208 insertions(+), 37 deletions(-) diff --git a/src/i18n/messages-de.po b/src/i18n/messages-de.po index 6fb3fd27..a45e518b 100644 --- a/src/i18n/messages-de.po +++ b/src/i18n/messages-de.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" -"PO-Revision-Date: 2015-02-18 14:49+0100\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" +"PO-Revision-Date: 2015-04-14 13:59+0100\n" "Last-Translator: Simon Eisenmann \n" "Language-Team: struktur AG \n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" @@ -246,6 +246,42 @@ msgstr "Optionen für Bildschirmfreigabe" msgid "Fit screen." msgstr "Bildschirm einpassen." +msgid "Share screen" +msgstr "Bildschirm teilen" + +msgid "Please select what to share." +msgstr "Bitte wählen Sie aus, was geteilt werden soll." + +msgid "Screen" +msgstr "Bildschirm" + +msgid "Window" +msgstr "Fenster" + +msgid "Application" +msgstr "Anwendung" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" +"Gesamten Bildschirm teilen. Klicken Sie auf Teilen um den Bildschirm " +"auszuwählen." + +msgid "Share a single window. Click share to select the window." +msgstr "" +"Einzelnes Fenster teilen. Klicken Sie auf Teilen um das Fenster " +"auszuwählen." + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" +"Alle Fenster einer Anwendung teilen. Es wird u.U. Inhalt hinter Fenstern " +"der Anwendung geteilt, wenn diese verschoben werden. Klicken Sie auf " +"Teilen um die Anwendung auszuwählen." + +msgid "Share" +msgstr "Teilen" + msgid "Profile" msgstr "Profil" @@ -519,9 +555,6 @@ msgstr "Das Video wird bei allen Gesprächsteilnehmern angezeigt." msgid "YouTube URL" msgstr "YouTube URL" -msgid "Share" -msgstr "Teilen" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/src/i18n/messages-ja.po b/src/i18n/messages-ja.po index 775942bb..f22003f5 100644 --- a/src/i18n/messages-ja.po +++ b/src/i18n/messages-ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" "PO-Revision-Date: 2014-04-23 22:25+0100\n" "Last-Translator: Curt Frisemo \n" "Language-Team: Curt Frisemo \n" @@ -246,6 +246,38 @@ msgstr "画面共有オプション" msgid "Fit screen." msgstr "画面に合わせる" +#, fuzzy +msgid "Share screen" +msgstr "画面を共有する." + +msgid "Please select what to share." +msgstr "" + +#, fuzzy +msgid "Screen" +msgstr "画面に合わせる" + +msgid "Window" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" + +msgid "Share a single window. Click share to select the window." +msgstr "" + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" + +#, fuzzy +msgid "Share" +msgstr "共有取り消し" + msgid "Profile" msgstr "" @@ -510,10 +542,6 @@ msgstr "" msgid "YouTube URL" msgstr "" -#, fuzzy -msgid "Share" -msgstr "共有取り消し" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/src/i18n/messages-ko.po b/src/i18n/messages-ko.po index 86758626..3d7a941d 100644 --- a/src/i18n/messages-ko.po +++ b/src/i18n/messages-ko.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" "PO-Revision-Date: 2014-04-13 20:30+0900\n" "Last-Translator: Curt Frisemo \n" "Language-Team: Curt Frisemo \n" @@ -246,6 +246,38 @@ msgstr "화면 공유 옵션" msgid "Fit screen." msgstr "화면에 맟춤" +#, fuzzy +msgid "Share screen" +msgstr "화면 공유하기" + +msgid "Please select what to share." +msgstr "" + +#, fuzzy +msgid "Screen" +msgstr "화면에 맟춤" + +msgid "Window" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" + +msgid "Share a single window. Click share to select the window." +msgstr "" + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" + +#, fuzzy +msgid "Share" +msgstr "비공유" + msgid "Profile" msgstr "" @@ -510,10 +542,6 @@ msgstr "" msgid "YouTube URL" msgstr "" -#, fuzzy -msgid "Share" -msgstr "비공유" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/src/i18n/messages-zh-cn.po b/src/i18n/messages-zh-cn.po index eeeffda3..b0de177d 100644 --- a/src/i18n/messages-zh-cn.po +++ b/src/i18n/messages-zh-cn.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" "PO-Revision-Date: 2014-05-21 09:54+0800\n" "Last-Translator: Michael P.\n" "Language-Team: Curt Frisemo \n" @@ -246,6 +246,38 @@ msgstr "屏幕共享设置" msgid "Fit screen." msgstr "适合屏幕" +#, fuzzy +msgid "Share screen" +msgstr "共享您的屏幕" + +msgid "Please select what to share." +msgstr "" + +#, fuzzy +msgid "Screen" +msgstr "适合屏幕" + +msgid "Window" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" + +msgid "Share a single window. Click share to select the window." +msgstr "" + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" + +#, fuzzy +msgid "Share" +msgstr "停止分享" + msgid "Profile" msgstr "" @@ -510,10 +542,6 @@ msgstr "" msgid "YouTube URL" msgstr "" -#, fuzzy -msgid "Share" -msgstr "停止分享" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/src/i18n/messages-zh-tw.po b/src/i18n/messages-zh-tw.po index 267d08dc..d0526982 100644 --- a/src/i18n/messages-zh-tw.po +++ b/src/i18n/messages-zh-tw.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" "PO-Revision-Date: 2014-05-21 09:55+0800\n" "Last-Translator: Michael P.\n" "Language-Team: Curt Frisemo \n" @@ -246,6 +246,38 @@ msgstr "屏幕共享設置" msgid "Fit screen." msgstr "適合屏幕" +#, fuzzy +msgid "Share screen" +msgstr "共享您的屏幕" + +msgid "Please select what to share." +msgstr "" + +#, fuzzy +msgid "Screen" +msgstr "適合屏幕" + +msgid "Window" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" + +msgid "Share a single window. Click share to select the window." +msgstr "" + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" + +#, fuzzy +msgid "Share" +msgstr "停止分享" + msgid "Profile" msgstr "" @@ -510,10 +542,6 @@ msgstr "" msgid "YouTube URL" msgstr "" -#, fuzzy -msgid "Share" -msgstr "停止分享" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/src/i18n/messages.pot b/src/i18n/messages.pot index 226649d7..11fdbdf1 100644 --- a/src/i18n/messages.pot +++ b/src/i18n/messages.pot @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Spreed WebRTC 1.0\n" "Report-Msgid-Bugs-To: simon@struktur.de\n" -"POT-Creation-Date: 2015-03-31 18:11+0200\n" +"POT-Creation-Date: 2015-04-14 13:55+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -242,6 +242,35 @@ msgstr "" msgid "Fit screen." msgstr "" +msgid "Share screen" +msgstr "" + +msgid "Please select what to share." +msgstr "" + +msgid "Screen" +msgstr "" + +msgid "Window" +msgstr "" + +msgid "Application" +msgstr "" + +msgid "Share the whole screen. Click share to select the screen." +msgstr "" + +msgid "Share a single window. Click share to select the window." +msgstr "" + +msgid "" +"Share all windows of a application. This can leak content behind windows " +"when windows get moved. Click share to select the application." +msgstr "" + +msgid "Share" +msgstr "" + msgid "Profile" msgstr "" @@ -503,9 +532,6 @@ msgstr "" msgid "YouTube URL" msgstr "" -msgid "Share" -msgstr "" - msgid "" "Could not load YouTube player API, please check your network / firewall " "settings." diff --git a/static/partials/screensharedialogff.html b/static/partials/screensharedialogff.html index 86a56687..67dfb763 100644 --- a/static/partials/screensharedialogff.html +++ b/static/partials/screensharedialogff.html @@ -9,9 +9,9 @@
- Share the whole screen. Click share to select the screen. - Share a single window. Click share to select the window. - Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application. + {{_("Share the whole screen. Click share to select the screen.")}} + {{_("Share a single window. Click share to select the window.")}} + {{_("Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.")}}
diff --git a/static/translation/messages-de.json b/static/translation/messages-de.json index 5b96a499..d0de44b9 100644 --- a/static/translation/messages-de.json +++ b/static/translation/messages-de.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=2; plural=(n != 1)"},"Your audio level":["Ihr Audio-Pegel"],"Standard view":["Standardansicht"],"Large view":["Große Videos"],"Kiosk view":["Kiosk-Ansicht"],"Auditorium":["Auditorium"],"Start chat":["Chat starten"],"Start video call":["Video-Anruf starten"],"Start audio conference":["Audio-Konferenz starten"],"No one else here":["Niemand sonst hier"],"Take":["Los"],"Retake":["Nochmal"],"Cancel":["Abbrechen"],"Set as Profile Picture":["Als Bild setzen"],"Take picture":["Bild machen"],"Upload picture":["Bild hochladen"],"Waiting for camera":["Warte auf die Kamera"],"Picture":["Bild"],"The file couldn't be read.":["Die Datei konnte nicht geöffnet werden."],"The file is not an image.":["Diese Datei ist kein Bild."],"The file is too large. Max. %d MB.":["Diese Datei ist zu groß. Max. %d MB."],"Select file":["Datei wählen"],"Chat sessions":["Chat-Sitzungen"],"Room chat":["Raum-Chat"],"Peer to peer":["Peer-to-peer"],"Close chat":["Chat schließen"],"Upload files":["Dateien hochladen"],"Share my location":["Meinen Standort teilen"],"Clear chat":["Chat löschen"],"is typing...":[" schreibt gerade..."],"has stopped typing...":[" schreibt nicht mehr..."],"Type here to chat...":["Nachricht hier eingeben..."],"Send":["Senden"],"Accept":["Akzeptieren"],"Reject":["Abweisen"],"You have no contacts.":["Sie haben keine Kontakte."],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":["Betreten Sie einen Raum und klicken dann auf das Stern-Symbol eines anderen Nutzers um eine Kontaktanfrage zu starten."],"Edit contact":["Kontakt bearbeiten"],"Edit":["Bearbeiten"],"Name":["Name"],"Remove":["Entfernen"],"Refresh":["Aktualisieren"],"Save":["Speichern"],"Close":["Schließen"],"File sharing":["Datei-Austausch"],"File is no longer available":["Datei ist nicht mehr verfügbar"],"Download":["Laden"],"Open":["Öffnen"],"Unshare":["Zurückziehen"],"Retry":["Nochmal versuchen"],"Download failed.":["Fehler beim Download."],"Share a YouTube video":["Ein YouTube Video teilen"],"Share a file as presentation":["Datei als Präsentation teilen."],"Share your screen":["Bildschirm freigeben"],"Chat":["Chat"],"Contacts":["Kontakte"],"Mute microphone":["Mikrofon abschalten"],"Turn camera off":["Kamera abschalten"],"Settings":["Einstellungen"],"Loading presentation ...":["Präsentation wird geladen..."],"Please upload a document":["Bitte Dokument hochladen"],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":["Das Dokument wird mit allen Gesprächsteilnehmern geteilt. Unterstützt werden PDF und OpenDocument Dateien."],"Upload":["Hochladen"],"You can drag files here too.":["Sie können Dateien auch hierhin ziehen."],"Presentation controls":["Präsentations-Steuerung"],"Prev":["Zurück"],"Next":["Vor"],"Change room":["Raum wechseln"],"Room":["Raum"],"Leave room":["Raum verlassen"],"Main":["Standard"],"Current room":["Raum"],"Screen sharing options":["Optionen für Bildschirmfreigabe"],"Fit screen.":["Bildschirm einpassen."],"Profile":["Profil"],"Your name":["Ihr Name"],"Your picture":["Ihr Bild"],"Status message":["Status Nachricht"],"What's on your mind?":["Was machen Sie gerade?"],"Your picture, name and status message identify yourself in calls, chats and rooms.":["Ihr Bild, Name und Status Nachricht repräsentiert Sie in Anrufen, Chats und Räumen."],"Your ID":["Ihre ID"],"Register":["Registrieren"],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":["Mit Zertifikat angemeldet. Melden Sie sich ab indem Sie das Zertifikat aus dem Browser entfernen."],"Sign in":["Anmelden"],"Create an account":["Registrieren"],"Sign out":["Abmelden"],"Manage account":["Konto verwalten"],"Media":["Kamera / Mikrofon"],"Microphone":["Mikrofon"],"Camera":["Kamera"],"Video quality":["Video-Qualität"],"Low":["Gering"],"High":["Hoch"],"HD":["HD"],"Full HD":["Full HD"],"General":["Allgemein"],"Language":["Sprache"],"Language changes become active on reload.":["Sie müssen die Seite neu laden, um die Spracheinstellung zu übernehmen."],"Default room":["Standard Raum"],"Set alternative room to join at start.":[" Raum wird beim Start automatisch betreten."],"Desktop notification":["Desktop-Benachrichtigung"],"Enable":["Aktivieren"],"Denied - check your browser settings":["Verweigert - prüfen Sie die Browser-Einstellungen"],"Allowed":["Aktiviert"],"Advanced settings":["Erweiterte Einstellungen"],"Play audio on same device as selected microphone":["Audioausgabe auf dem zum Mikrofon gehörenden Gerät"],"Experimental AEC":["Experimentelle AEC"],"Experimental AGC":["Experimentelle AGC"],"Experimental noise suppression":["Experimentelle Geräuschunterdrückung"],"Max video frame rate":["Max. Bildwiederholrate"],"auto":["auto"],"Send stereo audio":["Audio in Stereo übertragen"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":["Um Stereo zu übertragen wird die Echo-Unterdrückung deaktiviert. Nur aktivieren wenn das Eingangssignal Stereo ist."],"Detect CPU over use":["CPU-Überlast erkennen"],"Automatically reduces video quality as needed.":["Reduziert die Videoqualität wenn nötig."],"Optimize for high resolution video":["Für hohe Auflösung optimieren"],"Reduce video noise":["Rauschen reduzieren"],"Enable experiments":["Experimente aktivieren"],"Show advanced settings":["Erweiterte Einstellungen anzeigen"],"Hide advanced settings":["Erweiterte Einstellungen ausblenden"],"Remember settings":["Einstellungen merken"],"Your ID will still be kept - press the log out button above to delete the ID.":["Ihre ID bleibt dennoch gespeichert. Klicken Sie Ausloggen weiter oben um die ID zu löschen."],"Room link":["Raum-Link"],"Invite by Email":["Per E-Mail einladen"],"Invite with Facebook":["Mit Facebook einladen"],"Invite with Twitter":["Mit Twitter einladen"],"Invite with Google Plus":["Mit Google Plus einladen"],"Invite with XING":["Mit XING einladen"],"Initializing":["Initialisiere"],"Online":["Online"],"Calling":["Verbinde mit"],"Hangup":["Auflegen"],"In call with":["Verbunden mit"],"Conference with":["Konferenz mit"],"Your are offline":["Sie sind offline"],"Go online":["Online gehen"],"Connection interrupted":["Verbindung unterbrochen"],"An error occured":["Ein Fehler ist aufgetreten"],"Incoming call":["Eingehender Anruf"],"from":["von"],"Accept call":["Anruf annehmen"],"Waiting for camera/microphone access":["Warte auf Kamera/Mikrofon Freigabe"],"Checking camera and microphone access.":["Prüfe Zugriff auf Kamera und Mikrofon."],"Please allow access to your camera and microphone.":["Bitte gestatten Sie den Zugriff auf Ihre Kamera und Mikrofon."],"Camera / microphone access required.":["Kamera / Mikrofon Zugriff wird benötigt."],"Please check your browser settings and allow camera and microphone access for this site.":["Bitte prüfen Sie Ihre Browser-Einstellungen und gestatten Sie den Zugriff auf Kamera und Mikrofon für diese Seite."],"Skip check":["Überspringen"],"Click here for help (Google Chrome).":["Hier klicken für weitere Infos (Google Chrome)."],"Please set your user details and settings.":["Bitte vervollständigen Sie Ihre Daten und Einstellungen."],"Enter a room name":["Raum eingeben"],"Random room name":["Zufälliger Raum"],"Enter room":["Raum betreten"],"Enter the name of an existing room. You can create new rooms when you are signed in.":["Geben Sie den Namen eines existierenden Raums ein. Melden Sie sich an um eigene Räume zu erstellen."],"Room history":["Raum-Verlauf"],"Please sign in.":["Bitte melden Sie sich an."],"Videos play simultaneously for everyone in this call.":["Das Video wird bei allen Gesprächsteilnehmern angezeigt."],"YouTube URL":["YouTube URL"],"Share":["Teilen"],"Could not load YouTube player API, please check your network / firewall settings.":["Es konnte keine Verbindung zu YouTube aufgebaut werden. Bitte prüfen Sie Ihre Internetverbindung / Firewall."],"Currently playing":["Aktuelles Video"],"YouTube controls":["YouTube Steuerung"],"YouTube video to share":["YouTube Video teilen"],"Peer to peer chat active.":["Peer-to-peer Chat ist aktiv."],"Peer to peer chat is now off.":["Peer-to-peer Chat ist nicht mehr aktiv."]," is now offline.":[" ist jetzt offline."]," is now online.":[" ist jetzt online."],"You share file:":["Sie geben eine Datei frei:"],"Incoming file:":["Eingehende Datei:"],"You shared your location:":["Sie haben Ihren Standort geteilt:"],"Location received:":["Standort erhalten:"],"You accepted the contact request.":["Sie haben die Kontaktanfrage angenommen."],"You rejected the contact request.":["Sie haben die Kontaktanfrage abgelehnt."],"You sent a contact request.":["Sie haben eine Kontaktanfrage gesendet."],"Your contact request was accepted.":["Ihre Kontaktanfrage wurde angenommen."],"Incoming contact request.":["Kontaktanfrage erhalten."],"Your contact request was rejected.":["Ihre Kontaktanfrage wurde abgelehnt."],"Edit Contact":["Kontakt bearbeiten"],"Close this window and disconnect?":["Fenster schließen und die Verbindung trennen?"],"Contacts Manager":["Kontakte"],"Restart required to apply updates. Click ok to restart now.":["Es stehen Updates zur Verfügung. Klicken Sie Ok um die Anwendung neu zu starten."],"Failed to access camera/microphone.":["Fehler beim Zugriff auf die Kamera / das Mikrofon."],"Failed to establish peer connection.":["Fehler beim Verbindungsaufbau."],"We are sorry but something went wrong. Boo boo.":["Leider ist ein Fehler aufgetreten. Buhuhu."],"Oops":["Hoppla"],"Peer connection failed. Check your settings.":["Verbindung fehlgeschlagen. Überprüfen Sie Ihre Einstellungen."],"User hung up because of error.":["Teilnehmer hat aufgelegt, da ein Fehler aufgetreten ist."]," is busy. Try again later.":[" ist in einem Gespräch. Probieren Sie es später."]," rejected your call.":[" hat Ihren Anruf abgelehnt."]," does not pick up.":[" nimmt nicht ab."]," tried to call you":[" hat versucht Sie anzurufen"]," called you":[" hat Sie angerufen"],"Your browser is not supported. Please upgrade to a current version.":["Ihr Browser wird nicht unterstützt. Bitte aktualisieren Sie auf eine aktuelle Version."],"Your browser does not support WebRTC. No calls possible.":["Ihr Browser unterstützt kein WebRTC. Keine Anrufe möglich."],"Chat with":["Chat mit"],"Message from ":["Nachricht von "],"You are now in room %s ...":["Sie sind nun im Raum %s ..."],"Your browser does not support file transfer.":["Mit Ihrem Browser können keine Dateien übertragen werden."],"Could not load PDF: Please make sure to select a PDF document.":["PDF konnte nicht geladen werden - Bitte stellen Sie sicher, dass Sie ein gültiges PDF-Dokument ausgewählt haben."],"Could not load PDF: Missing PDF file.":["Das PDF konnte nicht geladen werden: Datei fehlt."],"An error occurred while loading the PDF (%s).":["Beim Laden des PDF's ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF.":["Beim Laden des PDF ist ein unbekannter Fehler aufgetreten."],"An error occurred while loading the PDF page (%s).":["Beim Laden der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF page.":["Beim Laden der PDF-Seite ist ein unbekannter Fehler aufgetreten (%s)."],"An error occurred while rendering the PDF page (%s).":["Beim Anzeigen der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while rendering the PDF page.":["Beim Anzeigen der PDF-Seite ist ein ubekannter Fehler aufgetreten."],"Only PDF documents and OpenDocument files can be shared at this time.":["Es können nur Dokumente im PDF oder OpenDocument-Format als Präsentation verwendet werden."],"Failed to start screen sharing (%s).":["Die Bildschirmfreigabe konnte nicht gestartet werden (%s)."],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["Die Berechtigung für die Bildschirmaufzeichnung wurde verweigert. Bitte stellen Sie sicher die Unterstützung für Bildschimaufzeichnung in Ihrem Browser aktiviert ist. Kopieren Sie dazu chrome://flags/#enable-usermedia-screen-capture und öffnen Sie diese Adresse in Ihrem Browser. Aktivieren Sie die oberste Einstellung und starten dann den Browser neu. Anschließend können Sie die Bildschirmfreigabe benutzen."],"Permission to start screen sharing was denied.":["Die Berechtigung den Bildschirm freizugeben wurde verweigert."],"Use browser language":["Browsereinstellung"],"Meet with me here:":["Meeting:"],"Room name":["Raum-Name"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":["Unbekanntes URL-Format. Bitte geben Sie eine gültige YouTube URL ein."],"Error":["Fehler"],"Hint":["Hinweis"],"Please confirm":["Bitte bestätigen"],"More information required":["Weitere Informationen nötig"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":["Die Bildschrimfreigabe benötigt eine Browser-Erweiterung. Bitte fügen Sie die \"Spreed WebRTC screen sharing\" Erweiterung zu Chrome hinzu."],"Access code required":["Bitte Zugriffscode eingeben"],"Access denied":["Zugriff verweigert"],"Please provide a valid access code.":["Bitte geben Sie einen gültigen Zugriffscode ein."],"Failed to verify access code. Check your Internet connection and try again.":["Der Zugriffscode konnte nicht überprueft werden. Bitte prüfen Sie Ihre Internetverbindung."],"PIN for room %s is now '%s'.":["PIN für Raum %s ist jetzt '%s'."],"PIN lock has been removed from room %s.":["Raum %s ist nicht mehr PIN-geschützt."],"Enter the PIN for room %s":["Geben Sie die PIN für Raum %s ein"],"Please sign in to create rooms.":["Bitte melden Sie sich an um Räume zu erstellen."],"and %s":["und %s"],"and %d others":["und %d weiteren"],"User":["Teilnehmer"],"Someone":["Unbekannt"],"Me":["Ich"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=2; plural=(n != 1)"},"Your audio level":["Ihr Audio-Pegel"],"Standard view":["Standardansicht"],"Large view":["Große Videos"],"Kiosk view":["Kiosk-Ansicht"],"Auditorium":["Auditorium"],"Start chat":["Chat starten"],"Start video call":["Video-Anruf starten"],"Start audio conference":["Audio-Konferenz starten"],"No one else here":["Niemand sonst hier"],"Take":["Los"],"Retake":["Nochmal"],"Cancel":["Abbrechen"],"Set as Profile Picture":["Als Bild setzen"],"Take picture":["Bild machen"],"Upload picture":["Bild hochladen"],"Waiting for camera":["Warte auf die Kamera"],"Picture":["Bild"],"The file couldn't be read.":["Die Datei konnte nicht geöffnet werden."],"The file is not an image.":["Diese Datei ist kein Bild."],"The file is too large. Max. %d MB.":["Diese Datei ist zu groß. Max. %d MB."],"Select file":["Datei wählen"],"Chat sessions":["Chat-Sitzungen"],"Room chat":["Raum-Chat"],"Peer to peer":["Peer-to-peer"],"Close chat":["Chat schließen"],"Upload files":["Dateien hochladen"],"Share my location":["Meinen Standort teilen"],"Clear chat":["Chat löschen"],"is typing...":[" schreibt gerade..."],"has stopped typing...":[" schreibt nicht mehr..."],"Type here to chat...":["Nachricht hier eingeben..."],"Send":["Senden"],"Accept":["Akzeptieren"],"Reject":["Abweisen"],"You have no contacts.":["Sie haben keine Kontakte."],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":["Betreten Sie einen Raum und klicken dann auf das Stern-Symbol eines anderen Nutzers um eine Kontaktanfrage zu starten."],"Edit contact":["Kontakt bearbeiten"],"Edit":["Bearbeiten"],"Name":["Name"],"Remove":["Entfernen"],"Refresh":["Aktualisieren"],"Save":["Speichern"],"Close":["Schließen"],"File sharing":["Datei-Austausch"],"File is no longer available":["Datei ist nicht mehr verfügbar"],"Download":["Laden"],"Open":["Öffnen"],"Unshare":["Zurückziehen"],"Retry":["Nochmal versuchen"],"Download failed.":["Fehler beim Download."],"Share a YouTube video":["Ein YouTube Video teilen"],"Share a file as presentation":["Datei als Präsentation teilen."],"Share your screen":["Bildschirm freigeben"],"Chat":["Chat"],"Contacts":["Kontakte"],"Mute microphone":["Mikrofon abschalten"],"Turn camera off":["Kamera abschalten"],"Settings":["Einstellungen"],"Loading presentation ...":["Präsentation wird geladen..."],"Please upload a document":["Bitte Dokument hochladen"],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":["Das Dokument wird mit allen Gesprächsteilnehmern geteilt. Unterstützt werden PDF und OpenDocument Dateien."],"Upload":["Hochladen"],"You can drag files here too.":["Sie können Dateien auch hierhin ziehen."],"Presentation controls":["Präsentations-Steuerung"],"Prev":["Zurück"],"Next":["Vor"],"Change room":["Raum wechseln"],"Room":["Raum"],"Leave room":["Raum verlassen"],"Main":["Standard"],"Current room":["Raum"],"Screen sharing options":["Optionen für Bildschirmfreigabe"],"Fit screen.":["Bildschirm einpassen."],"Share screen":["Bildschirm teilen"],"Please select what to share.":["Bitte wählen Sie aus, was geteilt werden soll."],"Screen":["Bildschirm"],"Window":["Fenster"],"Application":["Anwendung"],"Share the whole screen. Click share to select the screen.":["Gesamten Bildschirm teilen. Klicken Sie auf Teilen um den Bildschirm auszuwählen."],"Share a single window. Click share to select the window.":["Einzelnes Fenster teilen. Klicken Sie auf Teilen um das Fenster auszuwählen."],"Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.":["Alle Fenster einer Anwendung teilen. Es wird u.U. Inhalt hinter Fenstern der Anwendung geteilt, wenn diese verschoben werden. Klicken Sie auf Teilen um die Anwendung auszuwählen."],"Share":["Teilen"],"Profile":["Profil"],"Your name":["Ihr Name"],"Your picture":["Ihr Bild"],"Status message":["Status Nachricht"],"What's on your mind?":["Was machen Sie gerade?"],"Your picture, name and status message identify yourself in calls, chats and rooms.":["Ihr Bild, Name und Status Nachricht repräsentiert Sie in Anrufen, Chats und Räumen."],"Your ID":["Ihre ID"],"Register":["Registrieren"],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":["Mit Zertifikat angemeldet. Melden Sie sich ab indem Sie das Zertifikat aus dem Browser entfernen."],"Sign in":["Anmelden"],"Create an account":["Registrieren"],"Sign out":["Abmelden"],"Manage account":["Konto verwalten"],"Media":["Kamera / Mikrofon"],"Microphone":["Mikrofon"],"Camera":["Kamera"],"Video quality":["Video-Qualität"],"Low":["Gering"],"High":["Hoch"],"HD":["HD"],"Full HD":["Full HD"],"General":["Allgemein"],"Language":["Sprache"],"Language changes become active on reload.":["Sie müssen die Seite neu laden, um die Spracheinstellung zu übernehmen."],"Default room":["Standard Raum"],"Set alternative room to join at start.":[" Raum wird beim Start automatisch betreten."],"Desktop notification":["Desktop-Benachrichtigung"],"Enable":["Aktivieren"],"Denied - check your browser settings":["Verweigert - prüfen Sie die Browser-Einstellungen"],"Allowed":["Aktiviert"],"Advanced settings":["Erweiterte Einstellungen"],"Play audio on same device as selected microphone":["Audioausgabe auf dem zum Mikrofon gehörenden Gerät"],"Experimental AEC":["Experimentelle AEC"],"Experimental AGC":["Experimentelle AGC"],"Experimental noise suppression":["Experimentelle Geräuschunterdrückung"],"Max video frame rate":["Max. Bildwiederholrate"],"auto":["auto"],"Send stereo audio":["Audio in Stereo übertragen"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":["Um Stereo zu übertragen wird die Echo-Unterdrückung deaktiviert. Nur aktivieren wenn das Eingangssignal Stereo ist."],"Detect CPU over use":["CPU-Überlast erkennen"],"Automatically reduces video quality as needed.":["Reduziert die Videoqualität wenn nötig."],"Optimize for high resolution video":["Für hohe Auflösung optimieren"],"Reduce video noise":["Rauschen reduzieren"],"Enable experiments":["Experimente aktivieren"],"Show advanced settings":["Erweiterte Einstellungen anzeigen"],"Hide advanced settings":["Erweiterte Einstellungen ausblenden"],"Remember settings":["Einstellungen merken"],"Your ID will still be kept - press the log out button above to delete the ID.":["Ihre ID bleibt dennoch gespeichert. Klicken Sie Ausloggen weiter oben um die ID zu löschen."],"Room link":["Raum-Link"],"Invite by Email":["Per E-Mail einladen"],"Invite with Facebook":["Mit Facebook einladen"],"Invite with Twitter":["Mit Twitter einladen"],"Invite with Google Plus":["Mit Google Plus einladen"],"Invite with XING":["Mit XING einladen"],"Initializing":["Initialisiere"],"Online":["Online"],"Calling":["Verbinde mit"],"Hangup":["Auflegen"],"In call with":["Verbunden mit"],"Conference with":["Konferenz mit"],"Your are offline":["Sie sind offline"],"Go online":["Online gehen"],"Connection interrupted":["Verbindung unterbrochen"],"An error occured":["Ein Fehler ist aufgetreten"],"Incoming call":["Eingehender Anruf"],"from":["von"],"Accept call":["Anruf annehmen"],"Waiting for camera/microphone access":["Warte auf Kamera/Mikrofon Freigabe"],"Checking camera and microphone access.":["Prüfe Zugriff auf Kamera und Mikrofon."],"Please allow access to your camera and microphone.":["Bitte gestatten Sie den Zugriff auf Ihre Kamera und Mikrofon."],"Camera / microphone access required.":["Kamera / Mikrofon Zugriff wird benötigt."],"Please check your browser settings and allow camera and microphone access for this site.":["Bitte prüfen Sie Ihre Browser-Einstellungen und gestatten Sie den Zugriff auf Kamera und Mikrofon für diese Seite."],"Skip check":["Überspringen"],"Click here for help (Google Chrome).":["Hier klicken für weitere Infos (Google Chrome)."],"Please set your user details and settings.":["Bitte vervollständigen Sie Ihre Daten und Einstellungen."],"Enter a room name":["Raum eingeben"],"Random room name":["Zufälliger Raum"],"Enter room":["Raum betreten"],"Enter the name of an existing room. You can create new rooms when you are signed in.":["Geben Sie den Namen eines existierenden Raums ein. Melden Sie sich an um eigene Räume zu erstellen."],"Room history":["Raum-Verlauf"],"Please sign in.":["Bitte melden Sie sich an."],"Videos play simultaneously for everyone in this call.":["Das Video wird bei allen Gesprächsteilnehmern angezeigt."],"YouTube URL":["YouTube URL"],"Could not load YouTube player API, please check your network / firewall settings.":["Es konnte keine Verbindung zu YouTube aufgebaut werden. Bitte prüfen Sie Ihre Internetverbindung / Firewall."],"Currently playing":["Aktuelles Video"],"YouTube controls":["YouTube Steuerung"],"YouTube video to share":["YouTube Video teilen"],"Peer to peer chat active.":["Peer-to-peer Chat ist aktiv."],"Peer to peer chat is now off.":["Peer-to-peer Chat ist nicht mehr aktiv."]," is now offline.":[" ist jetzt offline."]," is now online.":[" ist jetzt online."],"You share file:":["Sie geben eine Datei frei:"],"Incoming file:":["Eingehende Datei:"],"You shared your location:":["Sie haben Ihren Standort geteilt:"],"Location received:":["Standort erhalten:"],"You accepted the contact request.":["Sie haben die Kontaktanfrage angenommen."],"You rejected the contact request.":["Sie haben die Kontaktanfrage abgelehnt."],"You sent a contact request.":["Sie haben eine Kontaktanfrage gesendet."],"Your contact request was accepted.":["Ihre Kontaktanfrage wurde angenommen."],"Incoming contact request.":["Kontaktanfrage erhalten."],"Your contact request was rejected.":["Ihre Kontaktanfrage wurde abgelehnt."],"Edit Contact":["Kontakt bearbeiten"],"Close this window and disconnect?":["Fenster schließen und die Verbindung trennen?"],"Contacts Manager":["Kontakte"],"Restart required to apply updates. Click ok to restart now.":["Es stehen Updates zur Verfügung. Klicken Sie Ok um die Anwendung neu zu starten."],"Failed to access camera/microphone.":["Fehler beim Zugriff auf die Kamera / das Mikrofon."],"Failed to establish peer connection.":["Fehler beim Verbindungsaufbau."],"We are sorry but something went wrong. Boo boo.":["Leider ist ein Fehler aufgetreten. Buhuhu."],"Oops":["Hoppla"],"Peer connection failed. Check your settings.":["Verbindung fehlgeschlagen. Überprüfen Sie Ihre Einstellungen."],"User hung up because of error.":["Teilnehmer hat aufgelegt, da ein Fehler aufgetreten ist."]," is busy. Try again later.":[" ist in einem Gespräch. Probieren Sie es später."]," rejected your call.":[" hat Ihren Anruf abgelehnt."]," does not pick up.":[" nimmt nicht ab."]," tried to call you":[" hat versucht Sie anzurufen"]," called you":[" hat Sie angerufen"],"Your browser is not supported. Please upgrade to a current version.":["Ihr Browser wird nicht unterstützt. Bitte aktualisieren Sie auf eine aktuelle Version."],"Your browser does not support WebRTC. No calls possible.":["Ihr Browser unterstützt kein WebRTC. Keine Anrufe möglich."],"Chat with":["Chat mit"],"Message from ":["Nachricht von "],"You are now in room %s ...":["Sie sind nun im Raum %s ..."],"Your browser does not support file transfer.":["Mit Ihrem Browser können keine Dateien übertragen werden."],"Could not load PDF: Please make sure to select a PDF document.":["PDF konnte nicht geladen werden - Bitte stellen Sie sicher, dass Sie ein gültiges PDF-Dokument ausgewählt haben."],"Could not load PDF: Missing PDF file.":["Das PDF konnte nicht geladen werden: Datei fehlt."],"An error occurred while loading the PDF (%s).":["Beim Laden des PDF's ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF.":["Beim Laden des PDF ist ein unbekannter Fehler aufgetreten."],"An error occurred while loading the PDF page (%s).":["Beim Laden der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while loading the PDF page.":["Beim Laden der PDF-Seite ist ein unbekannter Fehler aufgetreten (%s)."],"An error occurred while rendering the PDF page (%s).":["Beim Anzeigen der PDF-Seite ist ein Fehler aufgetreten (%s)."],"An unknown error occurred while rendering the PDF page.":["Beim Anzeigen der PDF-Seite ist ein ubekannter Fehler aufgetreten."],"Only PDF documents and OpenDocument files can be shared at this time.":["Es können nur Dokumente im PDF oder OpenDocument-Format als Präsentation verwendet werden."],"Failed to start screen sharing (%s).":["Die Bildschirmfreigabe konnte nicht gestartet werden (%s)."],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["Die Berechtigung für die Bildschirmaufzeichnung wurde verweigert. Bitte stellen Sie sicher die Unterstützung für Bildschimaufzeichnung in Ihrem Browser aktiviert ist. Kopieren Sie dazu chrome://flags/#enable-usermedia-screen-capture und öffnen Sie diese Adresse in Ihrem Browser. Aktivieren Sie die oberste Einstellung und starten dann den Browser neu. Anschließend können Sie die Bildschirmfreigabe benutzen."],"Permission to start screen sharing was denied.":["Die Berechtigung den Bildschirm freizugeben wurde verweigert."],"Use browser language":["Browsereinstellung"],"Meet with me here:":["Meeting:"],"Room name":["Raum-Name"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":["Unbekanntes URL-Format. Bitte geben Sie eine gültige YouTube URL ein."],"Error":["Fehler"],"Hint":["Hinweis"],"Please confirm":["Bitte bestätigen"],"More information required":["Weitere Informationen nötig"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":["Die Bildschrimfreigabe benötigt eine Browser-Erweiterung. Bitte fügen Sie die \"Spreed WebRTC screen sharing\" Erweiterung zu Chrome hinzu."],"Access code required":["Bitte Zugriffscode eingeben"],"Access denied":["Zugriff verweigert"],"Please provide a valid access code.":["Bitte geben Sie einen gültigen Zugriffscode ein."],"Failed to verify access code. Check your Internet connection and try again.":["Der Zugriffscode konnte nicht überprueft werden. Bitte prüfen Sie Ihre Internetverbindung."],"PIN for room %s is now '%s'.":["PIN für Raum %s ist jetzt '%s'."],"PIN lock has been removed from room %s.":["Raum %s ist nicht mehr PIN-geschützt."],"Enter the PIN for room %s":["Geben Sie die PIN für Raum %s ein"],"Please sign in to create rooms.":["Bitte melden Sie sich an um Räume zu erstellen."],"and %s":["und %s"],"and %d others":["und %d weiteren"],"User":["Teilnehmer"],"Someone":["Unbekannt"],"Me":["Ich"]}}} \ No newline at end of file diff --git a/static/translation/messages-ja.json b/static/translation/messages-ja.json index 5be7e269..763a50b2 100644 --- a/static/translation/messages-ja.json +++ b/static/translation/messages-ja.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["あなたの音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["チャットを始める"],"Start video call":["テレビ電話を始める"],"Start audio conference":["音声会議を始める"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["キャンセル"],"Set as Profile Picture":[""],"Take picture":["写真を取る"],"Waiting for camera":["カメラ待ち"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["チャットのセッション"],"Room chat":["ルームチャット"],"Peer to peer":["ピア・ツー・ピア"],"Close chat":["チャットを終える"],"Share my location":[""],"is typing...":["は入力中です..."],"has stopped typing...":["は入力を止めました..."],"Type here to chat...":["ここに入力してチャット開始します..."],"Send":["送信"],"Accept":[""],"Reject":["拒否"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名前"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["閉じる"],"File sharing":["ファイル共有"],"File is no longer available":["ファイルは有効ではありません"],"Download":["ダウンロード"],"Open":["開く"],"Unshare":["共有取り消し"],"Retry":["リトライ"],"Download failed.":["ダウンロード失敗."],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["画面を共有する."],"Chat":["チャット"],"Contacts":[""],"Mute microphone":["消音"],"Turn camera off":["カメラをオフにする"],"Settings":["設定"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["ルームチェンジ"],"Room":["ルーム"],"Leave room":["ルームを出る"],"Main":["メイン"],"Current room":["現在のルーム"],"Screen sharing options":["画面共有オプション"],"Fit screen.":["画面に合わせる"],"Profile":[""],"Your name":["あなたの名前"],"Your picture":["あなたの写真"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["マイク"],"Camera":["カメラ"],"Video quality":["ビデオ画質"],"Low":["低い"],"High":["高い"],"HD":["HD"],"Full HD":[""],"General":[""],"Language":["言語"],"Language changes become active on reload.":["言語の変更は再読み込み時に適用となります."],"Default room":["デフォルト・ルーム"],"Set alternative room to join at start.":["スタート時に別のルームに参加する."],"Desktop notification":["デスクトップ通知"],"Enable":["有効にする"],"Denied - check your browser settings":["拒否 - ブラウザ設定を確認して下さい"],"Allowed":["許可"],"Advanced settings":["詳細設定"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["ビデオ最高フレームレート"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["詳細設定を表示"],"Hide advanced settings":["詳細設定を隠す"],"Remember settings":["設定を保存"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初期化中"],"Online":["オンライン"],"Calling":["発信中"],"Hangup":["切断"],"In call with":["と会話中"],"Conference with":["と会議中"],"Your are offline":["オフラインです"],"Go online":["オンラインにする"],"Connection interrupted":["接続は中断されました"],"An error occured":["エラーが発生しました"],"Incoming call":["着信中"],"from":["から"],"Accept call":["通話"],"Waiting for camera/microphone access":["カメラ・マイクの接続待ち."],"Checking camera and microphone access.":["カメラ・マイクの接続確認中."],"Please allow access to your camera and microphone.":["カメラとマイクの接続を許可してください."],"Camera / microphone access required.":["カメラ・マイクの接続が必要です."],"Please check your browser settings and allow camera and microphone access for this site.":["ブラウザ設定で、このサイトへのカメラ・マイクの接続を許可してください."],"Skip check":["チェックをスキップ"],"Click here for help (Google Chrome).":["ここをクリックしてヘルプ表示(Google Chrome)"],"Please set your user details and settings.":["あなたのプロフィールとアプリの動作を設定してください."],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["ピア・ツー・ピア・チャットがアクティブです."],"Peer to peer chat is now off.":["ピア・ツー・ピア・チャットがオフです."]," is now offline.":["は今オフラインです"]," is now online.":["は今オンラインです"],"You share file:":["あなたの共有ファイル:"],"Incoming file:":["受信中ファイル:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["アップデート適用のため再起動してください.ここをクリックして再起動する."],"Failed to access camera/microphone.":["カメラ・マイクへの接続に失敗しました."],"Failed to establish peer connection.":["ピアとの接続に失敗しました."],"We are sorry but something went wrong. Boo boo.":["申し訳ないのですが、不具合が生じました。"],"Oops":["しまった"],"Peer connection failed. Check your settings.":["ピア接続に失敗しました.設定を確認してください."],"User hung up because of error.":["エラーのため切断しました."]," is busy. Try again later.":["は話中です.後で掛けなおしてください."]," rejected your call.":["着信拒否されました."]," does not pick up.":["は電話にでません."],"Your browser does not support WebRTC. No calls possible.":["ブラウザがWebRTCをサポートしていない為通話はできません."],"Chat with":["とチャットする"],"Message from ":["からのメッセージ"],"You are now in room %s ...":["あなたは%sのルームにいます..."],"Your browser does not support file transfer.":["ブラウザがファイル転送をサポートしていません."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["画面共有は拒否されました.ブラウザの画面共有の設定を確認して下さい. Chromeのアドレスバーに chrome://flags/#enable-usermedia-screen-capture を入力して開き、スクリーンキャプチャのサポートを有効にしてください。その後ブラウザを再起動してください。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["ブラウザの言語を使用"],"Meet with me here:":["ここで私と会う:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["エラー"],"Hint":["ヒント"],"Please confirm":["確認して下さい"],"More information required":["さらなる情報が必要です"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["アクセスコードが必要です"],"Access denied":["アクセスが拒否されました"],"Please provide a valid access code.":["有効なアクセスコードを入力してください."],"Failed to verify access code. Check your Internet connection and try again.":["アクセスコードの確認に失敗しました.インターネット接続を確認してリトライしてください."],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["ユーザー"],"Someone":["誰か"],"Me":["私"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["あなたの音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["チャットを始める"],"Start video call":["テレビ電話を始める"],"Start audio conference":["音声会議を始める"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["キャンセル"],"Set as Profile Picture":[""],"Take picture":["写真を取る"],"Waiting for camera":["カメラ待ち"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["チャットのセッション"],"Room chat":["ルームチャット"],"Peer to peer":["ピア・ツー・ピア"],"Close chat":["チャットを終える"],"Share my location":[""],"is typing...":["は入力中です..."],"has stopped typing...":["は入力を止めました..."],"Type here to chat...":["ここに入力してチャット開始します..."],"Send":["送信"],"Accept":[""],"Reject":["拒否"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名前"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["閉じる"],"File sharing":["ファイル共有"],"File is no longer available":["ファイルは有効ではありません"],"Download":["ダウンロード"],"Open":["開く"],"Unshare":["共有取り消し"],"Retry":["リトライ"],"Download failed.":["ダウンロード失敗."],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["画面を共有する."],"Chat":["チャット"],"Contacts":[""],"Mute microphone":["消音"],"Turn camera off":["カメラをオフにする"],"Settings":["設定"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["ルームチェンジ"],"Room":["ルーム"],"Leave room":["ルームを出る"],"Main":["メイン"],"Current room":["現在のルーム"],"Screen sharing options":["画面共有オプション"],"Fit screen.":["画面に合わせる"],"Please select what to share.":[""],"Window":[""],"Application":[""],"Share the whole screen. Click share to select the screen.":[""],"Share a single window. Click share to select the window.":[""],"Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.":[""],"Profile":[""],"Your name":["あなたの名前"],"Your picture":["あなたの写真"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["マイク"],"Camera":["カメラ"],"Video quality":["ビデオ画質"],"Low":["低い"],"High":["高い"],"HD":["HD"],"Full HD":[""],"General":[""],"Language":["言語"],"Language changes become active on reload.":["言語の変更は再読み込み時に適用となります."],"Default room":["デフォルト・ルーム"],"Set alternative room to join at start.":["スタート時に別のルームに参加する."],"Desktop notification":["デスクトップ通知"],"Enable":["有効にする"],"Denied - check your browser settings":["拒否 - ブラウザ設定を確認して下さい"],"Allowed":["許可"],"Advanced settings":["詳細設定"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["ビデオ最高フレームレート"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["詳細設定を表示"],"Hide advanced settings":["詳細設定を隠す"],"Remember settings":["設定を保存"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初期化中"],"Online":["オンライン"],"Calling":["発信中"],"Hangup":["切断"],"In call with":["と会話中"],"Conference with":["と会議中"],"Your are offline":["オフラインです"],"Go online":["オンラインにする"],"Connection interrupted":["接続は中断されました"],"An error occured":["エラーが発生しました"],"Incoming call":["着信中"],"from":["から"],"Accept call":["通話"],"Waiting for camera/microphone access":["カメラ・マイクの接続待ち."],"Checking camera and microphone access.":["カメラ・マイクの接続確認中."],"Please allow access to your camera and microphone.":["カメラとマイクの接続を許可してください."],"Camera / microphone access required.":["カメラ・マイクの接続が必要です."],"Please check your browser settings and allow camera and microphone access for this site.":["ブラウザ設定で、このサイトへのカメラ・マイクの接続を許可してください."],"Skip check":["チェックをスキップ"],"Click here for help (Google Chrome).":["ここをクリックしてヘルプ表示(Google Chrome)"],"Please set your user details and settings.":["あなたのプロフィールとアプリの動作を設定してください."],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["ピア・ツー・ピア・チャットがアクティブです."],"Peer to peer chat is now off.":["ピア・ツー・ピア・チャットがオフです."]," is now offline.":["は今オフラインです"]," is now online.":["は今オンラインです"],"You share file:":["あなたの共有ファイル:"],"Incoming file:":["受信中ファイル:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["アップデート適用のため再起動してください.ここをクリックして再起動する."],"Failed to access camera/microphone.":["カメラ・マイクへの接続に失敗しました."],"Failed to establish peer connection.":["ピアとの接続に失敗しました."],"We are sorry but something went wrong. Boo boo.":["申し訳ないのですが、不具合が生じました。"],"Oops":["しまった"],"Peer connection failed. Check your settings.":["ピア接続に失敗しました.設定を確認してください."],"User hung up because of error.":["エラーのため切断しました."]," is busy. Try again later.":["は話中です.後で掛けなおしてください."]," rejected your call.":["着信拒否されました."]," does not pick up.":["は電話にでません."],"Your browser does not support WebRTC. No calls possible.":["ブラウザがWebRTCをサポートしていない為通話はできません."],"Chat with":["とチャットする"],"Message from ":["からのメッセージ"],"You are now in room %s ...":["あなたは%sのルームにいます..."],"Your browser does not support file transfer.":["ブラウザがファイル転送をサポートしていません."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["画面共有は拒否されました.ブラウザの画面共有の設定を確認して下さい. Chromeのアドレスバーに chrome://flags/#enable-usermedia-screen-capture を入力して開き、スクリーンキャプチャのサポートを有効にしてください。その後ブラウザを再起動してください。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["ブラウザの言語を使用"],"Meet with me here:":["ここで私と会う:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["エラー"],"Hint":["ヒント"],"Please confirm":["確認して下さい"],"More information required":["さらなる情報が必要です"],"Ok":["OK"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["アクセスコードが必要です"],"Access denied":["アクセスが拒否されました"],"Please provide a valid access code.":["有効なアクセスコードを入力してください."],"Failed to verify access code. Check your Internet connection and try again.":["アクセスコードの確認に失敗しました.インターネット接続を確認してリトライしてください."],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["ユーザー"],"Someone":["誰か"],"Me":["私"]}}} \ No newline at end of file diff --git a/static/translation/messages-ko.json b/static/translation/messages-ko.json index 99aa9730..f3ed4cc9 100644 --- a/static/translation/messages-ko.json +++ b/static/translation/messages-ko.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["음성크기"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["대화시작"],"Start video call":["화상회의 시작"],"Start audio conference":["음성회의 시작"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["취소"],"Set as Profile Picture":[""],"Take picture":["사진 찍음"],"Waiting for camera":["카메라 대기중"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["대화 세션"],"Room chat":["대화 방"],"Peer to peer":["일대일"],"Close chat":["대화 종료"],"Share my location":[""],"is typing...":["입력중"],"has stopped typing...":["입력 종료"],"Type here to chat...":["대화 입력"],"Send":["전송"],"Accept":[""],"Reject":["거부"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["이름"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["닫음"],"File sharing":["회일 공유"],"File is no longer available":["화일이 유효하지 않습니다"],"Download":["다운로드"],"Open":["열기"],"Unshare":["비공유"],"Retry":["재시도"],"Download failed.":["다운로드실패"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["화면 공유하기"],"Chat":["대화"],"Contacts":[""],"Mute microphone":["음성제거"],"Turn camera off":["카메라꺼짐"],"Settings":["설정"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["방 변경"],"Room":["방"],"Leave room":["방 이동"],"Main":["메인"],"Current room":["현재 방"],"Screen sharing options":["화면 공유 옵션"],"Fit screen.":["화면에 맟춤"],"Profile":[""],"Your name":["사용자 이름"],"Your picture":["사용자 사진"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["마이크"],"Camera":["카메라"],"Video quality":["영상 수준"],"Low":["낮음"],"High":["높음"],"HD":["고화질"],"Full HD":[""],"General":[""],"Language":["언어"],"Language changes become active on reload.":["언어 변경이 재로드 되고 있습니다"],"Default room":["기본 방"],"Set alternative room to join at start.":["시작시에 다른 방에 합류하도록 설정 되었습니다"],"Desktop notification":["데스크탑에 통보"],"Enable":["활성화"],"Denied - check your browser settings":["거부됨 - 브라우저 설정을 확인하세요"],"Allowed":["허락됨"],"Advanced settings":["고급 설정"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["비디오프레임 비율 최대화"],"auto":["자동"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["고급 설정 보기"],"Hide advanced settings":["고급 설정 감추기"],"Remember settings":["설정 기억"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["초기화"],"Online":["온라인"],"Calling":["전화걸기"],"Hangup":["전화끊기"],"In call with":["전화중"],"Conference with":["회의중"],"Your are offline":["오프라인 입니다"],"Go online":["온라인에 연결합니다"],"Connection interrupted":["연결이 중단"],"An error occured":["에러 발생"],"Incoming call":["전화 걸려옴"],"from":["부터"],"Accept call":["전화 받음"],"Waiting for camera/microphone access":["카메라/마이크 사용을 기다림"],"Checking camera and microphone access.":["카메라와 마이크의 사용을 확인 하세요"],"Please allow access to your camera and microphone.":["카메라와 마이크의 사용을 허용 하세요"],"Camera / microphone access required.":["카메라/마이크 사용이 필요합니다"],"Please check your browser settings and allow camera and microphone access for this site.":["이 사이트에 대하여 브라우저의 설정을 확인하고 카메라와 마이크의 사용을 허용 하세요"],"Skip check":["확인 넘어가기"],"Click here for help (Google Chrome).":["도움말을 원하면 여기를 클릭 하세요 (구글 크롬)"],"Please set your user details and settings.":["사용자의 세부상세와 설정을 지정하세요 "],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["일대일 대화 활성화"],"Peer to peer chat is now off.":["일대일 대화 꺼짐"]," is now offline.":["현재 오프라인 상태"]," is now online.":["현재 온라인 상태"],"You share file:":["공유 화일:"],"Incoming file:":["도착하는 화일:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"],"Failed to access camera/microphone.":["카메라/마이크 사용 실패"],"Failed to establish peer connection.":["상대연결 설정이 실패 하였습니다"],"We are sorry but something went wrong. Boo boo.":["죄송합니다만 현재 문제가 있습니다."],"Oops":["이런"],"Peer connection failed. Check your settings.":["상대연결이 실패 했습니다. 설정을 확인 하십시오"],"User hung up because of error.":["오류로 인해 사용자 끊어짐"]," is busy. Try again later.":["통화중. 다시 시도 하세요."]," rejected your call.":["전화가 거부 되었습니다."]," does not pick up.":["전화를 받지 않습니다."],"Your browser does not support WebRTC. No calls possible.":["브라우저가 WebRTC를 지원하지 않습니다. 전화걸기가 불가능 합니다."],"Chat with":["대화하기"],"Message from ":["로 부터 메시지"],"You are now in room %s ...":["당신은 현재 방%s ...에 있습니다"],"Your browser does not support file transfer.":["당신의 브라우저가 회일전송을 지원하지 않습니다."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["화면공유가 거절되었습니다. 사용하시는 브라우저에서 화면공유를 가능하도록 하여 주십시오. chrome://flags/#enable-usermedia-screen-capture를 복사하여 브라우저에서 수행하시고 상단의 프래그를 가능으로 변경 하십시오. 브라우저를 다시 수행시키면 사용하실수 있습니다."],"Permission to start screen sharing was denied.":[""],"Use browser language":["브라우저 언어 사용"],"Meet with me here:":["나를 여기서 만납니다:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["오류"],"Hint":["도움말"],"Please confirm":["확인하십시오"],"More information required":["더 많은 정보가 필요함"],"Ok":["오케이"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["접속코드 필요함"],"Access denied":["접속 거부"],"Please provide a valid access code.":["유효한 접속코드가 필요합니다."],"Failed to verify access code. Check your Internet connection and try again.":["접속코드 확인이 실패 했습니다. 인터넷 연결을 확인하고 다시 시도해 주십시오. "],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["사용자"],"Someone":["어떤 사람"],"Me":["나"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["음성크기"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["대화시작"],"Start video call":["화상회의 시작"],"Start audio conference":["음성회의 시작"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["취소"],"Set as Profile Picture":[""],"Take picture":["사진 찍음"],"Waiting for camera":["카메라 대기중"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["대화 세션"],"Room chat":["대화 방"],"Peer to peer":["일대일"],"Close chat":["대화 종료"],"Share my location":[""],"is typing...":["입력중"],"has stopped typing...":["입력 종료"],"Type here to chat...":["대화 입력"],"Send":["전송"],"Accept":[""],"Reject":["거부"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["이름"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["닫음"],"File sharing":["회일 공유"],"File is no longer available":["화일이 유효하지 않습니다"],"Download":["다운로드"],"Open":["열기"],"Unshare":["비공유"],"Retry":["재시도"],"Download failed.":["다운로드실패"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["화면 공유하기"],"Chat":["대화"],"Contacts":[""],"Mute microphone":["음성제거"],"Turn camera off":["카메라꺼짐"],"Settings":["설정"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["방 변경"],"Room":["방"],"Leave room":["방 이동"],"Main":["메인"],"Current room":["현재 방"],"Screen sharing options":["화면 공유 옵션"],"Fit screen.":["화면에 맟춤"],"Please select what to share.":[""],"Window":[""],"Application":[""],"Share the whole screen. Click share to select the screen.":[""],"Share a single window. Click share to select the window.":[""],"Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.":[""],"Profile":[""],"Your name":["사용자 이름"],"Your picture":["사용자 사진"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["마이크"],"Camera":["카메라"],"Video quality":["영상 수준"],"Low":["낮음"],"High":["높음"],"HD":["고화질"],"Full HD":[""],"General":[""],"Language":["언어"],"Language changes become active on reload.":["언어 변경이 재로드 되고 있습니다"],"Default room":["기본 방"],"Set alternative room to join at start.":["시작시에 다른 방에 합류하도록 설정 되었습니다"],"Desktop notification":["데스크탑에 통보"],"Enable":["활성화"],"Denied - check your browser settings":["거부됨 - 브라우저 설정을 확인하세요"],"Allowed":["허락됨"],"Advanced settings":["고급 설정"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["비디오프레임 비율 최대화"],"auto":["자동"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["고급 설정 보기"],"Hide advanced settings":["고급 설정 감추기"],"Remember settings":["설정 기억"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["초기화"],"Online":["온라인"],"Calling":["전화걸기"],"Hangup":["전화끊기"],"In call with":["전화중"],"Conference with":["회의중"],"Your are offline":["오프라인 입니다"],"Go online":["온라인에 연결합니다"],"Connection interrupted":["연결이 중단"],"An error occured":["에러 발생"],"Incoming call":["전화 걸려옴"],"from":["부터"],"Accept call":["전화 받음"],"Waiting for camera/microphone access":["카메라/마이크 사용을 기다림"],"Checking camera and microphone access.":["카메라와 마이크의 사용을 확인 하세요"],"Please allow access to your camera and microphone.":["카메라와 마이크의 사용을 허용 하세요"],"Camera / microphone access required.":["카메라/마이크 사용이 필요합니다"],"Please check your browser settings and allow camera and microphone access for this site.":["이 사이트에 대하여 브라우저의 설정을 확인하고 카메라와 마이크의 사용을 허용 하세요"],"Skip check":["확인 넘어가기"],"Click here for help (Google Chrome).":["도움말을 원하면 여기를 클릭 하세요 (구글 크롬)"],"Please set your user details and settings.":["사용자의 세부상세와 설정을 지정하세요 "],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["일대일 대화 활성화"],"Peer to peer chat is now off.":["일대일 대화 꺼짐"]," is now offline.":["현재 오프라인 상태"]," is now online.":["현재 온라인 상태"],"You share file:":["공유 화일:"],"Incoming file:":["도착하는 화일:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"],"Failed to access camera/microphone.":["카메라/마이크 사용 실패"],"Failed to establish peer connection.":["상대연결 설정이 실패 하였습니다"],"We are sorry but something went wrong. Boo boo.":["죄송합니다만 현재 문제가 있습니다."],"Oops":["이런"],"Peer connection failed. Check your settings.":["상대연결이 실패 했습니다. 설정을 확인 하십시오"],"User hung up because of error.":["오류로 인해 사용자 끊어짐"]," is busy. Try again later.":["통화중. 다시 시도 하세요."]," rejected your call.":["전화가 거부 되었습니다."]," does not pick up.":["전화를 받지 않습니다."],"Your browser does not support WebRTC. No calls possible.":["브라우저가 WebRTC를 지원하지 않습니다. 전화걸기가 불가능 합니다."],"Chat with":["대화하기"],"Message from ":["로 부터 메시지"],"You are now in room %s ...":["당신은 현재 방%s ...에 있습니다"],"Your browser does not support file transfer.":["당신의 브라우저가 회일전송을 지원하지 않습니다."],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["화면공유가 거절되었습니다. 사용하시는 브라우저에서 화면공유를 가능하도록 하여 주십시오. chrome://flags/#enable-usermedia-screen-capture를 복사하여 브라우저에서 수행하시고 상단의 프래그를 가능으로 변경 하십시오. 브라우저를 다시 수행시키면 사용하실수 있습니다."],"Permission to start screen sharing was denied.":[""],"Use browser language":["브라우저 언어 사용"],"Meet with me here:":["나를 여기서 만납니다:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["오류"],"Hint":["도움말"],"Please confirm":["확인하십시오"],"More information required":["더 많은 정보가 필요함"],"Ok":["오케이"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["접속코드 필요함"],"Access denied":["접속 거부"],"Please provide a valid access code.":["유효한 접속코드가 필요합니다."],"Failed to verify access code. Check your Internet connection and try again.":["접속코드 확인이 실패 했습니다. 인터넷 연결을 확인하고 다시 시도해 주십시오. "],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %d others":[""],"User":["사용자"],"Someone":["어떤 사람"],"Me":["나"]}}} \ No newline at end of file diff --git a/static/translation/messages-zh-cn.json b/static/translation/messages-zh-cn.json index d1770c91..7641eac7 100644 --- a/static/translation/messages-zh-cn.json +++ b/static/translation/messages-zh-cn.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通话音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["开始聊天"],"Start video call":["开始视频通话"],"Start audio conference":["开始语音会议"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待启动摄像头"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["会话"],"Room chat":["房间聊天"],"Peer to peer":["P2P"],"Close chat":["关闭聊天"],"Share my location":[""],"is typing...":["正在输入..."],"has stopped typing...":["停止输入..."],"Type here to chat...":["在此输入开始聊天..."],"Send":["发送"],"Accept":[""],"Reject":["拒绝"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["关闭"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下载"],"Open":["打开"],"Unshare":["停止分享"],"Retry":["重试"],"Download failed.":["下载失败"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["关闭麦克风"],"Turn camera off":["关闭摄像头"],"Settings":["系统设置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更换房间"],"Room":["房间"],"Leave room":["离开房间"],"Main":["主房间"],"Current room":["當前房间"],"Screen sharing options":["屏幕共享设置"],"Fit screen.":["适合屏幕"],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的图片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麦克风"],"Camera":["摄像头"],"Video quality":["视频质量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["语言"],"Language changes become active on reload.":["转换语言需重启程序"],"Default room":["系统默认房间"],"Set alternative room to join at start.":["重设初始默认房间"],"Desktop notification":["桌面提醒"],"Enable":["开启"],"Denied - check your browser settings":["被拒绝--请检查浏览器设置"],"Allowed":["启用"],"Advanced settings":["高级设置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大视频帧速率"],"auto":["自动"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展开高级设置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["记住设置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在线"],"Calling":["呼叫中"],"Hangup":["挂断"],"In call with":["正在和**通话"],"Conference with":["和**会议通话"],"Your are offline":["您不在线"],"Go online":["上线"],"Connection interrupted":["连接已中断"],"An error occured":["出现错误"],"Incoming call":["来电"],"from":["来自"],"Accept call":["接受通话"],"Waiting for camera/microphone access":["等待摄像头/麦克风连接"],"Checking camera and microphone access.":["正在检查摄像头及麦克风连接"],"Please allow access to your camera and microphone.":["请允许连接您的摄像头及麦克风"],"Camera / microphone access required.":["需连接摄像头/麦克风"],"Please check your browser settings and allow camera and microphone access for this site.":["请检查浏览器设置并允许摄像头及麦克风连接此网站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["点击这里获取帮助 (Google Chrome)"],"Please set your user details and settings.":["请设定您的用户信息及设置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天已启动"],"Peer to peer chat is now off.":["P2P现在未启动"]," is now offline.":[" 不在线"]," is now online.":[" 现在在线"],"You share file:":["分享文件:"],"Incoming file:":["发来文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["适用更新需重启,现在点击Ok重新启动。"],"Failed to access camera/microphone.":["摄像头/麦克风连接失败"],"Failed to establish peer connection.":["对等连接建立失败"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有错误发生。"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["对等连接失败,请检查设置。"],"User hung up because of error.":["用户因错误挂断"]," is busy. Try again later.":[" 正在通话,请稍后再试。"]," rejected your call.":[" 拒绝了您的呼叫。"]," does not pick up.":[" 无人接听。"],"Your browser does not support WebRTC. No calls possible.":["您的浏览器不支持WebRTC。不能进行通话。"],"Chat with":["与**聊天"],"Message from ":["来自于**的信息"],"You are now in room %s ...":["您在 %s 房间"],"Your browser does not support file transfer.":["您的浏览器不支持文件传输"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["启动屏幕共享许可被拒绝。请确认您已开启浏览器屏幕共享连接。请复制chrome://flags/#enable-usermedia-screen-capture并用您的浏览器打开,启用最上端的功能。然后重启浏览器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用浏览器语言"],"Meet with me here:":["我们这里见:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["错误"],"Hint":["提示"],"Please confirm":["请确认"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入码"],"Access denied":["连接被拒绝"],"Please provide a valid access code.":["请提供有效接入码"],"Failed to verify access code. Check your Internet connection and try again.":["接入码认证失败。请检查您的网络连接并重试。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用户"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通话音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["开始聊天"],"Start video call":["开始视频通话"],"Start audio conference":["开始语音会议"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待启动摄像头"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["会话"],"Room chat":["房间聊天"],"Peer to peer":["P2P"],"Close chat":["关闭聊天"],"Share my location":[""],"is typing...":["正在输入..."],"has stopped typing...":["停止输入..."],"Type here to chat...":["在此输入开始聊天..."],"Send":["发送"],"Accept":[""],"Reject":["拒绝"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["关闭"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下载"],"Open":["打开"],"Unshare":["停止分享"],"Retry":["重试"],"Download failed.":["下载失败"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["关闭麦克风"],"Turn camera off":["关闭摄像头"],"Settings":["系统设置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更换房间"],"Room":["房间"],"Leave room":["离开房间"],"Main":["主房间"],"Current room":["當前房间"],"Screen sharing options":["屏幕共享设置"],"Fit screen.":["适合屏幕"],"Please select what to share.":[""],"Window":[""],"Application":[""],"Share the whole screen. Click share to select the screen.":[""],"Share a single window. Click share to select the window.":[""],"Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.":[""],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的图片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麦克风"],"Camera":["摄像头"],"Video quality":["视频质量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["语言"],"Language changes become active on reload.":["转换语言需重启程序"],"Default room":["系统默认房间"],"Set alternative room to join at start.":["重设初始默认房间"],"Desktop notification":["桌面提醒"],"Enable":["开启"],"Denied - check your browser settings":["被拒绝--请检查浏览器设置"],"Allowed":["启用"],"Advanced settings":["高级设置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大视频帧速率"],"auto":["自动"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展开高级设置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["记住设置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在线"],"Calling":["呼叫中"],"Hangup":["挂断"],"In call with":["正在和**通话"],"Conference with":["和**会议通话"],"Your are offline":["您不在线"],"Go online":["上线"],"Connection interrupted":["连接已中断"],"An error occured":["出现错误"],"Incoming call":["来电"],"from":["来自"],"Accept call":["接受通话"],"Waiting for camera/microphone access":["等待摄像头/麦克风连接"],"Checking camera and microphone access.":["正在检查摄像头及麦克风连接"],"Please allow access to your camera and microphone.":["请允许连接您的摄像头及麦克风"],"Camera / microphone access required.":["需连接摄像头/麦克风"],"Please check your browser settings and allow camera and microphone access for this site.":["请检查浏览器设置并允许摄像头及麦克风连接此网站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["点击这里获取帮助 (Google Chrome)"],"Please set your user details and settings.":["请设定您的用户信息及设置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天已启动"],"Peer to peer chat is now off.":["P2P现在未启动"]," is now offline.":[" 不在线"]," is now online.":[" 现在在线"],"You share file:":["分享文件:"],"Incoming file:":["发来文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["适用更新需重启,现在点击Ok重新启动。"],"Failed to access camera/microphone.":["摄像头/麦克风连接失败"],"Failed to establish peer connection.":["对等连接建立失败"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有错误发生。"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["对等连接失败,请检查设置。"],"User hung up because of error.":["用户因错误挂断"]," is busy. Try again later.":[" 正在通话,请稍后再试。"]," rejected your call.":[" 拒绝了您的呼叫。"]," does not pick up.":[" 无人接听。"],"Your browser does not support WebRTC. No calls possible.":["您的浏览器不支持WebRTC。不能进行通话。"],"Chat with":["与**聊天"],"Message from ":["来自于**的信息"],"You are now in room %s ...":["您在 %s 房间"],"Your browser does not support file transfer.":["您的浏览器不支持文件传输"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["启动屏幕共享许可被拒绝。请确认您已开启浏览器屏幕共享连接。请复制chrome://flags/#enable-usermedia-screen-capture并用您的浏览器打开,启用最上端的功能。然后重启浏览器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用浏览器语言"],"Meet with me here:":["我们这里见:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["错误"],"Hint":["提示"],"Please confirm":["请确认"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入码"],"Access denied":["连接被拒绝"],"Please provide a valid access code.":["请提供有效接入码"],"Failed to verify access code. Check your Internet connection and try again.":["接入码认证失败。请检查您的网络连接并重试。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用户"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file diff --git a/static/translation/messages-zh-tw.json b/static/translation/messages-zh-tw.json index 5bc5fa81..f5c9e0e4 100644 --- a/static/translation/messages-zh-tw.json +++ b/static/translation/messages-zh-tw.json @@ -1 +1 @@ -{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通話音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["開始聊天"],"Start video call":["開始視頻通話"],"Start audio conference":["開始語音會議"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待啟動攝像頭"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["會話"],"Room chat":["房間聊天"],"Peer to peer":["P2P"],"Close chat":["關閉聊天"],"Share my location":[""],"is typing...":["正在輸入..."],"has stopped typing...":["停止輸入..."],"Type here to chat...":["在此輸入開始聊天..."],"Send":["發送"],"Accept":[""],"Reject":["拒絕"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["關閉"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下載"],"Open":["打開"],"Unshare":["停止分享"],"Retry":["重試"],"Download failed.":["下載失敗"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["關閉麥克風"],"Turn camera off":["關閉攝像頭"],"Settings":["系統設置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更換房間"],"Room":["房間"],"Leave room":["離開房間"],"Main":["住房間"],"Current room":["當前房間"],"Screen sharing options":["屏幕共享設置"],"Fit screen.":["適合屏幕"],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的圖片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麥克風"],"Camera":["攝像頭"],"Video quality":["視頻質量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["語言"],"Language changes become active on reload.":["轉換語言需要重啟程序"],"Default room":["系統默認房間"],"Set alternative room to join at start.":["重設初始默認房間"],"Desktop notification":["桌面提醒"],"Enable":["開啟"],"Denied - check your browser settings":["被拒絕﹣請檢查瀏覽器設置"],"Allowed":["啟用"],"Advanced settings":["高級設置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大視頻幀速率"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展開高級設置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["記住設置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在線"],"Calling":["呼叫中"],"Hangup":["掛斷"],"In call with":["正在和**通電話"],"Conference with":["和**會議通話"],"Your are offline":["您不在線"],"Go online":["上線"],"Connection interrupted":["連接已終端"],"An error occured":["出現錯誤"],"Incoming call":["來電"],"from":["來自"],"Accept call":["接受通話"],"Waiting for camera/microphone access":["等待攝像頭/麥克風連接"],"Checking camera and microphone access.":["正在檢查攝像頭及麥克風連接"],"Please allow access to your camera and microphone.":["請允許連接您的攝像頭及麥克風"],"Camera / microphone access required.":["需連接攝像頭/麥克風"],"Please check your browser settings and allow camera and microphone access for this site.":["請檢查瀏覽器設置並允許攝像頭及麥克風連接此網站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["點擊這裡獲取幫助 (Google Chrome)"],"Please set your user details and settings.":["請設定您的用戶信息及設置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天啟動"],"Peer to peer chat is now off.":["P2P現在未啟動"]," is now offline.":[" 不在線"]," is now online.":[" 現在在線"],"You share file:":["分享文件:"],"Incoming file:":["發來文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["適用更新需重啟,現在點擊Ok重新啟動。"],"Failed to access camera/microphone.":["攝像頭/麥克風連接失敗"],"Failed to establish peer connection.":["對等連接建立失敗"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有序哦嗚發生......"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["對等連接失敗,請檢查設置。"],"User hung up because of error.":["用戶因錯誤掛斷"]," is busy. Try again later.":[" 正在通話,請您稍後。"]," rejected your call.":[" 拒絕了您的呼叫"]," does not pick up.":[" 無人接聽。"],"Your browser does not support WebRTC. No calls possible.":["您的遊覽器不支持WebRTC。不能進行通話。"],"Chat with":["于**聊天"],"Message from ":["來自於**的信息"],"You are now in room %s ...":["您在 %s 房間"],"Your browser does not support file transfer.":["您的遊覽器不支持文件傳輸"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["啟動屏幕共享許可被拒絕。請確認您已開啟瀏覽器屏幕共享連接。請復制chrome://flags/#enable-usermedia-screen-capture並用您的瀏覽器打開,啟用最上端的功能。然後重啟瀏覽器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用瀏覽器語言"],"Meet with me here:":["我們這裡見:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["錯誤"],"Hint":["提示"],"Please confirm":["請確認"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入碼"],"Access denied":["連接被拒絕"],"Please provide a valid access code.":["請提供有效接入碼"],"Failed to verify access code. Check your Internet connection and try again.":["接入碼認證錯誤。請檢查您的網絡連接并重試。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用戶"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file +{"domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural_forms":"nplurals=1; plural=0"},"Your audio level":["您的通話音量"],"Standard view":[""],"Large view":[""],"Kiosk view":[""],"Auditorium":[""],"Start chat":["開始聊天"],"Start video call":["開始視頻通話"],"Start audio conference":["開始語音會議"],"No one else here":[""],"Take":[""],"Retake":[""],"Cancel":["取消"],"Set as Profile Picture":[""],"Take picture":["拍照"],"Waiting for camera":["等待啟動攝像頭"],"The file couldn't be read.":[""],"The file is not an image.":[""],"The file is too large. Max. %d MB.":[""],"Select file":[""],"Chat sessions":["會話"],"Room chat":["房間聊天"],"Peer to peer":["P2P"],"Close chat":["關閉聊天"],"Share my location":[""],"is typing...":["正在輸入..."],"has stopped typing...":["停止輸入..."],"Type here to chat...":["在此輸入開始聊天..."],"Send":["發送"],"Accept":[""],"Reject":["拒絕"],"You have no contacts.":[""],"To add new contacts, join a room and create a contact add request by clicking on the star icon next to a user entry.":[""],"Edit contact":[""],"Edit":[""],"Name":["名字"],"Remove":[""],"Refresh":[""],"Save":[""],"Close":["關閉"],"File sharing":["分享文件"],"File is no longer available":["文件已不存在"],"Download":["下載"],"Open":["打開"],"Unshare":["停止分享"],"Retry":["重試"],"Download failed.":["下載失敗"],"Share a YouTube video":[""],"Share a file as presentation":[""],"Share your screen":["共享您的屏幕"],"Chat":["聊天"],"Contacts":[""],"Mute microphone":["關閉麥克風"],"Turn camera off":["關閉攝像頭"],"Settings":["系統設置"],"Loading presentation ...":[""],"Please upload a document":[""],"Documents are shared with everyone in this call. The supported file types are PDF and OpenDocument files.":[""],"Upload":[""],"You can drag files here too.":[""],"Presentation controls":[""],"Prev":[""],"Next":[""],"Change room":["更換房間"],"Room":["房間"],"Leave room":["離開房間"],"Main":["住房間"],"Current room":["當前房間"],"Screen sharing options":["屏幕共享設置"],"Fit screen.":["適合屏幕"],"Please select what to share.":[""],"Window":[""],"Application":[""],"Share the whole screen. Click share to select the screen.":[""],"Share a single window. Click share to select the window.":[""],"Share all windows of a application. This can leak content behind windows when windows get moved. Click share to select the application.":[""],"Profile":[""],"Your name":["您的名字"],"Your picture":["您的圖片"],"Status message":[""],"What's on your mind?":[""],"Your picture, name and status message identify yourself in calls, chats and rooms.":[""],"Your ID":[""],"Register":[""],"Authenticated by certificate. To log out you have to remove your certificate from the browser.":[""],"Sign in":[""],"Create an account":[""],"Sign out":[""],"Manage account":[""],"Media":[""],"Microphone":["麥克風"],"Camera":["攝像頭"],"Video quality":["視頻質量"],"Low":["低"],"High":["高"],"HD":["高清"],"Full HD":[""],"General":[""],"Language":["語言"],"Language changes become active on reload.":["轉換語言需要重啟程序"],"Default room":["系統默認房間"],"Set alternative room to join at start.":["重設初始默認房間"],"Desktop notification":["桌面提醒"],"Enable":["開啟"],"Denied - check your browser settings":["被拒絕﹣請檢查瀏覽器設置"],"Allowed":["啟用"],"Advanced settings":["高級設置"],"Play audio on same device as selected microphone":[""],"Experimental AEC":[""],"Experimental AGC":[""],"Experimental noise suppression":[""],"Max video frame rate":["最大視頻幀速率"],"auto":["自動"],"Sending stereo audio disables echo cancellation. Enable only if you have stereo input.":[""],"Detect CPU over use":[""],"Automatically reduces video quality as needed.":[""],"Optimize for high resolution video":[""],"Reduce video noise":[""],"Enable experiments":[""],"Show advanced settings":["展開高級設置"],"Hide advanced settings":["隐藏高级设置"],"Remember settings":["記住設置"],"Your ID will still be kept - press the log out button above to delete the ID.":[""],"Room link":[""],"Invite with Facebook":[""],"Invite with Twitter":[""],"Invite with Google Plus":[""],"Invite with XING":[""],"Initializing":["初始化"],"Online":["在線"],"Calling":["呼叫中"],"Hangup":["掛斷"],"In call with":["正在和**通電話"],"Conference with":["和**會議通話"],"Your are offline":["您不在線"],"Go online":["上線"],"Connection interrupted":["連接已終端"],"An error occured":["出現錯誤"],"Incoming call":["來電"],"from":["來自"],"Accept call":["接受通話"],"Waiting for camera/microphone access":["等待攝像頭/麥克風連接"],"Checking camera and microphone access.":["正在檢查攝像頭及麥克風連接"],"Please allow access to your camera and microphone.":["請允許連接您的攝像頭及麥克風"],"Camera / microphone access required.":["需連接攝像頭/麥克風"],"Please check your browser settings and allow camera and microphone access for this site.":["請檢查瀏覽器設置並允許攝像頭及麥克風連接此網站"],"Skip check":["越过检查"],"Click here for help (Google Chrome).":["點擊這裡獲取幫助 (Google Chrome)"],"Please set your user details and settings.":["請設定您的用戶信息及設置"],"Enter a room name":[""],"Random room name":[""],"Enter the name of an existing room. You can create new rooms when you are signed in.":[""],"Room history":[""],"Please sign in.":[""],"Videos play simultaneously for everyone in this call.":[""],"YouTube URL":[""],"Could not load YouTube player API, please check your network / firewall settings.":[""],"Currently playing":[""],"YouTube controls":[""],"YouTube video to share":[""],"Peer to peer chat active.":["P2P聊天啟動"],"Peer to peer chat is now off.":["P2P現在未啟動"]," is now offline.":[" 不在線"]," is now online.":[" 現在在線"],"You share file:":["分享文件:"],"Incoming file:":["發來文件:"],"You shared your location:":[""],"Location received:":[""],"You accepted the contact request.":[""],"You rejected the contact request.":[""],"You sent a contact request.":[""],"Your contact request was accepted.":[""],"Incoming contact request.":[""],"Your contact request was rejected.":[""],"Edit Contact":[""],"Close this window and disconnect?":[""],"Contacts Manager":[""],"Restart required to apply updates. Click ok to restart now.":["適用更新需重啟,現在點擊Ok重新啟動。"],"Failed to access camera/microphone.":["攝像頭/麥克風連接失敗"],"Failed to establish peer connection.":["對等連接建立失敗"],"We are sorry but something went wrong. Boo boo.":["很抱歉,有序哦嗚發生......"],"Oops":["Oops"],"Peer connection failed. Check your settings.":["對等連接失敗,請檢查設置。"],"User hung up because of error.":["用戶因錯誤掛斷"]," is busy. Try again later.":[" 正在通話,請您稍後。"]," rejected your call.":[" 拒絕了您的呼叫"]," does not pick up.":[" 無人接聽。"],"Your browser does not support WebRTC. No calls possible.":["您的遊覽器不支持WebRTC。不能進行通話。"],"Chat with":["于**聊天"],"Message from ":["來自於**的信息"],"You are now in room %s ...":["您在 %s 房間"],"Your browser does not support file transfer.":["您的遊覽器不支持文件傳輸"],"Could not load PDF: Please make sure to select a PDF document.":[""],"Could not load PDF: Missing PDF file.":[""],"An error occurred while loading the PDF (%s).":[""],"An unknown error occurred while loading the PDF.":[""],"An error occurred while loading the PDF page (%s).":[""],"An unknown error occurred while loading the PDF page.":[""],"An error occurred while rendering the PDF page (%s).":[""],"An unknown error occurred while rendering the PDF page.":[""],"Only PDF documents and OpenDocument files can be shared at this time.":[""],"Failed to start screen sharing (%s).":[""],"Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go.":["啟動屏幕共享許可被拒絕。請確認您已開啟瀏覽器屏幕共享連接。請復制chrome://flags/#enable-usermedia-screen-capture並用您的瀏覽器打開,啟用最上端的功能。然後重啟瀏覽器,操作完成。"],"Permission to start screen sharing was denied.":[""],"Use browser language":["使用瀏覽器語言"],"Meet with me here:":["我們這裡見:"],"Unknown URL format. Please make sure to enter a valid YouTube URL.":[""],"Error":["錯誤"],"Hint":["提示"],"Please confirm":["請確認"],"More information required":["需要更多信息"],"Ok":["Ok"],"Screen sharing requires a browser extension. Please add the Spreed WebRTC screen sharing extension to Chrome and try again.":[""],"Access code required":["需要接入碼"],"Access denied":["連接被拒絕"],"Please provide a valid access code.":["請提供有效接入碼"],"Failed to verify access code. Check your Internet connection and try again.":["接入碼認證錯誤。請檢查您的網絡連接并重試。"],"PIN for room %s is now '%s'.":[""],"PIN lock has been removed from room %s.":[""],"Enter the PIN for room %s":[""],"Please sign in to create rooms.":[""],"and %s":[""],"and %d others":[""],"User":["用戶"],"Someone":["某人"],"Me":["我"]}}} \ No newline at end of file From bb6200444b14160784fd708259e528bfa5cb9a7e Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 14 Apr 2015 14:42:40 +0200 Subject: [PATCH 030/121] Minimal po2json version is 0.4.1 to support updated jed. --- README.md | 2 +- configure.ac | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58622c80..a3f9f712 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ locally by running `npm install` from the project root. Consult the `package.json` file for more details. - [autoprefixer](https://www.npmjs.org/package/autoprefixer) >= 1.1 - - [po2json](https://github.com/mikeedwards/po2json) + - [po2json](https://github.com/mikeedwards/po2json) >= 0.4.1 - [JSHint](http://www.jshint.com/) >= 2.0.0 - [scss-lint](https://github.com/causes/scss-lint) >= 0.33.0 diff --git a/configure.ac b/configure.ac index bb66d12a..a068e3f0 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,7 @@ NODEJS_VERSION_MIN=0.6.0 NODEJS_VERSION_STYLES_MIN=0.10.0 SASS_VERSION_MIN=3.3.0 SCSS_LINT_VERSION_MIN=0.33.0 +PO2JSON_VERSION_MIN=0.4.1 AC_CONFIG_SRCDIR([src/app/spreed-webrtc-server/main.go]) AC_CONFIG_MACRO_DIR([m4]) @@ -183,9 +184,11 @@ if test x"${NPM}" != x"" ; then else AC_MSG_RESULT([ok]) AC_MSG_CHECKING([for version of po2json]) - PO2JSON_VERSION=`{ $NPM list --global & $NPM list; } 2>&1 | $GREP -v 'required' | $GREP po2json@ | $SED 's/^.*po2json@//'` + PO2JSON_VERSION=`{ $NPM list --global & $NPM list; } 2>&1 | $GREP -v 'required' | $GREP po2json@ | tail -n1 | $SED 's/^.*po2json@//'` AC_MSG_RESULT([$PO2JSON_VERSION]) - NODEJS_SUPPORT_PO2JSON=yes + AX_COMPARE_VERSION([$PO2JSON_VERSION], [lt], [$PO2JSON_VERSION_MIN], + [AC_MSG_WARN([Please install po2json version $PO2JSON_VERSION_MIN or newer before trying to build translations (found po2json $PO2JSON_VERSION).]) + NODEJS_SUPPORT_PO2JSON=no],[NODEJS_SUPPORT_PO2JSON=yes]) fi else AC_MSG_WARN([Please install npm and the the node.js module po2json to build i18n.]) From cb0ade48df019e27160f881f6aa90f3341ef7b6c Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 14 Apr 2015 15:02:54 +0200 Subject: [PATCH 031/121] Added conversion for older po2json generated files. --- static/js/app.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/static/js/app.js b/static/js/app.js index 488e1ce6..2368ba11 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -87,6 +87,22 @@ define([ var src; if (data && data.locale_data) { src = data.locale_data[domain]; + // Support older po files built for older jed (see https://github.com/SlexAxton/Jed/issues/36). + var count = 0; + var v; + for (var k in src) { + if (src.hasOwnProperty(k)) { + v = src[k]; + if (v.constructor === Array && v[0] === null) { + v.shift(); + } else { + count++; + } + if (count > 1) { + break; + } + } + } } var dst = this.data.locale_data[domain]; if (!dst) { From 1d031b71ca897007a8a27fa81bdfa4dd670bd4c8 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 14:31:44 +0200 Subject: [PATCH 032/121] Fixed missing chat envelope which got lost in 56aa603293f70f99c832feeef47c254ea7edde04. --- .../spreed-webrtc-server/channelling_api.go | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index f16bb7e1..9fccf764 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -133,7 +133,7 @@ func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *Data break } - api.HandleChat(session, msg.Chat.To, msg.Chat.Chat) + api.HandleChat(session, msg.Chat) case "Conference": if msg.Conference == nil { log.Println("Received invalid conference message.", msg) @@ -224,12 +224,15 @@ func (api *channellingAPI) HandleAuthentication(session *Session, st *SessionTok return self, err } -func (api *channellingAPI) HandleChat(session *Session, to string, chat *DataChatMessage) { +func (api *channellingAPI) HandleChat(session *Session, chat *DataChat) { // TODO(longsleep): Limit sent chat messages per incoming connection. - if !chat.NoEcho { + msg := chat.Chat + to := chat.To + + if !msg.NoEcho { session.Unicast(session.Id, chat) } - chat.Time = time.Now().Format(time.RFC3339) + msg.Time = time.Now().Format(time.RFC3339) if to == "" { // TODO(longsleep): Check if chat broadcast is allowed. if session.Hello { @@ -237,25 +240,25 @@ func (api *channellingAPI) HandleChat(session *Session, to string, chat *DataCha session.Broadcast(chat) } } else { - if chat.Status != nil { - if chat.Status.ContactRequest != nil { + if msg.Status != nil { + if msg.Status.ContactRequest != nil { if !api.Config.WithModule("contacts") { return } - if err := api.contactrequestHandler(session, to, chat.Status.ContactRequest); err != nil { + if err := api.contactrequestHandler(session, to, msg.Status.ContactRequest); err != nil { log.Println("Ignoring invalid contact request.", err) return } - chat.Status.ContactRequest.Userid = session.Userid() + msg.Status.ContactRequest.Userid = session.Userid() } } else { api.CountUnicastChat() } session.Unicast(to, chat) - if chat.Mid != "" { + if msg.Mid != "" { // Send out delivery confirmation status chat message. - session.Unicast(session.Id, &DataChat{To: to, Type: "Chat", Chat: &DataChatMessage{Mid: chat.Mid, Status: &DataChatStatus{State: "sent"}}}) + session.Unicast(session.Id, &DataChat{To: to, Type: "Chat", Chat: &DataChatMessage{Mid: msg.Mid, Status: &DataChatStatus{State: "sent"}}}) } } } From 98487861454e82e4f445c21cd0db0f7174abcae1 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 19:01:57 +0200 Subject: [PATCH 033/121] First step in getting rid of the huge mediastreamcontroller. --- html/logo.html | 1 - html/main.html | 53 +-------- static/js/app.js | 3 +- static/js/controllers/appcontroller.js | 105 ++++++++++++++++ static/js/controllers/controllers.js | 6 +- .../js/controllers/mediastreamcontroller.js | 112 +++--------------- static/js/directives/directives.js | 6 +- static/js/directives/ui.js | 38 ++++++ static/partials/ui.html | 52 ++++++++ 9 files changed, 223 insertions(+), 153 deletions(-) delete mode 100644 html/logo.html create mode 100644 static/js/controllers/appcontroller.js create mode 100644 static/js/directives/ui.js create mode 100644 static/partials/ui.html diff --git a/html/logo.html b/html/logo.html deleted file mode 100644 index 22c2622a..00000000 --- a/html/logo.html +++ /dev/null @@ -1 +0,0 @@ -<%define "logo"%><%end%> diff --git a/html/main.html b/html/main.html index f485bc1d..c61eee94 100644 --- a/html/main.html +++ b/html/main.html @@ -6,57 +6,8 @@
- - -
- -
-
-
-
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
+ <%template "extra-body" .%> -<%end%> +<%end%> \ No newline at end of file diff --git a/static/js/app.js b/static/js/app.js index 2368ba11..ca3992d0 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -190,7 +190,8 @@ define([ app.directive("spreedWebrtc", [function() { return { restrict: "A", - controller: "MediastreamController" + scope: false, + controller: "AppController" } }]); diff --git a/static/js/controllers/appcontroller.js b/static/js/controllers/appcontroller.js new file mode 100644 index 00000000..0c5d48cf --- /dev/null +++ b/static/js/controllers/appcontroller.js @@ -0,0 +1,105 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +"use strict"; +define(["jquery", "angular", "underscore"], function($, angular, _) { + + // AppController + return ["$scope", "$window", "appData", "userSettingsData", function($scope, $window, appData, userSettingsData) { + + // Disable drag and drop. + $($window).on("dragover dragenter drop", function(event) { + event.preventDefault(); + }); + + appData.set($scope); + + // User related scope data. + $scope.roomsHistory = []; + $scope.defaults = { + displayName: null, + buddyPicture: null, + message: null, + settings: { + videoQuality: "high", + sendStereo: false, + maxFrameRate: 20, + defaultRoom: "", + language: "", + audioRenderToAssociatedSkin: true, + videoCpuOveruseDetection: true, + experimental: { + enabled: false, + audioEchoCancellation2: true, + audioAutoGainControl2: true, + audioNoiseSuppression2: true, + audioTypingNoiseDetection: true, + videoLeakyBucket: true, + videoNoiseReduction: false + } + } + }; + $scope.master = angular.copy($scope.defaults); + + $scope.update = function(user) { + $scope.master = angular.copy(user); + if (appData.flags.connected) { + $scope.updateStatus(); + } + $scope.refreshWebrtcSettings(); + }; + + $scope.reset = function() { + $scope.user = angular.copy($scope.master); + }; + + $scope.loadUserSettings = function() { + $scope.master = angular.copy($scope.defaults); + var storedUser = userSettingsData.load(); + if (storedUser) { + $scope.user = $.extend(true, {}, $scope.master, storedUser); + $scope.user.settings = $.extend(true, {}, $scope.user.settings, $scope.master.settings, $scope.user.settings); + $scope.update($scope.user); + $scope.loadedUser = storedUser.displayName && true; + } else { + $scope.loadedUser = false; + } + $scope.roomsHistory = []; + appData.e.triggerHandler("userSettingsLoaded", [$scope.loadedUser, $scope.user]); + $scope.reset(); + }; + + $scope.$on("room.joined", function(event, roomName) { + if (roomName) { + _.pull($scope.roomsHistory, roomName); + $scope.roomsHistory.unshift(roomName); + if ($scope.roomsHistory.length > 15) { + // Limit the history. + $scope.roomsHistory = $scope.roomsHistory.splice(0, 15); + } + } + }); + + $scope.reset(); // Call once for bootstrap. + + }]; + +}); \ No newline at end of file diff --git a/static/js/controllers/controllers.js b/static/js/controllers/controllers.js index 10d51949..57c25a0c 100644 --- a/static/js/controllers/controllers.js +++ b/static/js/controllers/controllers.js @@ -28,7 +28,8 @@ define([ 'controllers/chatroomcontroller', 'controllers/usersettingscontroller', 'controllers/contactsmanagercontroller', - 'controllers/contactsmanagereditcontroller'], function(_, MediastreamController, StatusmessageController, ChatroomController, UsersettingsController, ContactsmanagerController, ContactsmanagereditController) { + 'controllers/contactsmanagereditcontroller', + 'controllers/appcontroller'], function(_, MediastreamController, StatusmessageController, ChatroomController, UsersettingsController, ContactsmanagerController, ContactsmanagereditController, AppController) { var controllers = { MediastreamController: MediastreamController, @@ -36,7 +37,8 @@ define([ ChatroomController: ChatroomController, UsersettingsController: UsersettingsController, ContactsmanagerController: ContactsmanagerController, - ContactsmanagereditController: ContactsmanagereditController + ContactsmanagereditController: ContactsmanagereditController, + AppController: AppController }; var initialize = function(angModule) { diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index c8e931ee..2876a06f 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -20,16 +20,9 @@ */ "use strict"; -define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapter'], function($, _, angular, BigScreen, moment, sjcl, Modernizr) { +define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'webrtc.adapter'], function($, _, BigScreen, moment, sjcl, Modernizr) { - return ["$scope", "$rootScope", "$element", "$window", "$timeout", "safeDisplayName", "safeApply", "mediaStream", "appData", "playSound", "desktopNotify", "alertify", "toastr", "translation", "fileDownload", "localStorage", "screensharing", "userSettingsData", "localStatus", "dialogs", "rooms", "constraints", function($scope, $rootScope, $element, $window, $timeout, safeDisplayName, safeApply, mediaStream, appData, playSound, desktopNotify, alertify, toastr, translation, fileDownload, localStorage, screensharing, userSettingsData, localStatus, dialogs, rooms, constraints) { - - /*console.log("route", $route, $routeParams, $location);*/ - - // Disable drag and drop. - $($window).on("dragover dragenter drop", function(event) { - event.preventDefault(); - }); + return ["$scope", "$rootScope", "$element", "$window", "$timeout", "safeDisplayName", "safeApply", "mediaStream", "appData", "playSound", "desktopNotify", "alertify", "toastr", "translation", "fileDownload", "localStorage", "screensharing", "localStatus", "dialogs", "rooms", "constraints", function($scope, $rootScope, $element, $window, $timeout, safeDisplayName, safeApply, mediaStream, appData, playSound, desktopNotify, alertify, toastr, translation, fileDownload, localStorage, screensharing, localStatus, dialogs, rooms, constraints) { // Avoid accidential reloads or exits when in a call. var manualUnload = false; @@ -93,8 +86,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder "prompt": "question1" }); - appData.set($scope); - var displayName = safeDisplayName; // Init STUN from server config. @@ -112,7 +103,7 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder $scope.supported = { screensharing: screensharing.supported, constraints: constraints.supported - } + }; // Default scope data. $scope.status = "initializing"; @@ -132,50 +123,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder $scope.chatMessagesUnseen = 0; $scope.autoAccept = null; $scope.isCollapsed = true; - $scope.roomsHistory = []; - $scope.defaults = { - displayName: null, - buddyPicture: null, - message: null, - settings: { - videoQuality: "high", - sendStereo: false, - maxFrameRate: 20, - defaultRoom: "", - language: "", - audioRenderToAssociatedSkin: true, - videoCpuOveruseDetection: true, - experimental: { - enabled: false, - audioEchoCancellation2: true, - audioAutoGainControl2: true, - audioNoiseSuppression2: true, - audioTypingNoiseDetection: true, - videoLeakyBucket: true, - videoNoiseReduction: false - } - } - }; - $scope.master = angular.copy($scope.defaults); - - // Data voids. - var resurrect = null; - var reconnecting = false; - var connected = false; - var autoreconnect = true; - - $scope.update = function(user) { - $scope.master = angular.copy(user); - if (connected) { - $scope.updateStatus(); - } - $scope.refreshWebrtcSettings(); - }; - - $scope.reset = function() { - $scope.user = angular.copy($scope.master); - }; - $scope.reset(); // Call once for bootstrap. $scope.setStatus = function(status) { // This is the connection status to signaling server. @@ -242,22 +189,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder } }; - $scope.loadUserSettings = function() { - $scope.master = angular.copy($scope.defaults); - var storedUser = userSettingsData.load(); - if (storedUser) { - $scope.user = $.extend(true, {}, $scope.master, storedUser); - $scope.user.settings = $.extend(true, {}, $scope.user.settings, $scope.master.settings, $scope.user.settings); - $scope.update($scope.user); - $scope.loadedUser = storedUser.displayName && true; - } else { - $scope.loadedUser = false; - } - $scope.roomsHistory = []; - appData.e.triggerHandler("userSettingsLoaded", [$scope.loadedUser, $scope.user]); - $scope.reset(); - }; - $scope.toggleBuddylist = (function() { var oldState = null; return function(status, force) { @@ -364,9 +295,9 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder } // Support resurrection shrine. - if (resurrect) { - var resurrection = resurrect; - resurrect = null; + if (appData.flags.resurrect) { + var resurrection = appData.flags.resurrect; + appData.flags.resurrect = null; $timeout(function() { if (resurrection.id === $scope.id) { console.log("Using resurrection shrine", resurrection); @@ -490,23 +421,23 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder }); var reconnect = function() { - if (connected && autoreconnect) { - if (resurrect === null) { + if (appData.flags.connected && appData.flags.autoreconnect) { + if (appData.flags.resurrect === null) { // Storage data at the resurrection shrine. - resurrect = { + appData.flags.resurrect = { status: $scope.getStatus(), id: $scope.id } - console.log("Stored data at the resurrection shrine", resurrect); + console.log("Stored data at the resurrection shrine", appData.flags.resurrect); } - if (!reconnecting) { - reconnecting = true; + if (!appData.flags.reconnecting) { + appData.flags.reconnecting = true; _.delay(function() { - if (autoreconnect) { + if (appData.flags.autoreconnect) { console.log("Requesting to reconnect ..."); mediaStream.reconnect(); } - reconnecting = false; + appData.flags.reconnecting = false; }, 500); $scope.setStatus("reconnecting"); } else { @@ -526,12 +457,12 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder $scope.userid = $scope.suserid = null; switch (event.type) { case "open": - connected = true; + appData.flags.connected = true; $scope.updateStatus(true); $scope.setStatus("waiting"); break; case "error": - if (connected) { + if (appData.flags.connected) { reconnect(); } else { $scope.setStatus(event.type); @@ -768,17 +699,6 @@ define(['jquery', 'underscore', 'angular', 'bigscreen', 'moment', 'sjcl', 'moder $scope.chatMessagesUnseen = $scope.chatMessagesUnseen - count; }); - $scope.$on("room.joined", function(event, roomName) { - if (roomName) { - _.pull($scope.roomsHistory, roomName); - $scope.roomsHistory.unshift(roomName); - if ($scope.roomsHistory.length > 15) { - // Limit the history. - $scope.roomsHistory = $scope.roomsHistory.splice(0, 15); - } - } - }); - _.defer(function() { if (!Modernizr.websockets) { alertify.dialog.alert(translation._("Your browser is not supported. Please upgrade to a current version.")); diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index b0a110ec..ad556a4e 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -48,7 +48,8 @@ define([ 'directives/bfi', 'directives/title', 'directives/welcome', - 'directives/menu'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, buddyPictureUpload, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo, bfi, title, welcome, menu) { + 'directives/menu', + 'directives/ui'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, buddyPictureUpload, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo, bfi, title, welcome, menu, ui) { var directives = { onEnter: onEnter, @@ -76,7 +77,8 @@ define([ bfi: bfi, title: title, welcome: welcome, - menu: menu + menu: menu, + ui: ui }; var initialize = function(angModule) { diff --git a/static/js/directives/ui.js b/static/js/directives/ui.js new file mode 100644 index 00000000..2d7d81fe --- /dev/null +++ b/static/js/directives/ui.js @@ -0,0 +1,38 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +"use strict"; +define(['text!partials/ui.html'], function(template) { + + // ui + return [function() { + + return { + restrict: 'E', + replace: true, + scope: false, + controller: 'MediastreamController', + template: template + } + + }]; + +}); diff --git a/static/partials/ui.html b/static/partials/ui.html new file mode 100644 index 00000000..648c20ba --- /dev/null +++ b/static/partials/ui.html @@ -0,0 +1,52 @@ +
+ + +
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+ \ No newline at end of file From ac24895d94609bed00427694331a3364c0c3f881 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 10:38:34 +0200 Subject: [PATCH 034/121] Moved more stuff to appcontroller. --- static/js/controllers/appcontroller.js | 14 +++++++++++++- static/js/controllers/mediastreamcontroller.js | 15 +-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/static/js/controllers/appcontroller.js b/static/js/controllers/appcontroller.js index 0c5d48cf..6561a82d 100644 --- a/static/js/controllers/appcontroller.js +++ b/static/js/controllers/appcontroller.js @@ -23,7 +23,7 @@ define(["jquery", "angular", "underscore"], function($, angular, _) { // AppController - return ["$scope", "$window", "appData", "userSettingsData", function($scope, $window, appData, userSettingsData) { + return ["$scope", "$window", "appData", "userSettingsData", "$timeout", function($scope, $window, appData, userSettingsData, $timeout) { // Disable drag and drop. $($window).on("dragover dragenter drop", function(event) { @@ -87,6 +87,18 @@ define(["jquery", "angular", "underscore"], function($, angular, _) { $scope.reset(); }; + $scope.manualReloadApp = function(url) { + appData.flags.manualUnload = true; + if (url) { + $window.location.href = url; + $timeout(function() { + appData.flags.manualUnload = false; + }, 0); + } else { + $window.location.reload(true); + } + }; + $scope.$on("room.joined", function(event, roomName) { if (roomName) { _.pull($scope.roomsHistory, roomName); diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index 2876a06f..85e13f72 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -25,9 +25,8 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web return ["$scope", "$rootScope", "$element", "$window", "$timeout", "safeDisplayName", "safeApply", "mediaStream", "appData", "playSound", "desktopNotify", "alertify", "toastr", "translation", "fileDownload", "localStorage", "screensharing", "localStatus", "dialogs", "rooms", "constraints", function($scope, $rootScope, $element, $window, $timeout, safeDisplayName, safeApply, mediaStream, appData, playSound, desktopNotify, alertify, toastr, translation, fileDownload, localStorage, screensharing, localStatus, dialogs, rooms, constraints) { // Avoid accidential reloads or exits when in a call. - var manualUnload = false; $($window).on("beforeunload", function(event) { - if (manualUnload || !$scope.peer) { + if (appData.flags.manualUnload || !$scope.peer) { return; } return translation._("Close this window and disconnect?"); @@ -177,18 +176,6 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web }; - $scope.manualReloadApp = function(url) { - manualUnload = true; - if (url) { - $window.location.href = url; - $timeout(function() { - manualUnload = false; - }, 0); - } else { - $window.location.reload(true); - } - }; - $scope.toggleBuddylist = (function() { var oldState = null; return function(status, force) { From 3b52da2d821ac21828bcca097c006a0001b7c077 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 10:55:05 +0200 Subject: [PATCH 035/121] Added increasing delay on reconnect to avoid killing slow browsers by reconnecting too fast. Reconnect delay now goes up to 10 seconds in 500 ms steps. --- static/js/controllers/mediastreamcontroller.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/mediastreamcontroller.js index 85e13f72..65622969 100644 --- a/static/js/controllers/mediastreamcontroller.js +++ b/static/js/controllers/mediastreamcontroller.js @@ -407,6 +407,9 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web alertify.dialog.alert(translation._("Oops") + "
" + message); }); + appData.flags.autoreconnect = true; + appData.flags.autoreconnectDelay = 0; + var reconnect = function() { if (appData.flags.connected && appData.flags.autoreconnect) { if (appData.flags.resurrect === null) { @@ -418,6 +421,10 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web console.log("Stored data at the resurrection shrine", appData.flags.resurrect); } if (!appData.flags.reconnecting) { + var delay = appData.flags.autoreconnectDelay; + if (delay < 10000) { + appData.flags.autoreconnectDelay += 500; + } appData.flags.reconnecting = true; _.delay(function() { if (appData.flags.autoreconnect) { @@ -425,7 +432,7 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web mediaStream.reconnect(); } appData.flags.reconnecting = false; - }, 500); + }, delay); $scope.setStatus("reconnecting"); } else { console.warn("Already reconnecting ..."); @@ -445,6 +452,7 @@ define(['jquery', 'underscore', 'bigscreen', 'moment', 'sjcl', 'modernizr', 'web switch (event.type) { case "open": appData.flags.connected = true; + appData.flags.autoreconnectDelay = 0; $scope.updateStatus(true); $scope.setStatus("waiting"); break; From fff50faa2d62bddb1dacd37992c249bd9463966d Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 14:36:22 +0200 Subject: [PATCH 036/121] Bring back title attribute on logo. --- static/js/app.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/static/js/app.js b/static/js/app.js index ca3992d0..2317b38f 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -195,6 +195,15 @@ define([ } }]); + app.directive("uiLogo", ["globalContext", function(globalContext) { + return { + restrict: "A", + link: function($scope, $element, $attrs) { + $attrs.$set("title", globalContext.Cfg.Title || ""); + } + } + }]); + return app; }; From 0a44f596bf73052aa2b3110822e1a7dbcb9ede97 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 14:02:17 +0200 Subject: [PATCH 037/121] Implemented room types. --- src/app/spreed-webrtc-server/channelling.go | 8 ++-- .../spreed-webrtc-server/channelling_api.go | 8 +++- src/app/spreed-webrtc-server/room_manager.go | 40 +++++++++++++------ src/app/spreed-webrtc-server/roomworker.go | 24 +++++++---- src/app/spreed-webrtc-server/session.go | 5 ++- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/app/spreed-webrtc-server/channelling.go b/src/app/spreed-webrtc-server/channelling.go index 5099b114..c05dcf8e 100644 --- a/src/app/spreed-webrtc-server/channelling.go +++ b/src/app/spreed-webrtc-server/channelling.go @@ -42,7 +42,9 @@ type DataRoomCredentials struct { type DataHello struct { Version string Ua string - Id string + Id string // Compatibility with old clients. + Name string // Room name. + Type string // Room type. Credentials *DataRoomCredentials } @@ -53,8 +55,8 @@ type DataWelcome struct { } type DataRoom struct { - Type string - Name string + Type string // Room type. + Name string // Room name. Credentials *DataRoomCredentials } diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index 9fccf764..958e9a9b 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -189,7 +189,13 @@ func (api *channellingAPI) HandleHello(session *Session, hello *DataHello, sende // TODO(longsleep): Filter room id and user agent. session.Update(&SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua}) - room, err := session.JoinRoom(hello.Id, hello.Credentials, sender) + // Compatibily for old clients. + roomName := hello.Name + if roomName == "" { + roomName = hello.Id + } + + room, err := session.JoinRoom(roomName, hello.Type, hello.Credentials, sender) if err != nil { return nil, err } diff --git a/src/app/spreed-webrtc-server/room_manager.go b/src/app/spreed-webrtc-server/room_manager.go index 01bd9094..1d221c2c 100644 --- a/src/app/spreed-webrtc-server/room_manager.go +++ b/src/app/spreed-webrtc-server/room_manager.go @@ -22,15 +22,17 @@ package main import ( + "fmt" "log" "sync" ) type RoomStatusManager interface { RoomUsers(*Session) []*DataSession - JoinRoom(roomID string, credentials *DataRoomCredentials, session *Session, sessionAuthenticated bool, sender Sender) (*DataRoom, error) + JoinRoom(roomID, roomName, roomType string, credentials *DataRoomCredentials, session *Session, sessionAuthenticated bool, sender Sender) (*DataRoom, error) LeaveRoom(roomID, sessionID string) UpdateRoom(*Session, *DataRoom) (*DataRoom, error) + MakeRoomID(roomName, roomType string) string } type Broadcaster interface { @@ -51,16 +53,25 @@ type roomManager struct { sync.RWMutex *Config OutgoingEncoder - roomTable map[string]RoomWorker + roomTable map[string]RoomWorker + globalRoomID string + defaultRoomID string + roomTypeDefault string } func NewRoomManager(config *Config, encoder OutgoingEncoder) RoomManager { - return &roomManager{ + rm := &roomManager{ sync.RWMutex{}, config, encoder, make(map[string]RoomWorker), + "", + "", + "Room", } + rm.globalRoomID = rm.MakeRoomID(config.globalRoomID, "") + rm.defaultRoomID = rm.MakeRoomID("", "") + return rm } func (rooms *roomManager) RoomUsers(session *Session) []*DataSession { @@ -71,12 +82,12 @@ func (rooms *roomManager) RoomUsers(session *Session) []*DataSession { return []*DataSession{} } -func (rooms *roomManager) JoinRoom(roomID string, credentials *DataRoomCredentials, session *Session, sessionAuthenticated bool, sender Sender) (*DataRoom, error) { - if roomID == "" && !rooms.DefaultRoomEnabled { +func (rooms *roomManager) JoinRoom(roomID, roomName, roomType string, credentials *DataRoomCredentials, session *Session, sessionAuthenticated bool, sender Sender) (*DataRoom, error) { + if roomID == rooms.defaultRoomID && !rooms.DefaultRoomEnabled { return nil, NewDataError("default_room_disabled", "The default room is not enabled") } - roomWorker, err := rooms.GetOrCreate(roomID, credentials, sessionAuthenticated) + roomWorker, err := rooms.GetOrCreate(roomID, roomName, roomType, credentials, sessionAuthenticated) if err != nil { return nil, err } @@ -91,12 +102,10 @@ func (rooms *roomManager) LeaveRoom(roomID, sessionID string) { } func (rooms *roomManager) UpdateRoom(session *Session, room *DataRoom) (*DataRoom, error) { - if !session.Hello || session.Roomid != room.Name { + roomID := rooms.MakeRoomID(room.Name, room.Type) + if !session.Hello || session.Roomid != roomID { return nil, NewDataError("not_in_room", "Cannot update other rooms") } - // XXX(lcooper): We'll process and send documents without this field - // correctly, however clients cannot not handle it currently. - room.Type = "Room" if roomWorker, ok := rooms.Get(session.Roomid); ok { return room, roomWorker.Update(room) } @@ -145,7 +154,7 @@ func (rooms *roomManager) Get(roomID string) (room RoomWorker, ok bool) { return } -func (rooms *roomManager) GetOrCreate(roomID string, credentials *DataRoomCredentials, sessionAuthenticated bool) (RoomWorker, error) { +func (rooms *roomManager) GetOrCreate(roomID, roomName, roomType string, credentials *DataRoomCredentials, sessionAuthenticated bool) (RoomWorker, error) { if rooms.AuthorizeRoomJoin && rooms.UsersEnabled && !sessionAuthenticated { return nil, NewDataError("room_join_requires_account", "Room join requires a user account") } @@ -167,7 +176,7 @@ func (rooms *roomManager) GetOrCreate(roomID string, credentials *DataRoomCreden return nil, NewDataError("room_join_requires_account", "Room creation requires a user account") } - room := NewRoomWorker(rooms, roomID, credentials) + room := NewRoomWorker(rooms, roomID, roomName, roomType, credentials) rooms.roomTable[roomID] = room rooms.Unlock() go func() { @@ -196,3 +205,10 @@ func (rooms *roomManager) GlobalUsers() []*roomUser { rooms.RUnlock() return make([]*roomUser, 0) } + +func (rooms *roomManager) MakeRoomID(roomName, roomType string) string { + if roomType == "" { + roomType = rooms.roomTypeDefault + } + return fmt.Sprintf("%s:%s", roomType, roomName) +} diff --git a/src/app/spreed-webrtc-server/roomworker.go b/src/app/spreed-webrtc-server/roomworker.go index f0dea820..a0d24661 100644 --- a/src/app/spreed-webrtc-server/roomworker.go +++ b/src/app/spreed-webrtc-server/roomworker.go @@ -56,7 +56,9 @@ type roomWorker struct { mutex sync.RWMutex // Metadata. - Id string + id string + Name string + Type string credentials *DataRoomCredentials } @@ -65,13 +67,15 @@ type roomUser struct { Sender } -func NewRoomWorker(manager *roomManager, id string, credentials *DataRoomCredentials) RoomWorker { +func NewRoomWorker(manager *roomManager, roomID, roomName, roomType string, credentials *DataRoomCredentials) RoomWorker { - log.Printf("Creating worker for room '%s'\n", id) + log.Printf("Creating worker for room '%s'\n", roomID) r := &roomWorker{ manager: manager, - Id: id, + id: roomID, + Name: roomName, + Type: roomType, workers: make(chan func(), roomMaxWorkers), expired: make(chan bool), users: make(map[string]*roomUser), @@ -107,7 +111,7 @@ L: if len(r.users) == 0 { // Cleanup room when it is empty. r.mutex.RUnlock() - log.Printf("Room worker not in use - cleaning up '%s'\n", r.Id) + log.Printf("Room worker not in use - cleaning up '%s'\n", r.id) break L } else { r.mutex.RUnlock() @@ -149,7 +153,7 @@ func (r *roomWorker) Run(f func()) bool { case r.workers <- f: return true default: - log.Printf("Room worker channel full or closed '%s'\n", r.Id) + log.Printf("Room worker channel full or closed '%s'\n", r.id) return false } @@ -159,6 +163,10 @@ func (r *roomWorker) Update(room *DataRoom) error { fault := make(chan error, 1) worker := func() { r.mutex.Lock() + // Enforce room type and name. + room.Type = r.Type + room.Name = r.Name + // Update credentials. if room.Credentials != nil { if len(room.Credentials.PIN) > 0 { r.credentials = room.Credentials @@ -184,7 +192,7 @@ func (r *roomWorker) GetUsers() []*DataSession { session.Type = "Online" sl = append(sl, session) if len(sl) > maxUsersLength { - log.Println("Limiting users response length in channel", r.Id) + log.Println("Limiting users response length in channel", r.id) return false } } @@ -264,7 +272,7 @@ func (r *roomWorker) Join(credentials *DataRoomCredentials, session *Session, se r.users[session.Id] = &roomUser{session, sender} // NOTE(lcooper): Needs to be a copy, else we risk races with // a subsequent modification of room properties. - result := joinResult{&DataRoom{Name: r.Id}, nil} + result := joinResult{&DataRoom{Name: r.Name, Type: r.Type}, nil} r.mutex.Unlock() results <- result } diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index aa07e332..427564b0 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -116,7 +116,8 @@ func (s *Session) RemoveSubscriber(id string) { s.mutex.Unlock() } -func (s *Session) JoinRoom(roomID string, credentials *DataRoomCredentials, sender Sender) (*DataRoom, error) { +func (s *Session) JoinRoom(roomName, roomType string, credentials *DataRoomCredentials, sender Sender) (*DataRoom, error) { + roomID := s.RoomStatusManager.MakeRoomID(roomName, roomType) s.mutex.Lock() defer s.mutex.Unlock() @@ -133,7 +134,7 @@ func (s *Session) JoinRoom(roomID string, credentials *DataRoomCredentials, send }) } - room, err := s.RoomStatusManager.JoinRoom(roomID, credentials, s, s.authenticated(), sender) + room, err := s.RoomStatusManager.JoinRoom(roomID, roomName, roomType, credentials, s, s.authenticated(), sender) if err == nil { s.Hello = true s.Roomid = roomID From 8d4ff54505dcc165d33a1c4f23f0dfc31c5f9f71 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 15:02:10 +0200 Subject: [PATCH 038/121] Updated tests to new room name with type api. --- .../channelling_api_test.go | 20 +++++++++++++------ src/app/spreed-webrtc-server/room_manager.go | 8 +++++++- .../spreed-webrtc-server/room_manager_test.go | 18 ++++++++--------- .../spreed-webrtc-server/roomworker_test.go | 6 ++++-- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/app/spreed-webrtc-server/channelling_api_test.go b/src/app/spreed-webrtc-server/channelling_api_test.go index df91e779..52326a8c 100644 --- a/src/app/spreed-webrtc-server/channelling_api_test.go +++ b/src/app/spreed-webrtc-server/channelling_api_test.go @@ -23,6 +23,7 @@ package main import ( "errors" + "fmt" "testing" ) @@ -48,9 +49,9 @@ func (fake *fakeRoomManager) RoomUsers(session *Session) []*DataSession { return fake.roomUsers } -func (fake *fakeRoomManager) JoinRoom(id string, _ *DataRoomCredentials, session *Session, sessionAuthenticated bool, _ Sender) (*DataRoom, error) { +func (fake *fakeRoomManager) JoinRoom(id, roomName, roomType string, _ *DataRoomCredentials, session *Session, sessionAuthenticated bool, _ Sender) (*DataRoom, error) { fake.joinedID = id - return &DataRoom{Name: id}, fake.joinError + return &DataRoom{Name: roomName, Type: roomType}, fake.joinError } func (fake *fakeRoomManager) LeaveRoom(roomID, sessionID string) { @@ -65,6 +66,13 @@ func (fake *fakeRoomManager) UpdateRoom(_ *Session, _ *DataRoom) (*DataRoom, err return fake.updatedRoom, fake.updateError } +func (fake *fakeRoomManager) MakeRoomID(roomName, roomType string) string { + if roomType == "" { + roomType = "Room" + } + return fmt.Sprintf("%s:%s", roomType, roomName) +} + func NewTestChannellingAPI() (ChannellingAPI, *fakeClient, *Session, *fakeRoomManager) { client, roomManager := &fakeClient{}, &fakeRoomManager{} session := &Session{ @@ -77,10 +85,10 @@ func NewTestChannellingAPI() (ChannellingAPI, *fakeClient, *Session, *fakeRoomMa } func Test_ChannellingAPI_OnIncoming_HelloMessage_JoinsTheSelectedRoom(t *testing.T) { - roomID, ua := "foobar", "unit tests" + roomID, roomName, ua := "Room:foobar", "foobar", "unit tests" api, client, session, roomManager := NewTestChannellingAPI() - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomID, Ua: ua}}) + api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName, Ua: ua}}) if roomManager.joinedID != roomID { t.Errorf("Expected to have joined room %v, but got %v", roomID, roomManager.joinedID) @@ -101,10 +109,10 @@ func Test_ChannellingAPI_OnIncoming_HelloMessage_JoinsTheSelectedRoom(t *testing } func Test_ChannellingAPI_OnIncoming_HelloMessage_LeavesAnyPreviouslyJoinedRooms(t *testing.T) { - roomID := "foobar" + roomID, roomName := "Room:foobar", "foobar" api, client, session, roomManager := NewTestChannellingAPI() - api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomID}}) + api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: roomName}}) api.OnIncoming(client, session, &DataIncoming{Type: "Hello", Hello: &DataHello{Id: "baz"}}) if roomManager.leftID != roomID { diff --git a/src/app/spreed-webrtc-server/room_manager.go b/src/app/spreed-webrtc-server/room_manager.go index 1d221c2c..44779127 100644 --- a/src/app/spreed-webrtc-server/room_manager.go +++ b/src/app/spreed-webrtc-server/room_manager.go @@ -102,12 +102,18 @@ func (rooms *roomManager) LeaveRoom(roomID, sessionID string) { } func (rooms *roomManager) UpdateRoom(session *Session, room *DataRoom) (*DataRoom, error) { - roomID := rooms.MakeRoomID(room.Name, room.Type) + var roomID string + if room != nil { + roomID = rooms.MakeRoomID(room.Name, room.Type) + } if !session.Hello || session.Roomid != roomID { return nil, NewDataError("not_in_room", "Cannot update other rooms") } if roomWorker, ok := rooms.Get(session.Roomid); ok { return room, roomWorker.Update(room) + } else { + // Set default room type if not found. + room.Type = rooms.roomTypeDefault } // TODO(lcooper): We should almost certainly return an error in this case. return room, nil diff --git a/src/app/spreed-webrtc-server/room_manager_test.go b/src/app/spreed-webrtc-server/room_manager_test.go index e87c934f..76494de8 100644 --- a/src/app/spreed-webrtc-server/room_manager_test.go +++ b/src/app/spreed-webrtc-server/room_manager_test.go @@ -36,16 +36,16 @@ func Test_RoomManager_JoinRoom_ReturnsAnErrorForUnauthenticatedSessionsWhenCreat config.AuthorizeRoomCreation = true unauthenticatedSession := &Session{} - _, err := roomManager.JoinRoom("foo", nil, unauthenticatedSession, false, nil) + _, err := roomManager.JoinRoom("Room:foo", "foo", "Room", nil, unauthenticatedSession, false, nil) assertDataError(t, err, "room_join_requires_account") authenticatedSession := &Session{userid: "9870457"} - _, err = roomManager.JoinRoom("foo", nil, authenticatedSession, true, nil) + _, err = roomManager.JoinRoom("Room:foo", "foo", "Room", nil, authenticatedSession, true, nil) if err != nil { t.Fatalf("Unexpected error %v joining room while authenticated", err) } - _, err = roomManager.JoinRoom("foo", nil, unauthenticatedSession, false, nil) + _, err = roomManager.JoinRoom("Room:foo", "foo", "Room", nil, unauthenticatedSession, false, nil) if err != nil { t.Fatalf("Unexpected error %v joining room while unauthenticated", err) } @@ -57,16 +57,16 @@ func Test_RoomManager_JoinRoom_ReturnsAnErrorForUnauthenticatedSessionsWhenJoinR config.AuthorizeRoomJoin = true unauthenticatedSession := &Session{} - _, err := roomManager.JoinRoom("foo", nil, unauthenticatedSession, false, nil) + _, err := roomManager.JoinRoom("Room:foo", "foo", "Room", nil, unauthenticatedSession, false, nil) assertDataError(t, err, "room_join_requires_account") authenticatedSession := &Session{userid: "9870457"} - _, err = roomManager.JoinRoom("foo", nil, authenticatedSession, true, nil) + _, err = roomManager.JoinRoom("Room:foo", "foo", "Room", nil, authenticatedSession, true, nil) if err != nil { t.Fatalf("Unexpected error %v joining room while authenticated", err) } - _, err = roomManager.JoinRoom("foo", nil, unauthenticatedSession, false, nil) + _, err = roomManager.JoinRoom("Room:foo", "foo", "Room", nil, unauthenticatedSession, false, nil) assertDataError(t, err, "room_join_requires_account") } @@ -79,15 +79,15 @@ func Test_RoomManager_UpdateRoom_ReturnsAnErrorIfNoRoomHasBeenJoined(t *testing. func Test_RoomManager_UpdateRoom_ReturnsAnErrorIfUpdatingAnUnjoinedRoom(t *testing.T) { roomManager, _ := NewTestRoomManager() - session := &Session{Hello: true, Roomid: "foo"} + session := &Session{Hello: true, Roomid: "Room:foo"} _, err := roomManager.UpdateRoom(session, &DataRoom{Name: "bar"}) assertDataError(t, err, "not_in_room") } func Test_RoomManager_UpdateRoom_ReturnsACorrectlyTypedDocument(t *testing.T) { roomManager, _ := NewTestRoomManager() - session := &Session{Hello: true, Roomid: "foo"} - room, err := roomManager.UpdateRoom(session, &DataRoom{Name: session.Roomid}) + session := &Session{Hello: true, Roomid: "Room:foo"} + room, err := roomManager.UpdateRoom(session, &DataRoom{Name: "foo"}) if err != nil { t.Fatalf("Unexpected error %v updating room", err) } diff --git a/src/app/spreed-webrtc-server/roomworker_test.go b/src/app/spreed-webrtc-server/roomworker_test.go index f963c5cd..25d8f0c5 100644 --- a/src/app/spreed-webrtc-server/roomworker_test.go +++ b/src/app/spreed-webrtc-server/roomworker_test.go @@ -26,18 +26,20 @@ import ( ) const ( + testRoomID string = "Room:a-room-name" testRoomName string = "a-room-name" + testRoomType string = "Room" ) func NewTestRoomWorker() RoomWorker { - worker := NewRoomWorker(&roomManager{Config: &Config{}}, testRoomName, nil) + worker := NewRoomWorker(&roomManager{Config: &Config{}}, testRoomID, testRoomName, testRoomType, nil) go worker.Start() return worker } func NewTestRoomWorkerWithPIN(t *testing.T) (RoomWorker, string) { pin := "asdf" - worker := NewRoomWorker(&roomManager{Config: &Config{}}, testRoomName, &DataRoomCredentials{PIN: pin}) + worker := NewRoomWorker(&roomManager{Config: &Config{}}, testRoomID, testRoomName, testRoomType, &DataRoomCredentials{PIN: pin}) go worker.Start() return worker, pin } From aefdbdac6ca0393b25c334304fcdb73401bcafa0 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 15:49:59 +0200 Subject: [PATCH 039/121] Updated channel api docs to reflect room type changes. --- doc/CHANNELING-API.txt | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index 0d328ad9..3a504d15 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -162,9 +162,10 @@ Special purpose documents for channling { Type: "Hello", Hello: { - Version: "1.0.0", - Ua: "Test client 1.0", - Id: "", + "Version": "1.0.0", + "Ua": "Test client 1.0", + "Name": "", + "Type": "", "Credentials": {...} } } @@ -179,7 +180,10 @@ Special purpose documents for channling Version : Channel protocol version (string). Ua : User agent description (string). - Id : Room id. The default Room has the empty string Id ("") (string). + Name : Room name. The default Room has the empty string name ("") (string). + Type : Room type. Use empty string to let the server select the + default type. + Id : Same as 'Name' (kept for compatibility). Credentials : An optional RoomCredentials document containing room authentication information. See the Room document for information on how such credentials should be handled after @@ -218,10 +222,10 @@ Special purpose documents for channling Keys under Welcome: - Room: Contains the current state of the room, see the description of - the Room document for more details. - Users: Contains the user list for the room, see the description of - the Users document for more details. + Room : Contains the current state of the room, see the description of + the Room document for more details. + Users : Contains the user list for the room, see the description of + the Users document for more details. RoomCredentials @@ -241,7 +245,7 @@ Special purpose documents for channling Room { - "Type": "Room", + "Type": "room-type", "Name": "room-name-here" "Credentials": {...} } @@ -256,8 +260,10 @@ Special purpose documents for channling Keys under Room: - Name : The human readable ID of the room, currently must be globally - unique. + Type : The room type. This field should only be send to alter + the room type. It will always contain the type of the room + when returned by the server. + Name : The human readable name of the room. Credentials : Optional authentication information for the room, see the documentation of the RoomCredentials document for more details. This field shall only be present when sending or @@ -423,8 +429,8 @@ Additional types for session listing and notifications } - 'buddyPicture' can be in next formats: - 1. Base64 encoded string of an image. + 'buddyPicture' can be in next formats: + 1. Base64 encoded string of an image. Example: data:image/jpeg;base64,/9j/4... 2. url subpath to query REST API. Please refer to REST API for more information Example: img:8nG33oDk8Yv8fvK6IphL/6vjI2NLigcET/picture.jpg From f4f7d8b4236482e67af8c6af586169edd53c357a Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sun, 19 Apr 2015 15:50:30 +0200 Subject: [PATCH 040/121] Bumped copyright. --- doc/CHANNELING-API.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index 3a504d15..955b7ca5 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -1,7 +1,7 @@ Spreed WebRTC Channeling API v1.3.0 ================================================= - (c)2014 struktur AG + (c)2015 struktur AG The server provides a Websocket connection end point as channeling API to share peer information for peer to peer connectivity. From 8c4298d82a66d4213b6e9ebe904c61e86c35ebf8 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 14:50:10 +0200 Subject: [PATCH 041/121] Bumped server API version to 1.2. --- static/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/app.js b/static/js/app.js index 2317b38f..dfbb5594 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -210,7 +210,7 @@ define([ // Our API version as float. This value is incremented on // breaking changes to plugins can check on it. - var apiversion = 1.1; + var apiversion = 1.2; var initialize = function(app, launcher) { From 4025f0fa7662fc0c9f2c9193f0cf34886d871bf7 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 14:52:47 +0200 Subject: [PATCH 042/121] Sync API version with docs and bumped to 1.4. --- doc/CHANNELING-API.txt | 2 +- static/js/app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index 955b7ca5..c3a34cb0 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -1,5 +1,5 @@ - Spreed WebRTC Channeling API v1.3.0 + Spreed WebRTC Channeling API v1.4.0 ================================================= (c)2015 struktur AG diff --git a/static/js/app.js b/static/js/app.js index dfbb5594..3180afc7 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -210,7 +210,7 @@ define([ // Our API version as float. This value is incremented on // breaking changes to plugins can check on it. - var apiversion = 1.2; + var apiversion = 1.4; var initialize = function(app, launcher) { From 69db76290dbbfe4f476d2a4d1357b3eaa249ac75 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 15:07:41 +0200 Subject: [PATCH 043/121] Added server side ApiVersion returned with self to distinguish client and server API version support. --- doc/CHANNELING-API.txt | 36 +++++++++++-------- src/app/spreed-webrtc-server/channelling.go | 19 +++++----- .../spreed-webrtc-server/channelling_api.go | 20 ++++++----- static/js/app.js | 4 +-- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index c3a34cb0..1d4e03be 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -117,6 +117,7 @@ Special purpose documents for channling "Suserid": "", "Token": "some-very-long-string", "Version": "server-version-number", + "ApiVersion": 1.4, "Turn": { "username": "turn-username", "password": "turn-password", @@ -136,21 +137,26 @@ Special purpose documents for channling Keys: - Type : Self (string) - Id : Public Session id for this connection (string). - Sid : Secure (non public) id for this session (string). - Userid : User id if this session belongs to an authenticated user. Else empty. - Suserid : Secure (non public) user id if session has an user id. Else empty. - Token : Security token (string), to restablish connection with the same - session. Pass the value as URL query parameter t, to the websocket URL. - Version : Server version number. Use this to detect server upgrades. - Turn : Mapping (interface{}) to contain TURN server details, like - urls, password and username. See - http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00 - and TURN REST API section in - https://code.google.com/p/rfc5766-turn-server/wiki/turnserver - for details. - Stun : Array with STUN server URLs. + Type : Self (string) + Id : Public Session id for this connection (string). + Sid : Secure (non public) id for this session (string). + Userid : User id if this session belongs to an authenticated user. + Else empty. + Suserid : Secure (non public) user id if session has an user id. + Else empty. + Token : Security token (string), to restablish connection with the + same session. Pass the value as URL query parameter t, to + the websocket URL. + Version : Server version number. Use this to detect server upgrades. + ApiVersion : Server channeling API base version. Use this version to select + client side compatibility with the connected server. + Turn : Mapping (interface{}) to contain TURN server details, like + urls, password and username. See + http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00 + and TURN REST API section in + https://code.google.com/p/rfc5766-turn-server/wiki/turnserver + for details. + Stun : Array with STUN server URLs. You can also send an empty Self document to the server to make the server transmit a fresh Self document (eg. to refresh when ttl was reached). Please diff --git a/src/app/spreed-webrtc-server/channelling.go b/src/app/spreed-webrtc-server/channelling.go index c05dcf8e..2fcd68c5 100644 --- a/src/app/spreed-webrtc-server/channelling.go +++ b/src/app/spreed-webrtc-server/channelling.go @@ -79,15 +79,16 @@ type DataAnswer struct { } type DataSelf struct { - Type string - Id string - Sid string - Userid string - Suserid string - Token string - Version string - Turn *DataTurn - Stun []string + Type string + Id string + Sid string + Userid string + Suserid string + Token string + Version string // Server version. + ApiVersion float64 // Server channelling API version. + Turn *DataTurn + Stun []string } type DataTurn struct { diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index 958e9a9b..afd5b581 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -28,6 +28,7 @@ import ( const ( maxConferenceSize = 100 + apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand ) type ChannellingAPI interface { @@ -171,15 +172,16 @@ func (api *channellingAPI) HandleSelf(session *Session) (*DataSelf, error) { log.Println("Created new session token", len(token), token) self := &DataSelf{ - Type: "Self", - Id: session.Id, - Sid: session.Sid, - Userid: session.Userid(), - Suserid: api.EncodeSessionUserID(session), - Token: token, - Version: api.Version, - Turn: api.CreateTurnData(session), - Stun: api.StunURIs, + Type: "Self", + Id: session.Id, + Sid: session.Sid, + Userid: session.Userid(), + Suserid: api.EncodeSessionUserID(session), + Token: token, + Version: api.Version, + ApiVersion: apiVersion, + Turn: api.CreateTurnData(session), + Stun: api.StunURIs, } return self, nil diff --git a/static/js/app.js b/static/js/app.js index 3180afc7..d63c58a0 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -208,9 +208,9 @@ define([ }; - // Our API version as float. This value is incremented on + // Our client side API version as float. This value is incremented on // breaking changes to plugins can check on it. - var apiversion = 1.4; + var apiversion = 1.1; var initialize = function(app, launcher) { From 9df314a37f9d7740877b481de802322ef17fc735 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 15:14:35 +0200 Subject: [PATCH 044/121] Use new Name field to send room name, rather than deprectated Id field. --- static/js/mediastream/api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/js/mediastream/api.js b/static/js/mediastream/api.js index 8214d31e..892e27e4 100644 --- a/static/js/mediastream/api.js +++ b/static/js/mediastream/api.js @@ -236,7 +236,8 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { var data = { Version: this.version, Ua: this.userAgent, - Id: name + Name: name, + Type: "" // Selects the default room type. }; if (pin) { From 513116f783998b27adc9382a3c63a199add8cdbb Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 15:33:12 +0200 Subject: [PATCH 045/121] We finally have a ui controller. --- static/js/controllers/controllers.js | 6 +++--- .../{mediastreamcontroller.js => uicontroller.js} | 0 static/js/directives/ui.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename static/js/controllers/{mediastreamcontroller.js => uicontroller.js} (100%) diff --git a/static/js/controllers/controllers.js b/static/js/controllers/controllers.js index 57c25a0c..f455e02d 100644 --- a/static/js/controllers/controllers.js +++ b/static/js/controllers/controllers.js @@ -23,16 +23,16 @@ define([ 'underscore', - 'controllers/mediastreamcontroller', + 'controllers/uicontroller', 'controllers/statusmessagecontroller', 'controllers/chatroomcontroller', 'controllers/usersettingscontroller', 'controllers/contactsmanagercontroller', 'controllers/contactsmanagereditcontroller', - 'controllers/appcontroller'], function(_, MediastreamController, StatusmessageController, ChatroomController, UsersettingsController, ContactsmanagerController, ContactsmanagereditController, AppController) { + 'controllers/appcontroller'], function(_, UiController, StatusmessageController, ChatroomController, UsersettingsController, ContactsmanagerController, ContactsmanagereditController, AppController) { var controllers = { - MediastreamController: MediastreamController, + UiController: UiController, StatusmessageController: StatusmessageController, ChatroomController: ChatroomController, UsersettingsController: UsersettingsController, diff --git a/static/js/controllers/mediastreamcontroller.js b/static/js/controllers/uicontroller.js similarity index 100% rename from static/js/controllers/mediastreamcontroller.js rename to static/js/controllers/uicontroller.js diff --git a/static/js/directives/ui.js b/static/js/directives/ui.js index 2d7d81fe..41a19725 100644 --- a/static/js/directives/ui.js +++ b/static/js/directives/ui.js @@ -29,7 +29,7 @@ define(['text!partials/ui.html'], function(template) { restrict: 'E', replace: true, scope: false, - controller: 'MediastreamController', + controller: 'UiController', template: template } From e0fa8c8b43eb9dbbd918abc317fd8ebae449e956 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 18:08:59 +0200 Subject: [PATCH 046/121] Allow slashes unquoted in room names. This brings nested rooms. --- src/app/spreed-webrtc-server/main.go | 6 ++++ static/js/app.js | 2 +- static/js/services/resturl.js | 45 ++++++++++++++++++++-------- static/js/services/rooms.js | 11 +++---- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 86a157a8..8ea32933 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -352,6 +352,8 @@ func runner(runtime phoenix.Runtime) error { r.Handle("/robots.txt", http.StripPrefix(config.B, http.FileServer(http.Dir(path.Join(rootFolder, "static"))))) r.Handle("/favicon.ico", http.StripPrefix(config.B, http.FileServer(http.Dir(path.Join(rootFolder, "static", "img"))))) r.Handle("/ws", makeWSHandler(statsManager, sessionManager, codec, channellingAPI)) + + // Simple room handler. r.HandleFunc("/{room}", httputils.MakeGzipHandler(roomHandler)) // Add API end points. @@ -382,6 +384,10 @@ func runner(runtime phoenix.Runtime) error { } } + // Map everything else to a room when it is a GET. + rooms := r.PathPrefix("/").Methods("GET").Subrouter() + rooms.HandleFunc("/{room:.*}", httputils.MakeGzipHandler(roomHandler)) + return runtime.Start() } diff --git a/static/js/app.js b/static/js/app.js index d63c58a0..989277bb 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -154,7 +154,7 @@ define([ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|filesystem|blob):/); $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|filesystem|blob):|data:image\//); // Setup routing - $routeProvider.when("/:room", {}); + $routeProvider.when("/:room*", {}); // Use HTML5 routing. $locationProvider.html5Mode(true); }]); diff --git a/static/js/services/resturl.js b/static/js/services/resturl.js index 381124c1..c585076c 100644 --- a/static/js/services/resturl.js +++ b/static/js/services/resturl.js @@ -20,21 +20,42 @@ */ "use strict"; -define([ -], function() { +define(["underscore"], function(_) { + // restURL return ["globalContext", "$window", function(context, $window) { - return { - room: function(id) { - id = $window.encodeURIComponent(id); - return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + id; - }, - buddy: function(id) { - return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + "static/img/buddy/s46/" + id; - }, - api: function(path) { - return (context.Cfg.B || "/") + "api/v1/" + path; + var RestURL = function() {}; + RestURL.prototype.room = function(name) { + var url = this.encodeRoomURL(name); + return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + url; + }; + RestURL.prototype.buddy = function(id) { + return $window.location.protocol + '//' + $window.location.host + context.Cfg.B + "static/img/buddy/s46/" + id; + }; + RestURL.prototype.api = function(path) { + return (context.Cfg.B || "/") + "api/v1/" + path; + }; + RestURL.prototype.encodeRoomURL = function(name, prefix) { + // Split parts so slashes are allowed. + var parts = name.split("/"); + var url = []; + if (typeof prefix !== "undefined") { + url.push(prefix); + } + // Allow some thing in room name parts. + _.each(parts, function(p) { + p = $window.encodeURIComponent(p); + p = p.replace(/^%40/, "@"); + p = p.replace(/^%24/, "$"); + p = p.replace(/^%2B/, "+"); + url.push(p); + }); + if (url.length > 1 && url[url.length-1] === "") { + // Remove trailing slash if any. + url.pop(); } + return url.join("/"); }; + return new RestURL(); }]; }); diff --git a/static/js/services/rooms.js b/static/js/services/rooms.js index df99a0ca..94d0ba16 100644 --- a/static/js/services/rooms.js +++ b/static/js/services/rooms.js @@ -103,7 +103,7 @@ define([ currentRoom = room; if (priorRoom) { priorRoomName = priorRoom.Name; - console.log("Left room", priorRoom.Name); + console.log("Left room", [priorRoom.Name]); $rootScope.$broadcast("room.left", priorRoom.Name); } if (currentRoom) { @@ -212,13 +212,10 @@ define([ return canJoinRooms; }, joinByName: function(name, replace) { - name = $window.encodeURIComponent(name); - name = name.replace(/^%40/, "@"); - name = name.replace(/^%24/, "$"); - name = name.replace(/^%2B/, "+"); - + var url = restURL.encodeRoomURL(name, ""); + // Apply new URL. safeApply($rootScope, function(scope) { - $location.path("/" + name); + $location.path(url); if (replace) { $location.replace(); } From 37ce3c6bfaa7fb016e20dc095aa93eadbaacb20f Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 18:48:06 +0200 Subject: [PATCH 047/121] Strip spurious slashes and white space in path segments of room names. --- static/js/directives/roombar.js | 8 +++++--- static/js/services/resturl.js | 22 ++++++++++++++++------ static/js/services/rooms.js | 17 +++++++++-------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/static/js/directives/roombar.js b/static/js/directives/roombar.js index 0573e23e..250e0184 100644 --- a/static/js/directives/roombar.js +++ b/static/js/directives/roombar.js @@ -32,15 +32,17 @@ define(['underscore', 'angular', 'text!partials/roombar.html'], function(_, angu $scope.newRoomName = ""; }; - //console.log("roomBar directive link", arguments); - //$scope.layout.roombar = true; - $scope.save = function() { if ($scope.roombarform.$invalid) { return; } var roomName = rooms.joinByName($scope.newRoomName); if (roomName !== $scope.currentRoomName) { + // Room name accepted. + $scope.roombarform.$setPristine(); + } else { + // Room name did not apply. Reset new name and form. + $scope.newRoomName = roomName; $scope.roombarform.$setPristine(); } }; diff --git a/static/js/services/resturl.js b/static/js/services/resturl.js index c585076c..fdacf59f 100644 --- a/static/js/services/resturl.js +++ b/static/js/services/resturl.js @@ -20,7 +20,7 @@ */ "use strict"; -define(["underscore"], function(_) { +define(["underscore", "jquery"], function(_, $) { // restURL return ["globalContext", "$window", function(context, $window) { @@ -35,24 +35,34 @@ define(["underscore"], function(_) { RestURL.prototype.api = function(path) { return (context.Cfg.B || "/") + "api/v1/" + path; }; - RestURL.prototype.encodeRoomURL = function(name, prefix) { + RestURL.prototype.encodeRoomURL = function(name, prefix, cb) { // Split parts so slashes are allowed. var parts = name.split("/"); var url = []; + var nn = []; if (typeof prefix !== "undefined") { url.push(prefix); } - // Allow some thing in room name parts. + // Allow some things in room name parts. _.each(parts, function(p) { + if (p === "") { + // Skip empty parts, effectly stripping spurious slashes. + return; + } + // Trim parts. removing white space from start and end. + p = $.trim(p); + nn.push(p); + // URL encode. p = $window.encodeURIComponent(p); + // Encode back certain stuff we allow. p = p.replace(/^%40/, "@"); p = p.replace(/^%24/, "$"); p = p.replace(/^%2B/, "+"); url.push(p); }); - if (url.length > 1 && url[url.length-1] === "") { - // Remove trailing slash if any. - url.pop(); + if (cb) { + cb(url.join("/")); + return nn.join("/"); } return url.join("/"); }; diff --git a/static/js/services/rooms.js b/static/js/services/rooms.js index 94d0ba16..f21bee68 100644 --- a/static/js/services/rooms.js +++ b/static/js/services/rooms.js @@ -212,15 +212,16 @@ define([ return canJoinRooms; }, joinByName: function(name, replace) { - var url = restURL.encodeRoomURL(name, ""); - // Apply new URL. - safeApply($rootScope, function(scope) { - $location.path(url); - if (replace) { - $location.replace(); - } + var nn = restURL.encodeRoomURL(name, "", function(url) { + // Apply new URL. + safeApply($rootScope, function(scope) { + $location.path(url); + if (replace) { + $location.replace(); + } + }); }); - return name; + return nn; }, joinDefault: function(replace) { return rooms.joinByName("", replace); From 22c1e889cc2e185bbb25805cdf4c445b5e36a560 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 20 Apr 2015 18:51:26 +0200 Subject: [PATCH 048/121] Do not strip spaced in room path parts. --- static/js/services/resturl.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/static/js/services/resturl.js b/static/js/services/resturl.js index fdacf59f..6ffe19d8 100644 --- a/static/js/services/resturl.js +++ b/static/js/services/resturl.js @@ -20,7 +20,7 @@ */ "use strict"; -define(["underscore", "jquery"], function(_, $) { +define(["underscore"], function(_) { // restURL return ["globalContext", "$window", function(context, $window) { @@ -49,8 +49,6 @@ define(["underscore", "jquery"], function(_, $) { // Skip empty parts, effectly stripping spurious slashes. return; } - // Trim parts. removing white space from start and end. - p = $.trim(p); nn.push(p); // URL encode. p = $window.encodeURIComponent(p); From d6f5dcac9e2fa497511fb508cbfd5c045ed778a0 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 21 Apr 2015 16:05:52 +0200 Subject: [PATCH 049/121] Moved from Sleepy to Sloth. --- src/app/spreed-webrtc-server/main.go | 4 +- src/app/spreed-webrtc-server/sleepy/core.go | 234 -------------------- 2 files changed, 2 insertions(+), 236 deletions(-) delete mode 100644 src/app/spreed-webrtc-server/sleepy/core.go diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 8ea32933..7fdaa6d9 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -22,7 +22,6 @@ package main import ( - "app/spreed-webrtc-server/sleepy" "bytes" "crypto/rand" "encoding/hex" @@ -32,6 +31,7 @@ import ( "github.com/strukturag/goacceptlanguageparser" "github.com/strukturag/httputils" "github.com/strukturag/phoenix" + "github.com/strukturag/sloth" "html/template" "log" "net/http" @@ -357,7 +357,7 @@ func runner(runtime phoenix.Runtime) error { r.HandleFunc("/{room}", httputils.MakeGzipHandler(roomHandler)) // Add API end points. - api := sleepy.NewAPI() + api := sloth.NewAPI() api.SetMux(r.PathPrefix("/api/v1/").Subrouter()) api.AddResource(&Rooms{}, "/rooms") api.AddResource(config, "/config") diff --git a/src/app/spreed-webrtc-server/sleepy/core.go b/src/app/spreed-webrtc-server/sleepy/core.go deleted file mode 100644 index 465e497b..00000000 --- a/src/app/spreed-webrtc-server/sleepy/core.go +++ /dev/null @@ -1,234 +0,0 @@ -/** - * A RESTful framework for Go - * - * Modified version of sleepy to support Gorilla muxers. - * https://github.com/strukturag/sleepy - * - * Copyright (c) 2014 struktur AG - * Copyright (c) 2013-2014 Doug Black and the Sleepy authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * -**/ - -package sleepy - -import ( - "encoding/json" - "errors" - "fmt" - "github.com/gorilla/mux" - "net/http" -) - -const ( - GET = "GET" - POST = "POST" - PUT = "PUT" - DELETE = "DELETE" - HEAD = "HEAD" - PATCH = "PATCH" -) - -// GetSupported is the interface that provides the Get -// method a resource must support to receive HTTP GETs. -type GetSupported interface { - Get(*http.Request) (int, interface{}, http.Header) -} - -// PostSupported is the interface that provides the Post -// method a resource must support to receive HTTP POSTs. -type PostSupported interface { - Post(*http.Request) (int, interface{}, http.Header) -} - -// PutSupported is the interface that provides the Put -// method a resource must support to receive HTTP PUTs. -type PutSupported interface { - Put(*http.Request) (int, interface{}, http.Header) -} - -// DeleteSupported is the interface that provides the Delete -// method a resource must support to receive HTTP DELETEs. -type DeleteSupported interface { - Delete(*http.Request) (int, interface{}, http.Header) -} - -// HeadSupported is the interface that provides the Head -// method a resource must support to receive HTTP HEADs. -type HeadSupported interface { - Head(*http.Request) (int, interface{}, http.Header) -} - -// PatchSupported is the interface that provides the Patch -// method a resource must support to receive HTTP PATCHs. -type PatchSupported interface { - Patch(*http.Request) (int, interface{}, http.Header) -} - -// Interface for arbitrary muxer support (like http.ServeMux). -type APIMux interface { - HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) *mux.Route - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - -// An API manages a group of resources by routing requests -// to the correct method on a matching resource and marshalling -// the returned data to JSON for the HTTP response. -// -// You can instantiate multiple APIs on separate ports. Each API -// will manage its own set of resources. -type API struct { - mux APIMux - muxInitialized bool -} - -// NewAPI allocates and returns a new API. -func NewAPI() *API { - return &API{} -} - -func (api *API) requestHandler(resource interface{}) http.HandlerFunc { - return func(rw http.ResponseWriter, request *http.Request) { - - if request.ParseForm() != nil { - rw.WriteHeader(http.StatusBadRequest) - return - } - - var handler func(*http.Request) (int, interface{}, http.Header) - - switch request.Method { - case GET: - if resource, ok := resource.(GetSupported); ok { - handler = resource.Get - } - case POST: - if resource, ok := resource.(PostSupported); ok { - handler = resource.Post - } - case PUT: - if resource, ok := resource.(PutSupported); ok { - handler = resource.Put - } - case DELETE: - if resource, ok := resource.(DeleteSupported); ok { - handler = resource.Delete - } - case HEAD: - if resource, ok := resource.(HeadSupported); ok { - handler = resource.Head - } - case PATCH: - if resource, ok := resource.(PatchSupported); ok { - handler = resource.Patch - } - } - - if handler == nil { - rw.WriteHeader(http.StatusMethodNotAllowed) - return - } - - code, data, header := handler(request) - - var content []byte - var err error - - switch data.(type) { - case string: - content = []byte(data.(string)) - case []byte: - content = data.([]byte) - default: - // Encode JSON. - content, err = json.MarshalIndent(data, "", " ") - if err != nil { - if header == nil { - header = http.Header{"Content-Type": {"application/json"}} - } else if header.Get("Content-Type") == "" { - header.Set("Content-Type", "application/json") - } - } - } - - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - return - } - for name, values := range header { - for _, value := range values { - rw.Header().Add(name, value) - } - } - rw.WriteHeader(code) - rw.Write(content) - } -} - -// Mux returns the muxer used by an API. If a ServeMux does not -// yet exist, a new *http.ServeMux will be created and returned. -func (api *API) Mux() APIMux { - if api.muxInitialized { - return api.mux - } else { - api.mux = mux.NewRouter() - api.muxInitialized = true - return api.mux - } -} - -// SetMux sets the muxer to use by an API. A muxer needs to -// implement the APIMux interface (eg. http.ServeMux). -func (api *API) SetMux(mux APIMux) error { - if api.muxInitialized { - return errors.New("You cannot set a muxer when already initialized.") - } else { - api.mux = mux - api.muxInitialized = true - return nil - } -} - -// AddResource adds a new resource to an API. The API will route -// requests that match one of the given paths to the matching HTTP -// method on the resource. -func (api *API) AddResource(resource interface{}, paths ...string) { - for _, path := range paths { - api.Mux().HandleFunc(path, api.requestHandler(resource)) - } -} - -// AddResourceWithWrapper behaves exactly like AddResource but wraps -// the generated handler function with a give wrapper function to allow -// to hook in Gzip support and similar. -func (api *API) AddResourceWithWrapper(resource interface{}, wrapper func(handler http.HandlerFunc) http.HandlerFunc, paths ...string) { - for _, path := range paths { - api.Mux().HandleFunc(path, wrapper(api.requestHandler(resource))) - } -} - -// Start causes the API to begin serving requests on the given port. -func (api *API) Start(port int) error { - if !api.muxInitialized { - return errors.New("You must add at least one resource to this API.") - } - portString := fmt.Sprintf(":%d", port) - return http.ListenAndServe(portString, api.Mux()) -} From befa31eb8f60a42006b83aa00a67250cba2b5791 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 21 Apr 2015 18:53:19 +0200 Subject: [PATCH 050/121] Make travis test Go 1.4. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index abd40504..00cccae3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ go: - 1.1 - 1.2 - 1.3 + - 1.4 - tip env: From 0a3f2cb879ac9c83dca3d6d675f0fac110ab3709 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 22 Apr 2015 11:25:34 +0200 Subject: [PATCH 051/121] Expose authorizing flag in scope and hide sign-in button when true. --- static/js/controllers/appcontroller.js | 5 +++++ static/partials/statusmessage.html | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/static/js/controllers/appcontroller.js b/static/js/controllers/appcontroller.js index 6561a82d..b8fe85eb 100644 --- a/static/js/controllers/appcontroller.js +++ b/static/js/controllers/appcontroller.js @@ -33,6 +33,7 @@ define(["jquery", "angular", "underscore"], function($, angular, _) { appData.set($scope); // User related scope data. + $scope.authorizing = false; $scope.roomsHistory = []; $scope.defaults = { displayName: null, @@ -110,6 +111,10 @@ define(["jquery", "angular", "underscore"], function($, angular, _) { } }); + appData.e.on("authorizing", function(event, authorizing) { + $scope.authorizing = !!authorizing; + }); + $scope.reset(); // Call once for bootstrap. }]; diff --git a/static/partials/statusmessage.html b/static/partials/statusmessage.html index e60cb482..2660143d 100644 --- a/static/partials/statusmessage.html +++ b/static/partials/statusmessage.html @@ -1,6 +1,6 @@ {{_("Initializing")}} - {{id|displayName}} + {{id|displayName}} {{_("Calling")}} {{dialing|displayName}} {{_("Hangup")}} {{_("In call with")}} {{peer|displayName}} {{_("Hangup")}} {{_("Conference with")}} {{peer|displayName}}{{conferencePeers|displayConference}} {{_("Hangup")}} From beff7439b8fb31b3c11a9d474562996c9f5650d1 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 22 Apr 2015 13:43:59 +0200 Subject: [PATCH 052/121] Bumped copyright to 2015. --- src/app/spreed-webrtc-server/api.go | 2 +- src/app/spreed-webrtc-server/buffercache.go | 2 +- src/app/spreed-webrtc-server/channelling.go | 2 +- src/app/spreed-webrtc-server/channelling_api.go | 2 +- src/app/spreed-webrtc-server/channelling_api_test.go | 2 +- src/app/spreed-webrtc-server/client.go | 2 +- src/app/spreed-webrtc-server/common_test.go | 2 +- src/app/spreed-webrtc-server/config.go | 2 +- src/app/spreed-webrtc-server/connection.go | 2 +- src/app/spreed-webrtc-server/contact.go | 2 +- src/app/spreed-webrtc-server/context.go | 2 +- src/app/spreed-webrtc-server/hub.go | 2 +- src/app/spreed-webrtc-server/images.go | 2 +- src/app/spreed-webrtc-server/incoming_codec.go | 2 +- src/app/spreed-webrtc-server/main.go | 2 +- src/app/spreed-webrtc-server/random.go | 2 +- src/app/spreed-webrtc-server/room_manager.go | 2 +- src/app/spreed-webrtc-server/room_manager_test.go | 2 +- src/app/spreed-webrtc-server/rooms.go | 2 +- src/app/spreed-webrtc-server/roomworker.go | 2 +- src/app/spreed-webrtc-server/roomworker_test.go | 2 +- src/app/spreed-webrtc-server/session.go | 2 +- src/app/spreed-webrtc-server/session_manager.go | 2 +- src/app/spreed-webrtc-server/sessions.go | 2 +- src/app/spreed-webrtc-server/stats.go | 2 +- src/app/spreed-webrtc-server/stats_manager.go | 2 +- src/app/spreed-webrtc-server/tickets.go | 2 +- src/app/spreed-webrtc-server/tls.go | 2 +- src/app/spreed-webrtc-server/tokenprovider.go | 2 +- src/app/spreed-webrtc-server/tokens.go | 2 +- src/app/spreed-webrtc-server/user.go | 2 +- src/app/spreed-webrtc-server/users.go | 2 +- src/app/spreed-webrtc-server/ws.go | 2 +- src/styles/_shame.scss | 2 +- src/styles/components/_audiolevel.scss | 2 +- src/styles/components/_audiovideo.scss | 2 +- src/styles/components/_bar.scss | 2 +- src/styles/components/_buddylist.scss | 2 +- src/styles/components/_buddypicturecapture.scss | 2 +- src/styles/components/_buddypictureupload.scss | 2 +- src/styles/components/_chat.scss | 2 +- src/styles/components/_contactsmanager.scss | 2 +- src/styles/components/_fileinfo.scss | 2 +- src/styles/components/_presentation.scss | 2 +- src/styles/components/_rightslide.scss | 2 +- src/styles/components/_roombar.scss | 2 +- src/styles/components/_screenshare.scss | 2 +- src/styles/components/_settings.scss | 2 +- src/styles/components/_social.scss | 2 +- src/styles/components/_usability.scss | 2 +- src/styles/components/_youtubevideo.scss | 2 +- src/styles/csp.scss | 2 +- src/styles/global/_animations.scss | 2 +- src/styles/global/_base.scss | 2 +- src/styles/global/_loader.scss | 2 +- src/styles/global/_nicescroll.scss | 2 +- src/styles/global/_overlaybar.scss | 2 +- src/styles/global/_pages.scss | 2 +- src/styles/global/_variables.scss | 2 +- src/styles/global/_views.scss | 2 +- src/styles/global/_withs.scss | 2 +- src/styles/libs/_dialogs.scss | 2 +- src/styles/libs/angular/angular-csp.scss | 2 +- src/styles/libs/angular/angular.scss | 2 +- src/styles/main.scss | 2 +- static/js/app.js | 2 +- static/js/base.js | 2 +- static/js/controllers/appcontroller.js | 2 +- static/js/controllers/chatroomcontroller.js | 2 +- static/js/controllers/contactsmanagercontroller.js | 2 +- static/js/controllers/contactsmanagereditcontroller.js | 2 +- static/js/controllers/controllers.js | 2 +- static/js/controllers/statusmessagecontroller.js | 2 +- static/js/controllers/uicontroller.js | 2 +- static/js/controllers/usersettingscontroller.js | 2 +- static/js/directives/audiolevel.js | 2 +- static/js/directives/audiovideo.js | 2 +- static/js/directives/bfi.js | 2 +- static/js/directives/buddylist.js | 2 +- static/js/directives/buddypicturecapture.js | 2 +- static/js/directives/buddypictureupload.js | 2 +- static/js/directives/chat.js | 2 +- static/js/directives/contactrequest.js | 2 +- static/js/directives/defaultdialog.js | 2 +- static/js/directives/directives.js | 2 +- static/js/directives/fileinfo.js | 2 +- static/js/directives/odfcanvas.js | 2 +- static/js/directives/onenter.js | 2 +- static/js/directives/onescape.js | 2 +- static/js/directives/page.js | 2 +- static/js/directives/pdfcanvas.js | 2 +- static/js/directives/presentation.js | 2 +- static/js/directives/roombar.js | 2 +- static/js/directives/screenshare.js | 2 +- static/js/directives/settings.js | 2 +- static/js/directives/socialshare.js | 2 +- static/js/directives/statusmessage.js | 2 +- static/js/directives/title.js | 2 +- static/js/directives/ui.js | 2 +- static/js/directives/usability.js | 2 +- static/js/directives/welcome.js | 2 +- static/js/directives/youtubevideo.js | 2 +- static/js/filters/buddyimagesrc.js | 2 +- static/js/filters/displayconference.js | 2 +- static/js/filters/displayname.js | 2 +- static/js/filters/displaynameforsession.js | 2 +- static/js/filters/displayuserid.js | 2 +- static/js/filters/filters.js | 2 +- static/js/filters/formatbase1000.js | 2 +- static/js/main.js | 2 +- static/js/mediastream/api.js | 2 +- static/js/mediastream/connector.js | 2 +- static/js/mediastream/peercall.js | 2 +- static/js/mediastream/peerconference.js | 2 +- static/js/mediastream/peerconnection.js | 2 +- static/js/mediastream/peerscreenshare.js | 2 +- static/js/mediastream/peerxfer.js | 2 +- static/js/mediastream/tokens.js | 2 +- static/js/mediastream/usermedia.js | 2 +- static/js/mediastream/webrtc.js | 2 +- static/js/modules/angular-humanize.js | 2 +- static/js/services/alertify.js | 2 +- static/js/services/animationframe.js | 2 +- static/js/services/api.js | 2 +- static/js/services/appdata.js | 2 +- static/js/services/buddydata.js | 2 +- static/js/services/buddylist.js | 2 +- static/js/services/buddypicture.js | 2 +- static/js/services/buddysession.js | 2 +- static/js/services/chromeextension.js | 2 +- static/js/services/connector.js | 2 +- static/js/services/constraints.js | 2 +- static/js/services/contactdata.js | 2 +- static/js/services/contacts.js | 2 +- static/js/services/continueconnector.js | 2 +- static/js/services/desktopnotify.js | 2 +- static/js/services/dialogs.js | 2 +- static/js/services/enrichmessage.js | 2 +- static/js/services/fastscroll.js | 2 +- static/js/services/filedata.js | 2 +- static/js/services/filedownload.js | 2 +- static/js/services/filetransfer.js | 2 +- static/js/services/fileupload.js | 2 +- static/js/services/geolocation.js | 2 +- static/js/services/localstatus.js | 2 +- static/js/services/localstorage.js | 4 ++-- static/js/services/mediadevices.js | 2 +- static/js/services/mediasources.js | 2 +- static/js/services/mediastream.js | 2 +- static/js/services/modules.js | 2 +- static/js/services/playsound.js | 2 +- static/js/services/randomgen.js | 2 +- static/js/services/resturl.js | 2 +- static/js/services/roompin.js | 2 +- static/js/services/rooms.js | 2 +- static/js/services/safeapply.js | 2 +- static/js/services/safedisplayname.js | 2 +- static/js/services/safemessage.js | 2 +- static/js/services/screensharing.js | 2 +- static/js/services/services.js | 2 +- static/js/services/toastr.js | 2 +- static/js/services/translation.js | 2 +- static/js/services/usersettingsdata.js | 2 +- static/js/services/videolayout.js | 2 +- static/js/services/videowaiter.js | 2 +- static/js/services/visibility.js | 2 +- static/js/services/webrtc.js | 2 +- 167 files changed, 168 insertions(+), 168 deletions(-) diff --git a/src/app/spreed-webrtc-server/api.go b/src/app/spreed-webrtc-server/api.go index 61d1bb2f..0fa83666 100644 --- a/src/app/spreed-webrtc-server/api.go +++ b/src/app/spreed-webrtc-server/api.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/buffercache.go b/src/app/spreed-webrtc-server/buffercache.go index 44a797e9..d19ba72d 100644 --- a/src/app/spreed-webrtc-server/buffercache.go +++ b/src/app/spreed-webrtc-server/buffercache.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/channelling.go b/src/app/spreed-webrtc-server/channelling.go index 2fcd68c5..c37629ba 100644 --- a/src/app/spreed-webrtc-server/channelling.go +++ b/src/app/spreed-webrtc-server/channelling.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/channelling_api.go b/src/app/spreed-webrtc-server/channelling_api.go index afd5b581..f44e4671 100644 --- a/src/app/spreed-webrtc-server/channelling_api.go +++ b/src/app/spreed-webrtc-server/channelling_api.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/channelling_api_test.go b/src/app/spreed-webrtc-server/channelling_api_test.go index 52326a8c..2a2d66c7 100644 --- a/src/app/spreed-webrtc-server/channelling_api_test.go +++ b/src/app/spreed-webrtc-server/channelling_api_test.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/client.go b/src/app/spreed-webrtc-server/client.go index 85c0f062..7e6269f6 100644 --- a/src/app/spreed-webrtc-server/client.go +++ b/src/app/spreed-webrtc-server/client.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/common_test.go b/src/app/spreed-webrtc-server/common_test.go index 395e2a9c..66bf4822 100644 --- a/src/app/spreed-webrtc-server/common_test.go +++ b/src/app/spreed-webrtc-server/common_test.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/config.go b/src/app/spreed-webrtc-server/config.go index 0e250c61..e6899989 100644 --- a/src/app/spreed-webrtc-server/config.go +++ b/src/app/spreed-webrtc-server/config.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/connection.go b/src/app/spreed-webrtc-server/connection.go index 47f29970..dc3fece1 100644 --- a/src/app/spreed-webrtc-server/connection.go +++ b/src/app/spreed-webrtc-server/connection.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/contact.go b/src/app/spreed-webrtc-server/contact.go index 995f92d6..09588a33 100644 --- a/src/app/spreed-webrtc-server/contact.go +++ b/src/app/spreed-webrtc-server/contact.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/context.go b/src/app/spreed-webrtc-server/context.go index cb944c33..fee07996 100644 --- a/src/app/spreed-webrtc-server/context.go +++ b/src/app/spreed-webrtc-server/context.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/hub.go b/src/app/spreed-webrtc-server/hub.go index 6a7dcd26..6c4f9386 100644 --- a/src/app/spreed-webrtc-server/hub.go +++ b/src/app/spreed-webrtc-server/hub.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/images.go b/src/app/spreed-webrtc-server/images.go index 36d66dab..d18e4ce2 100644 --- a/src/app/spreed-webrtc-server/images.go +++ b/src/app/spreed-webrtc-server/images.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/incoming_codec.go b/src/app/spreed-webrtc-server/incoming_codec.go index fb8911bf..d3d0c3f0 100644 --- a/src/app/spreed-webrtc-server/incoming_codec.go +++ b/src/app/spreed-webrtc-server/incoming_codec.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 7fdaa6d9..80649a00 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/random.go b/src/app/spreed-webrtc-server/random.go index 4001a917..a884cd5b 100644 --- a/src/app/spreed-webrtc-server/random.go +++ b/src/app/spreed-webrtc-server/random.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/room_manager.go b/src/app/spreed-webrtc-server/room_manager.go index 44779127..091e17d4 100644 --- a/src/app/spreed-webrtc-server/room_manager.go +++ b/src/app/spreed-webrtc-server/room_manager.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/room_manager_test.go b/src/app/spreed-webrtc-server/room_manager_test.go index 76494de8..fd4ff413 100644 --- a/src/app/spreed-webrtc-server/room_manager_test.go +++ b/src/app/spreed-webrtc-server/room_manager_test.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/rooms.go b/src/app/spreed-webrtc-server/rooms.go index a10e3ca2..bea8b90d 100644 --- a/src/app/spreed-webrtc-server/rooms.go +++ b/src/app/spreed-webrtc-server/rooms.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/roomworker.go b/src/app/spreed-webrtc-server/roomworker.go index a0d24661..95355309 100644 --- a/src/app/spreed-webrtc-server/roomworker.go +++ b/src/app/spreed-webrtc-server/roomworker.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/roomworker_test.go b/src/app/spreed-webrtc-server/roomworker_test.go index 25d8f0c5..1ada20b3 100644 --- a/src/app/spreed-webrtc-server/roomworker_test.go +++ b/src/app/spreed-webrtc-server/roomworker_test.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/session.go b/src/app/spreed-webrtc-server/session.go index 427564b0..84043147 100644 --- a/src/app/spreed-webrtc-server/session.go +++ b/src/app/spreed-webrtc-server/session.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/session_manager.go b/src/app/spreed-webrtc-server/session_manager.go index 43360f7d..3ba91525 100644 --- a/src/app/spreed-webrtc-server/session_manager.go +++ b/src/app/spreed-webrtc-server/session_manager.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/sessions.go b/src/app/spreed-webrtc-server/sessions.go index 6ea0b452..1c22c2ea 100644 --- a/src/app/spreed-webrtc-server/sessions.go +++ b/src/app/spreed-webrtc-server/sessions.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/stats.go b/src/app/spreed-webrtc-server/stats.go index ac9ac0e5..5318175c 100644 --- a/src/app/spreed-webrtc-server/stats.go +++ b/src/app/spreed-webrtc-server/stats.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/stats_manager.go b/src/app/spreed-webrtc-server/stats_manager.go index 59163839..d2507db0 100644 --- a/src/app/spreed-webrtc-server/stats_manager.go +++ b/src/app/spreed-webrtc-server/stats_manager.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/tickets.go b/src/app/spreed-webrtc-server/tickets.go index b44f8bef..f75cc1d4 100644 --- a/src/app/spreed-webrtc-server/tickets.go +++ b/src/app/spreed-webrtc-server/tickets.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/tls.go b/src/app/spreed-webrtc-server/tls.go index 92a082c4..a431c72c 100644 --- a/src/app/spreed-webrtc-server/tls.go +++ b/src/app/spreed-webrtc-server/tls.go @@ -1,7 +1,7 @@ /* * TLS helpers for Go based on crypto/tls package. * - * Copyright (C) 2014 struktur AG. All rights reserved. + * Copyright (C) 2015 struktur AG. All rights reserved. * Copyright 2011 The Go Authors. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/app/spreed-webrtc-server/tokenprovider.go b/src/app/spreed-webrtc-server/tokenprovider.go index 2d6ec585..f93fb853 100644 --- a/src/app/spreed-webrtc-server/tokenprovider.go +++ b/src/app/spreed-webrtc-server/tokenprovider.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/tokens.go b/src/app/spreed-webrtc-server/tokens.go index c1993eaf..0f172b9a 100644 --- a/src/app/spreed-webrtc-server/tokens.go +++ b/src/app/spreed-webrtc-server/tokens.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/user.go b/src/app/spreed-webrtc-server/user.go index fa838f05..4b8d9807 100644 --- a/src/app/spreed-webrtc-server/user.go +++ b/src/app/spreed-webrtc-server/user.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/users.go b/src/app/spreed-webrtc-server/users.go index c10fa512..3c991c6f 100644 --- a/src/app/spreed-webrtc-server/users.go +++ b/src/app/spreed-webrtc-server/users.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/app/spreed-webrtc-server/ws.go b/src/app/spreed-webrtc-server/ws.go index 70ad83fd..f43f01d1 100644 --- a/src/app/spreed-webrtc-server/ws.go +++ b/src/app/spreed-webrtc-server/ws.go @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/_shame.scss b/src/styles/_shame.scss index 9822aa0f..a2f16225 100644 --- a/src/styles/_shame.scss +++ b/src/styles/_shame.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_audiolevel.scss b/src/styles/components/_audiolevel.scss index b1dc4239..b632c10f 100644 --- a/src/styles/components/_audiolevel.scss +++ b/src/styles/components/_audiolevel.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_audiovideo.scss b/src/styles/components/_audiovideo.scss index 9481bfe4..bc85fe31 100644 --- a/src/styles/components/_audiovideo.scss +++ b/src/styles/components/_audiovideo.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_bar.scss b/src/styles/components/_bar.scss index bba29bc3..366b929f 100644 --- a/src/styles/components/_bar.scss +++ b/src/styles/components/_bar.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_buddylist.scss b/src/styles/components/_buddylist.scss index 8cac6628..2ea4ced0 100644 --- a/src/styles/components/_buddylist.scss +++ b/src/styles/components/_buddylist.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_buddypicturecapture.scss b/src/styles/components/_buddypicturecapture.scss index 02104c2b..9afe92a2 100644 --- a/src/styles/components/_buddypicturecapture.scss +++ b/src/styles/components/_buddypicturecapture.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_buddypictureupload.scss b/src/styles/components/_buddypictureupload.scss index dfe2ef16..9f4eda98 100644 --- a/src/styles/components/_buddypictureupload.scss +++ b/src/styles/components/_buddypictureupload.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss index a9f4c9fb..7fddb035 100644 --- a/src/styles/components/_chat.scss +++ b/src/styles/components/_chat.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_contactsmanager.scss b/src/styles/components/_contactsmanager.scss index e7bb7157..743c1b56 100644 --- a/src/styles/components/_contactsmanager.scss +++ b/src/styles/components/_contactsmanager.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_fileinfo.scss b/src/styles/components/_fileinfo.scss index 778ab375..28ed4180 100644 --- a/src/styles/components/_fileinfo.scss +++ b/src/styles/components/_fileinfo.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index 487a1f94..09583e6c 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_rightslide.scss b/src/styles/components/_rightslide.scss index 9fd0eb82..ce242090 100644 --- a/src/styles/components/_rightslide.scss +++ b/src/styles/components/_rightslide.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_roombar.scss b/src/styles/components/_roombar.scss index 1d7c499c..fae2967c 100644 --- a/src/styles/components/_roombar.scss +++ b/src/styles/components/_roombar.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_screenshare.scss b/src/styles/components/_screenshare.scss index c5028d60..297013b1 100644 --- a/src/styles/components/_screenshare.scss +++ b/src/styles/components/_screenshare.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_settings.scss b/src/styles/components/_settings.scss index 55d1fcac..7e52935c 100644 --- a/src/styles/components/_settings.scss +++ b/src/styles/components/_settings.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_social.scss b/src/styles/components/_social.scss index f43b5545..125d564a 100644 --- a/src/styles/components/_social.scss +++ b/src/styles/components/_social.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_usability.scss b/src/styles/components/_usability.scss index 3db56ef4..da1dbbaf 100644 --- a/src/styles/components/_usability.scss +++ b/src/styles/components/_usability.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/components/_youtubevideo.scss b/src/styles/components/_youtubevideo.scss index 8d122f72..398a2a53 100644 --- a/src/styles/components/_youtubevideo.scss +++ b/src/styles/components/_youtubevideo.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/csp.scss b/src/styles/csp.scss index 5fc6c5ce..cd82a8bb 100644 --- a/src/styles/csp.scss +++ b/src/styles/csp.scss @@ -1,6 +1,6 @@ /*! * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_animations.scss b/src/styles/global/_animations.scss index 22f3e569..eac29df3 100644 --- a/src/styles/global/_animations.scss +++ b/src/styles/global/_animations.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_base.scss b/src/styles/global/_base.scss index e1db99f7..9a7ef9f5 100644 --- a/src/styles/global/_base.scss +++ b/src/styles/global/_base.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_loader.scss b/src/styles/global/_loader.scss index 20d89f8f..e2d0afd8 100644 --- a/src/styles/global/_loader.scss +++ b/src/styles/global/_loader.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_nicescroll.scss b/src/styles/global/_nicescroll.scss index dc0f864c..c978b90a 100644 --- a/src/styles/global/_nicescroll.scss +++ b/src/styles/global/_nicescroll.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_overlaybar.scss b/src/styles/global/_overlaybar.scss index 3ba9d41d..93abbf64 100644 --- a/src/styles/global/_overlaybar.scss +++ b/src/styles/global/_overlaybar.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_pages.scss b/src/styles/global/_pages.scss index 487d7f8f..81752e45 100644 --- a/src/styles/global/_pages.scss +++ b/src/styles/global/_pages.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_variables.scss b/src/styles/global/_variables.scss index dcf6f2fa..056a8ab3 100644 --- a/src/styles/global/_variables.scss +++ b/src/styles/global/_variables.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_views.scss b/src/styles/global/_views.scss index e563d1b1..7541cc4e 100644 --- a/src/styles/global/_views.scss +++ b/src/styles/global/_views.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/global/_withs.scss b/src/styles/global/_withs.scss index dae95b83..8f0feb97 100644 --- a/src/styles/global/_withs.scss +++ b/src/styles/global/_withs.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/libs/_dialogs.scss b/src/styles/libs/_dialogs.scss index f08da9ff..d64d6e43 100644 --- a/src/styles/libs/_dialogs.scss +++ b/src/styles/libs/_dialogs.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/libs/angular/angular-csp.scss b/src/styles/libs/angular/angular-csp.scss index e64287ec..656a7705 100644 --- a/src/styles/libs/angular/angular-csp.scss +++ b/src/styles/libs/angular/angular-csp.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/libs/angular/angular.scss b/src/styles/libs/angular/angular.scss index 45c1b924..84498244 100644 --- a/src/styles/libs/angular/angular.scss +++ b/src/styles/libs/angular/angular.scss @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/src/styles/main.scss b/src/styles/main.scss index bb04b257..e061bb08 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -1,6 +1,6 @@ /*! * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/app.js b/static/js/app.js index 989277bb..c6cc7736 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/base.js b/static/js/base.js index 730ee3fa..92b324b0 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/appcontroller.js b/static/js/controllers/appcontroller.js index b8fe85eb..2d3d6dfd 100644 --- a/static/js/controllers/appcontroller.js +++ b/static/js/controllers/appcontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/chatroomcontroller.js b/static/js/controllers/chatroomcontroller.js index ca36a3a8..d6611ef8 100644 --- a/static/js/controllers/chatroomcontroller.js +++ b/static/js/controllers/chatroomcontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/contactsmanagercontroller.js b/static/js/controllers/contactsmanagercontroller.js index c5bae123..7fb00028 100644 --- a/static/js/controllers/contactsmanagercontroller.js +++ b/static/js/controllers/contactsmanagercontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/contactsmanagereditcontroller.js b/static/js/controllers/contactsmanagereditcontroller.js index 214dad69..d0c74c2d 100644 --- a/static/js/controllers/contactsmanagereditcontroller.js +++ b/static/js/controllers/contactsmanagereditcontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/controllers.js b/static/js/controllers/controllers.js index f455e02d..102124a6 100644 --- a/static/js/controllers/controllers.js +++ b/static/js/controllers/controllers.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/statusmessagecontroller.js b/static/js/controllers/statusmessagecontroller.js index b606189e..5313fd0a 100644 --- a/static/js/controllers/statusmessagecontroller.js +++ b/static/js/controllers/statusmessagecontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/uicontroller.js b/static/js/controllers/uicontroller.js index 65622969..fadfe0d9 100644 --- a/static/js/controllers/uicontroller.js +++ b/static/js/controllers/uicontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/controllers/usersettingscontroller.js b/static/js/controllers/usersettingscontroller.js index 41756b20..5ac12ca2 100644 --- a/static/js/controllers/usersettingscontroller.js +++ b/static/js/controllers/usersettingscontroller.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/audiolevel.js b/static/js/directives/audiolevel.js index bfcf22cd..87220dec 100644 --- a/static/js/directives/audiolevel.js +++ b/static/js/directives/audiolevel.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/audiovideo.js b/static/js/directives/audiovideo.js index f931acc4..e62f135c 100644 --- a/static/js/directives/audiovideo.js +++ b/static/js/directives/audiovideo.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/bfi.js b/static/js/directives/bfi.js index af445851..e141fbc2 100644 --- a/static/js/directives/bfi.js +++ b/static/js/directives/bfi.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/buddylist.js b/static/js/directives/buddylist.js index 69c428dd..38efcc17 100644 --- a/static/js/directives/buddylist.js +++ b/static/js/directives/buddylist.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/buddypicturecapture.js b/static/js/directives/buddypicturecapture.js index 09a21951..32e3625f 100644 --- a/static/js/directives/buddypicturecapture.js +++ b/static/js/directives/buddypicturecapture.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/buddypictureupload.js b/static/js/directives/buddypictureupload.js index 744df141..65533ace 100644 --- a/static/js/directives/buddypictureupload.js +++ b/static/js/directives/buddypictureupload.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index 18e971a4..2c9bf7b4 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/contactrequest.js b/static/js/directives/contactrequest.js index d59ea8c4..ce991451 100644 --- a/static/js/directives/contactrequest.js +++ b/static/js/directives/contactrequest.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/defaultdialog.js b/static/js/directives/defaultdialog.js index 14edda42..e15b0a89 100644 --- a/static/js/directives/defaultdialog.js +++ b/static/js/directives/defaultdialog.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index ad556a4e..5c60f9ec 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/fileinfo.js b/static/js/directives/fileinfo.js index 43107a2a..cd8b4e99 100644 --- a/static/js/directives/fileinfo.js +++ b/static/js/directives/fileinfo.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/odfcanvas.js b/static/js/directives/odfcanvas.js index 7aa980fb..aa29c796 100644 --- a/static/js/directives/odfcanvas.js +++ b/static/js/directives/odfcanvas.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/onenter.js b/static/js/directives/onenter.js index 29272ce9..c86a10bb 100644 --- a/static/js/directives/onenter.js +++ b/static/js/directives/onenter.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/onescape.js b/static/js/directives/onescape.js index 3396a11f..ce19035e 100644 --- a/static/js/directives/onescape.js +++ b/static/js/directives/onescape.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/page.js b/static/js/directives/page.js index fd279d70..a03dd982 100644 --- a/static/js/directives/page.js +++ b/static/js/directives/page.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/pdfcanvas.js b/static/js/directives/pdfcanvas.js index 3ce31134..baf922c2 100644 --- a/static/js/directives/pdfcanvas.js +++ b/static/js/directives/pdfcanvas.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/presentation.js b/static/js/directives/presentation.js index 4737202a..82ef8709 100644 --- a/static/js/directives/presentation.js +++ b/static/js/directives/presentation.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/roombar.js b/static/js/directives/roombar.js index 250e0184..c6b8817b 100644 --- a/static/js/directives/roombar.js +++ b/static/js/directives/roombar.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/screenshare.js b/static/js/directives/screenshare.js index 4b6a598e..0e6c0726 100644 --- a/static/js/directives/screenshare.js +++ b/static/js/directives/screenshare.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/settings.js b/static/js/directives/settings.js index 925b03ad..f145b6de 100644 --- a/static/js/directives/settings.js +++ b/static/js/directives/settings.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/socialshare.js b/static/js/directives/socialshare.js index bd9292b8..a0576251 100644 --- a/static/js/directives/socialshare.js +++ b/static/js/directives/socialshare.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/statusmessage.js b/static/js/directives/statusmessage.js index ed45ee75..da50591d 100644 --- a/static/js/directives/statusmessage.js +++ b/static/js/directives/statusmessage.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/title.js b/static/js/directives/title.js index a62e5c16..a30a4750 100644 --- a/static/js/directives/title.js +++ b/static/js/directives/title.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/ui.js b/static/js/directives/ui.js index 41a19725..53e95b5d 100644 --- a/static/js/directives/ui.js +++ b/static/js/directives/ui.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/usability.js b/static/js/directives/usability.js index ce6bd434..260a57ac 100644 --- a/static/js/directives/usability.js +++ b/static/js/directives/usability.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/welcome.js b/static/js/directives/welcome.js index 801827c9..117ac279 100644 --- a/static/js/directives/welcome.js +++ b/static/js/directives/welcome.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/directives/youtubevideo.js b/static/js/directives/youtubevideo.js index 2264a74a..706570b9 100644 --- a/static/js/directives/youtubevideo.js +++ b/static/js/directives/youtubevideo.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/buddyimagesrc.js b/static/js/filters/buddyimagesrc.js index f1ac0d96..6abce770 100644 --- a/static/js/filters/buddyimagesrc.js +++ b/static/js/filters/buddyimagesrc.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/displayconference.js b/static/js/filters/displayconference.js index 1979fe19..a8a0fee2 100644 --- a/static/js/filters/displayconference.js +++ b/static/js/filters/displayconference.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/displayname.js b/static/js/filters/displayname.js index 20003426..a76d8fa0 100644 --- a/static/js/filters/displayname.js +++ b/static/js/filters/displayname.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/displaynameforsession.js b/static/js/filters/displaynameforsession.js index bde9ebc2..0f2f1841 100644 --- a/static/js/filters/displaynameforsession.js +++ b/static/js/filters/displaynameforsession.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/displayuserid.js b/static/js/filters/displayuserid.js index e8c0db61..e6afe04c 100644 --- a/static/js/filters/displayuserid.js +++ b/static/js/filters/displayuserid.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/filters.js b/static/js/filters/filters.js index b84df186..4f0cdcac 100644 --- a/static/js/filters/filters.js +++ b/static/js/filters/filters.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/filters/formatbase1000.js b/static/js/filters/formatbase1000.js index e675e2a5..28666c96 100644 --- a/static/js/filters/formatbase1000.js +++ b/static/js/filters/formatbase1000.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/main.js b/static/js/main.js index d78b9aaa..05f03d8f 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/api.js b/static/js/mediastream/api.js index 892e27e4..058b523c 100644 --- a/static/js/mediastream/api.js +++ b/static/js/mediastream/api.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/connector.js b/static/js/mediastream/connector.js index 0223d59c..80c18dfe 100644 --- a/static/js/mediastream/connector.js +++ b/static/js/mediastream/connector.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/peercall.js b/static/js/mediastream/peercall.js index 27055cc1..b954abdb 100644 --- a/static/js/mediastream/peercall.js +++ b/static/js/mediastream/peercall.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/peerconference.js b/static/js/mediastream/peerconference.js index 0f5aa805..f57aa20a 100644 --- a/static/js/mediastream/peerconference.js +++ b/static/js/mediastream/peerconference.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/peerconnection.js b/static/js/mediastream/peerconnection.js index 61df5d12..79800f86 100644 --- a/static/js/mediastream/peerconnection.js +++ b/static/js/mediastream/peerconnection.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/peerscreenshare.js b/static/js/mediastream/peerscreenshare.js index ec5fbf1b..a38a8f15 100644 --- a/static/js/mediastream/peerscreenshare.js +++ b/static/js/mediastream/peerscreenshare.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/peerxfer.js b/static/js/mediastream/peerxfer.js index bdc3dfb9..bba8d6e7 100644 --- a/static/js/mediastream/peerxfer.js +++ b/static/js/mediastream/peerxfer.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/tokens.js b/static/js/mediastream/tokens.js index 1bf48dfc..bf3dc98d 100644 --- a/static/js/mediastream/tokens.js +++ b/static/js/mediastream/tokens.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/usermedia.js b/static/js/mediastream/usermedia.js index 0761fbce..fb6d3de8 100644 --- a/static/js/mediastream/usermedia.js +++ b/static/js/mediastream/usermedia.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/mediastream/webrtc.js b/static/js/mediastream/webrtc.js index 28298fa3..17405cd2 100644 --- a/static/js/mediastream/webrtc.js +++ b/static/js/mediastream/webrtc.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/modules/angular-humanize.js b/static/js/modules/angular-humanize.js index 822afd56..aeeae8b7 100644 --- a/static/js/modules/angular-humanize.js +++ b/static/js/modules/angular-humanize.js @@ -1,6 +1,6 @@ /* * @license angular-humanize - * Copyright 2013-2014 struktur AG, http://www.struktur.de + * Copyright 2013-2015 struktur AG, http://www.struktur.de * License: MIT */ (function(window, angular, humanize, undefined) { diff --git a/static/js/services/alertify.js b/static/js/services/alertify.js index 945edb38..02e14e88 100644 --- a/static/js/services/alertify.js +++ b/static/js/services/alertify.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/animationframe.js b/static/js/services/animationframe.js index 67b56bfc..228b834b 100644 --- a/static/js/services/animationframe.js +++ b/static/js/services/animationframe.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/api.js b/static/js/services/api.js index a1a581eb..a63ce819 100644 --- a/static/js/services/api.js +++ b/static/js/services/api.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/appdata.js b/static/js/services/appdata.js index 9bcba939..d5c4e984 100644 --- a/static/js/services/appdata.js +++ b/static/js/services/appdata.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/buddydata.js b/static/js/services/buddydata.js index acbecbf6..25c4be77 100644 --- a/static/js/services/buddydata.js +++ b/static/js/services/buddydata.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/buddylist.js b/static/js/services/buddylist.js index 563cf9cd..032a324f 100644 --- a/static/js/services/buddylist.js +++ b/static/js/services/buddylist.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/buddypicture.js b/static/js/services/buddypicture.js index e5738a21..bc7fa744 100644 --- a/static/js/services/buddypicture.js +++ b/static/js/services/buddypicture.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/buddysession.js b/static/js/services/buddysession.js index 32da83d1..3006714a 100644 --- a/static/js/services/buddysession.js +++ b/static/js/services/buddysession.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/chromeextension.js b/static/js/services/chromeextension.js index ae1308eb..3f26a0df 100644 --- a/static/js/services/chromeextension.js +++ b/static/js/services/chromeextension.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/connector.js b/static/js/services/connector.js index 91cf5fc7..bc404a43 100644 --- a/static/js/services/connector.js +++ b/static/js/services/connector.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 99224615..3a5883b5 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/contactdata.js b/static/js/services/contactdata.js index d6daaf8a..3e40f89f 100644 --- a/static/js/services/contactdata.js +++ b/static/js/services/contactdata.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/contacts.js b/static/js/services/contacts.js index 7e7ddffa..8de55f51 100644 --- a/static/js/services/contacts.js +++ b/static/js/services/contacts.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/continueconnector.js b/static/js/services/continueconnector.js index b02b75c8..afa55346 100644 --- a/static/js/services/continueconnector.js +++ b/static/js/services/continueconnector.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/desktopnotify.js b/static/js/services/desktopnotify.js index 7ccdfb8f..5484e720 100644 --- a/static/js/services/desktopnotify.js +++ b/static/js/services/desktopnotify.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/dialogs.js b/static/js/services/dialogs.js index 2328bbeb..87e3ebd1 100644 --- a/static/js/services/dialogs.js +++ b/static/js/services/dialogs.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/enrichmessage.js b/static/js/services/enrichmessage.js index 328d394c..379f0bd5 100644 --- a/static/js/services/enrichmessage.js +++ b/static/js/services/enrichmessage.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/fastscroll.js b/static/js/services/fastscroll.js index e472268b..c18b0f0f 100644 --- a/static/js/services/fastscroll.js +++ b/static/js/services/fastscroll.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/filedata.js b/static/js/services/filedata.js index e31eaa0b..1ed4e83e 100644 --- a/static/js/services/filedata.js +++ b/static/js/services/filedata.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/filedownload.js b/static/js/services/filedownload.js index d47b7842..9bcd167d 100644 --- a/static/js/services/filedownload.js +++ b/static/js/services/filedownload.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/filetransfer.js b/static/js/services/filetransfer.js index 91411893..def147e2 100644 --- a/static/js/services/filetransfer.js +++ b/static/js/services/filetransfer.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/fileupload.js b/static/js/services/fileupload.js index b593415f..53275ce6 100644 --- a/static/js/services/fileupload.js +++ b/static/js/services/fileupload.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/geolocation.js b/static/js/services/geolocation.js index 281fbcc4..5eb7fe19 100644 --- a/static/js/services/geolocation.js +++ b/static/js/services/geolocation.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/localstatus.js b/static/js/services/localstatus.js index 55333972..7fb083b6 100644 --- a/static/js/services/localstatus.js +++ b/static/js/services/localstatus.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/localstorage.js b/static/js/services/localstorage.js index b2955087..e156b0ee 100644 --- a/static/js/services/localstorage.js +++ b/static/js/services/localstorage.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * @@ -25,7 +25,7 @@ define(["modernizr"], function(Modernizr) { // localStorage return ["$window", function($window) { - // PersistentStorage (c)2014 struktur AG. MIT license. + // PersistentStorage (c)2015 struktur AG. MIT license. var PersistentStorage = function(prefix) { this.prefix = prefix ? prefix : "ps"; this.isPersistentStorage = true; diff --git a/static/js/services/mediadevices.js b/static/js/services/mediadevices.js index 5680aa1a..e11c9fce 100644 --- a/static/js/services/mediadevices.js +++ b/static/js/services/mediadevices.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/mediasources.js b/static/js/services/mediasources.js index e16b2ab2..22172219 100644 --- a/static/js/services/mediasources.js +++ b/static/js/services/mediasources.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/mediastream.js b/static/js/services/mediastream.js index f1ddfc5f..b116b3fc 100644 --- a/static/js/services/mediastream.js +++ b/static/js/services/mediastream.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/modules.js b/static/js/services/modules.js index 98d7ac51..99d9f844 100644 --- a/static/js/services/modules.js +++ b/static/js/services/modules.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/playsound.js b/static/js/services/playsound.js index b6acd876..eb682416 100644 --- a/static/js/services/playsound.js +++ b/static/js/services/playsound.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/randomgen.js b/static/js/services/randomgen.js index 647441a0..24c1a983 100644 --- a/static/js/services/randomgen.js +++ b/static/js/services/randomgen.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/resturl.js b/static/js/services/resturl.js index 6ffe19d8..4ba4ad73 100644 --- a/static/js/services/resturl.js +++ b/static/js/services/resturl.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/roompin.js b/static/js/services/roompin.js index b73aeaba..4eaa237a 100644 --- a/static/js/services/roompin.js +++ b/static/js/services/roompin.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/rooms.js b/static/js/services/rooms.js index f21bee68..93c9b0fb 100644 --- a/static/js/services/rooms.js +++ b/static/js/services/rooms.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/safeapply.js b/static/js/services/safeapply.js index 84d313ec..1b943d84 100644 --- a/static/js/services/safeapply.js +++ b/static/js/services/safeapply.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/safedisplayname.js b/static/js/services/safedisplayname.js index ff781d95..6519592d 100644 --- a/static/js/services/safedisplayname.js +++ b/static/js/services/safedisplayname.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/safemessage.js b/static/js/services/safemessage.js index b0a7e2b0..c1687fa2 100644 --- a/static/js/services/safemessage.js +++ b/static/js/services/safemessage.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/screensharing.js b/static/js/services/screensharing.js index 5a5f572b..2cc5c54f 100644 --- a/static/js/services/screensharing.js +++ b/static/js/services/screensharing.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/services.js b/static/js/services/services.js index b0fb7d02..b95c52fd 100644 --- a/static/js/services/services.js +++ b/static/js/services/services.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/toastr.js b/static/js/services/toastr.js index f2b521ba..ff70eb5b 100644 --- a/static/js/services/toastr.js +++ b/static/js/services/toastr.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/translation.js b/static/js/services/translation.js index 2641e85d..4ecc9545 100644 --- a/static/js/services/translation.js +++ b/static/js/services/translation.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/usersettingsdata.js b/static/js/services/usersettingsdata.js index 810a44f0..1772968e 100644 --- a/static/js/services/usersettingsdata.js +++ b/static/js/services/usersettingsdata.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/videolayout.js b/static/js/services/videolayout.js index fdbb3a4f..3718f439 100644 --- a/static/js/services/videolayout.js +++ b/static/js/services/videolayout.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/videowaiter.js b/static/js/services/videowaiter.js index bb15c78c..6a57af9b 100644 --- a/static/js/services/videowaiter.js +++ b/static/js/services/videowaiter.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/visibility.js b/static/js/services/visibility.js index 7296adf1..a487b30c 100644 --- a/static/js/services/visibility.js +++ b/static/js/services/visibility.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * diff --git a/static/js/services/webrtc.js b/static/js/services/webrtc.js index 7b8cdd08..fe3243fb 100644 --- a/static/js/services/webrtc.js +++ b/static/js/services/webrtc.js @@ -1,6 +1,6 @@ /* * Spreed WebRTC. - * Copyright (C) 2013-2014 struktur AG + * Copyright (C) 2013-2015 struktur AG * * This file is part of Spreed WebRTC. * From 856a23facad99abb5f36bd63f49b30f7f132a442 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 22 Apr 2015 14:03:37 +0200 Subject: [PATCH 053/121] Correct some errors found by golint. --- src/app/spreed-webrtc-server/config.go | 2 +- src/app/spreed-webrtc-server/main.go | 42 ++++++++++---------- src/app/spreed-webrtc-server/room_manager.go | 5 +-- src/app/spreed-webrtc-server/tokens.go | 5 +-- src/app/spreed-webrtc-server/user.go | 6 ++- src/app/spreed-webrtc-server/users.go | 13 +++--- 6 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/app/spreed-webrtc-server/config.go b/src/app/spreed-webrtc-server/config.go index e6899989..bda9e096 100644 --- a/src/app/spreed-webrtc-server/config.go +++ b/src/app/spreed-webrtc-server/config.go @@ -96,7 +96,7 @@ func NewConfig(container phoenix.Container, tokens bool) *Config { "contacts": true, } modules := []string{} - for module, _ := range modulesTable { + for module := range modulesTable { if container.GetBoolDefault("modules", module, true) { modules = append(modules, module) } else { diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 80649a00..13fd051a 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -196,15 +196,14 @@ func runner(runtime phoenix.Runtime) error { sessionSecretString, err := runtime.GetString("app", "sessionSecret") if err != nil { return fmt.Errorf("No sessionSecret in config file.") - } else { - sessionSecret, err = hex.DecodeString(sessionSecretString) - if err != nil { - log.Println("Warning: sessionSecret value is not a hex encoded", err) - sessionSecret = []byte(sessionSecretString) - } - if len(sessionSecret) < 32 { - return fmt.Errorf("Length of sessionSecret must be at least 32 bytes.") - } + } + sessionSecret, err = hex.DecodeString(sessionSecretString) + if err != nil { + log.Println("Warning: sessionSecret value is not a hex encoded", err) + sessionSecret = []byte(sessionSecretString) + } + if len(sessionSecret) < 32 { + return fmt.Errorf("Length of sessionSecret must be at least 32 bytes.") } if len(sessionSecret) < 32 { @@ -215,19 +214,18 @@ func runner(runtime phoenix.Runtime) error { encryptionSecretString, err := runtime.GetString("app", "encryptionSecret") if err != nil { return fmt.Errorf("No encryptionSecret in config file.") - } else { - encryptionSecret, err = hex.DecodeString(encryptionSecretString) - if err != nil { - log.Println("Warning: encryptionSecret value is not a hex encoded", err) - encryptionSecret = []byte(encryptionSecretString) - } - switch l := len(encryptionSecret); { - case l == 16: - case l == 24: - case l == 32: - default: - return fmt.Errorf("Length of encryptionSecret must be exactly 16, 24 or 32 bytes to select AES-128, AES-192 or AES-256.") - } + } + encryptionSecret, err = hex.DecodeString(encryptionSecretString) + if err != nil { + log.Println("Warning: encryptionSecret value is not a hex encoded", err) + encryptionSecret = []byte(encryptionSecretString) + } + switch l := len(encryptionSecret); { + case l == 16: + case l == 24: + case l == 32: + default: + return fmt.Errorf("Length of encryptionSecret must be exactly 16, 24 or 32 bytes to select AES-128, AES-192 or AES-256.") } var turnSecret []byte diff --git a/src/app/spreed-webrtc-server/room_manager.go b/src/app/spreed-webrtc-server/room_manager.go index 091e17d4..64b5f4bd 100644 --- a/src/app/spreed-webrtc-server/room_manager.go +++ b/src/app/spreed-webrtc-server/room_manager.go @@ -111,10 +111,9 @@ func (rooms *roomManager) UpdateRoom(session *Session, room *DataRoom) (*DataRoo } if roomWorker, ok := rooms.Get(session.Roomid); ok { return room, roomWorker.Update(room) - } else { - // Set default room type if not found. - room.Type = rooms.roomTypeDefault } + // Set default room type if room was not found. + room.Type = rooms.roomTypeDefault // TODO(lcooper): We should almost certainly return an error in this case. return room, nil } diff --git a/src/app/spreed-webrtc-server/tokens.go b/src/app/spreed-webrtc-server/tokens.go index 0f172b9a..d492d265 100644 --- a/src/app/spreed-webrtc-server/tokens.go +++ b/src/app/spreed-webrtc-server/tokens.go @@ -49,9 +49,8 @@ func (tokens Tokens) Post(request *http.Request) (int, interface{}, http.Header) if valid != "" { log.Printf("Good incoming token request: %s\n", auth) return 200, &Token{Token: valid, Success: true}, http.Header{"Content-Type": {"application/json"}} - } else { - log.Printf("Wrong incoming token request: %s\n", auth) - return 403, NewApiError("invalid_token", "Invalid token"), http.Header{"Content-Type": {"application/json"}} } + log.Printf("Wrong incoming token request: %s\n", auth) + return 403, NewApiError("invalid_token", "Invalid token"), http.Header{"Content-Type": {"application/json"}} } diff --git a/src/app/spreed-webrtc-server/user.go b/src/app/spreed-webrtc-server/user.go index 4b8d9807..c6e2b279 100644 --- a/src/app/spreed-webrtc-server/user.go +++ b/src/app/spreed-webrtc-server/user.go @@ -43,7 +43,8 @@ func NewUser(id string) *User { } -// Return true if first session. +// AddSession adds a session to the session table and returns true if +// s is the first session. func (u *User) AddSession(s *Session) bool { first := false u.mutex.Lock() @@ -56,7 +57,8 @@ func (u *User) AddSession(s *Session) bool { return first } -// Return true if no session left. +// RemoveSession removes a session from the session table abd returns +// true if no session is left left. func (u *User) RemoveSession(sessionID string) bool { last := false u.mutex.Lock() diff --git a/src/app/spreed-webrtc-server/users.go b/src/app/spreed-webrtc-server/users.go index 3c991c6f..6dac32bb 100644 --- a/src/app/spreed-webrtc-server/users.go +++ b/src/app/spreed-webrtc-server/users.go @@ -46,7 +46,7 @@ import ( ) var ( - serialNumberLimit *big.Int = new(big.Int).Lsh(big.NewInt(1), 128) + serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) ) type UsersHandler interface { @@ -229,12 +229,12 @@ func (uh *UsersCertificateHandler) Create(un *UserNonce, request *http.Request) } spkacDerBytes, err := base64.StdEncoding.DecodeString(spkac) if err != nil { - return nil, errors.New(fmt.Sprintf("spkac invalid: %s", err)) + return nil, fmt.Errorf("spkac invalid: %s", err) } publicKey, err := pkac.ParseSPKAC(spkacDerBytes) if err != nil { - return nil, errors.New(fmt.Sprintf("unable to parse spkac: %s", err)) + return nil, fmt.Errorf("unable to parse spkac: %s", err) } template, err := uh.makeTemplate(un.Userid) @@ -244,7 +244,7 @@ func (uh *UsersCertificateHandler) Create(un *UserNonce, request *http.Request) certDerBytes, err := x509.CreateCertificate(rand.Reader, template, uh.certificate, publicKey, uh.privateKey) if err != nil { - return nil, errors.New(fmt.Sprintf("failed to create certificate: %s", err)) + return nil, fmt.Errorf("failed to create certificate: %s", err) } log.Println("Generated new certificate", un.Userid) @@ -284,10 +284,9 @@ func (un *UserNonce) Response() (int, interface{}, http.Header) { if un.contentType != "" { header.Set("Content-Type", un.contentType) return 200, un.raw, header - } else { - header.Set("Content-Type", "application/json") - return 200, un, header } + header.Set("Content-Type", "application/json") + return 200, un, header } type Users struct { From 2be68c554c3af8fc777301b472672e3cec0abeed Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Wed, 22 Apr 2015 14:16:57 +0200 Subject: [PATCH 054/121] Moved default room type to config. --- src/app/spreed-webrtc-server/config.go | 2 ++ src/app/spreed-webrtc-server/room_manager.go | 18 +++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/spreed-webrtc-server/config.go b/src/app/spreed-webrtc-server/config.go index bda9e096..94dbd11f 100644 --- a/src/app/spreed-webrtc-server/config.go +++ b/src/app/spreed-webrtc-server/config.go @@ -52,6 +52,7 @@ type Config struct { globalRoomID string // Id of the global room (not exported to Javascript) contentSecurityPolicy string // HTML content security policy contentSecurityPolicyReportOnly string // HTML content security policy in report only mode + roomTypeDefault string // New rooms default to this type } func NewConfig(container phoenix.Container, tokens bool) *Config { @@ -127,6 +128,7 @@ func NewConfig(container phoenix.Container, tokens bool) *Config { globalRoomID: container.GetStringDefault("app", "globalRoom", ""), contentSecurityPolicy: container.GetStringDefault("app", "contentSecurityPolicy", ""), contentSecurityPolicyReportOnly: container.GetStringDefault("app", "contentSecurityPolicyReportOnly", ""), + roomTypeDefault: "Room", } } diff --git a/src/app/spreed-webrtc-server/room_manager.go b/src/app/spreed-webrtc-server/room_manager.go index 64b5f4bd..76a77faa 100644 --- a/src/app/spreed-webrtc-server/room_manager.go +++ b/src/app/spreed-webrtc-server/room_manager.go @@ -53,21 +53,17 @@ type roomManager struct { sync.RWMutex *Config OutgoingEncoder - roomTable map[string]RoomWorker - globalRoomID string - defaultRoomID string - roomTypeDefault string + roomTable map[string]RoomWorker + globalRoomID string + defaultRoomID string } func NewRoomManager(config *Config, encoder OutgoingEncoder) RoomManager { rm := &roomManager{ - sync.RWMutex{}, - config, - encoder, - make(map[string]RoomWorker), - "", - "", - "Room", + RWMutex: sync.RWMutex{}, + Config: config, + OutgoingEncoder: encoder, + roomTable: make(map[string]RoomWorker), } rm.globalRoomID = rm.MakeRoomID(config.globalRoomID, "") rm.defaultRoomID = rm.MakeRoomID("", "") From 29fc1baa51bf0f45b188b0863c5cd889155626fc Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 23 Apr 2015 02:12:12 +0200 Subject: [PATCH 055/121] Initial code to support running YouTube player in a sandboxed iframe. --- static/js/directives/youtubevideo.js | 155 ++++++++++++------- static/partials/youtubevideo.html | 2 +- static/partials/youtubevideo_sandbox.html | 175 ++++++++++++++++++++++ 3 files changed, 277 insertions(+), 55 deletions(-) create mode 100644 static/partials/youtubevideo_sandbox.html diff --git a/static/js/directives/youtubevideo.js b/static/js/directives/youtubevideo.js index 706570b9..986cb1ed 100644 --- a/static/js/directives/youtubevideo.js +++ b/static/js/directives/youtubevideo.js @@ -20,20 +20,65 @@ */ "use strict"; -define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], function($, _, template, BigScreen) { +define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partials/youtubevideo_sandbox.html', 'bigscreen'], function($, _, template, sandboxTemplate, BigScreen) { return ["$window", "$document", "mediaStream", "alertify", "translation", "safeApply", "appData", "$q", function($window, $document, mediaStream, alertify, translation, safeApply, appData, $q) { var YOUTUBE_IFRAME_API_URL = "//www.youtube.com/iframe_api"; - var isYouTubeIframeAPIReady = (function() { - var d = $q.defer(); - $window.onYouTubeIframeAPIReady = function() { - console.log("YouTube IFrame ready"); - d.resolve(); - }; - return d.promise; - })(); + var Sandbox = function(iframe) { + this.iframe = iframe; + this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(sandboxTemplate); + this.target = this.iframe.contentWindow; + }; + + Sandbox.prototype.postMessage = function(type, message) { + var msg = {"type": type} + msg[type] = message; + this.target.postMessage(msg, "*"); + }; + + var SandboxPlayer = function(sandbox, params) { + this.sandbox = sandbox; + this.sandbox.postMessage("loadPlayer", params); + }; + + SandboxPlayer.prototype.destroy = function() { + this.sandbox.postMessage("destroyPlayer", {"destroy": true}); + }; + + SandboxPlayer.prototype.loadVideoById = function(id, position) { + var msg = {"id": id}; + if (typeof(position) !== "undefined") { + msg.position = position; + } + this.sandbox.postMessage("loadVideo", msg); + }; + + SandboxPlayer.prototype.playVideo = function() { + this.sandbox.postMessage("playVideo", {"play": true}); + }; + + SandboxPlayer.prototype.pauseVideo = function() { + this.sandbox.postMessage("pauseVideo", {"pause": true}); + }; + + SandboxPlayer.prototype.stopVideo = function() { + this.sandbox.postMessage("stopVideo", {"stop": true}); + }; + + SandboxPlayer.prototype.seekTo = function(position, allowSeekAhead) { + var msg = {"position": position}; + if (typeof(allowSeekAhead) !== "undefined") { + msg.allowSeekAhead = allowSeekAhead; + } + this.sandbox.postMessage("seekTo", msg); + }; + + SandboxPlayer.prototype.getCurrentTime = function() { + // TODO(fancycode): implement me + return 0; + }; var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { @@ -47,14 +92,49 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], var prevNow = null; var initialState = null; - var stateEvents = { - "-1": "youtube.unstarted", - "0": "youtube.ended", - "1": "youtube.playing", - "2": "youtube.paused", - "3": "youtube.buffering", - "5": "youtube.videocued" + var sandbox = new Sandbox($("#youtubeplayer", $element)[0]); + + var isYouTubeIframeAPIReadyDefer = $q.defer(); + var isYouTubeIframeAPIReady = isYouTubeIframeAPIReadyDefer.promise; + + var onPostMessage = function(event) { + var msg = event.data; + var data = msg[msg.type] || {}; + switch (msg.type) { + case "youtube.apiReady": + $scope.$apply(function() { + console.log("YouTube IFrame ready"); + isYouTubeIframeAPIReadyDefer.resolve(); + }); + break; + case "youtube.playerReady": + $scope.$apply(function() { + playerReady.resolve(); + }); + break; + case "youtube.volume": + $scope.$apply(function(scope) { + scope.volume = data.volume; + }); + break; + case "youtube.event": + $scope.$apply(function(scope) { + console.log("State change", data.event); + scope.$emit(data.event); + }); + break; + default: + console.log("Unknown message received", event); + break; + } }; + + $window.addEventListener("message", onPostMessage, false); + + $scope.$on("$destroy", function() { + $window.removeEventListener("message", onPostMessage, false); + }); + var errorIds = { "2": "invalidParameter", "5": "htmlPlayerError", @@ -79,13 +159,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], }); }); - var onPlayerReady = function(event) { - $scope.$apply(function(scope) { - scope.volume = player.getVolume(); - playerReady.resolve(); - }); - }; - var onPlayerError = function(event) { var error = errorIds[event.data] || "unknownError"; $scope.$apply(function(scope) { @@ -93,19 +166,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], }); }; - var onPlayerStateChange = function(event) { - var msg = stateEvents[event.data]; - if (typeof msg === "undefined") { - console.warn("Unknown YouTube player state", event) - return; - } - - $scope.$apply(function(scope) { - console.log("State change", msg, event.target); - scope.$emit(msg, event.target); - }); - }; - var getYouTubeId = function(url) { /* * Supported URLs: @@ -131,6 +191,8 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], } var startDetectSeek = function() { + // TODO(fancycode): seek detection should be implemented in the sandbox + /* var checkSeek = function() { if (!player) { return; @@ -160,6 +222,7 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], }, 1000); } checkSeek(); + */ }; var stopDetectSeek = function() { @@ -278,7 +341,7 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], isYouTubeIframeAPIReady.then(function() { if (!player) { var origin = $window.location.protocol + "//" + $window.location.host; - player = new $window.YT.Player("youtubeplayer", { + player = new SandboxPlayer(sandbox, { height: "390", width: "640", playerVars: { @@ -291,10 +354,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], "controls": with_controls ? "2" : "0", "disablekb": with_controls ? "0" : "1", "origin": origin - }, - events: { - "onReady": onPlayerReady, - "onStateChange": onPlayerStateChange } }); $("#youtubeplayer").show(); @@ -475,19 +534,7 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'bigscreen'], }; $scope.loadYouTubeAPI = function() { - if (!addedIframeScript) { - var head = $document[0].getElementsByTagName('head')[0]; - var script = $document[0].createElement('script'); - script.type = "text/javascript"; - script.src = YOUTUBE_IFRAME_API_URL; - script.onerror = function(event) { - alertify.dialog.alert(translation._("Could not load YouTube player API, please check your network / firewall settings.")); - head.removeChild(script); - addedIframeScript = false; - }; - head.appendChild(script); - addedIframeScript = true; - } + sandbox.postMessage("loadApi", {"url": $window.location.protocol + YOUTUBE_IFRAME_API_URL}); }; $scope.showYouTubeVideo = function() { diff --git a/static/partials/youtubevideo.html b/static/partials/youtubevideo.html index 5fe5e3d3..b7c8350f 100644 --- a/static/partials/youtubevideo.html +++ b/static/partials/youtubevideo.html @@ -31,7 +31,7 @@
-
+
{{_('Currently playing')}}
{{ currentVideoUrl }}
diff --git a/static/partials/youtubevideo_sandbox.html b/static/partials/youtubevideo_sandbox.html new file mode 100644 index 00000000..3b434ed8 --- /dev/null +++ b/static/partials/youtubevideo_sandbox.html @@ -0,0 +1,175 @@ + + + + YouTube Player Sandbox + + + +
+ + + From c8ad76005b830768e36dcfdbfd97adbfdd503099 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 23 Apr 2015 12:21:04 +0200 Subject: [PATCH 056/121] Added seek and volume support, check origins in postMessage receivers. --- static/js/directives/youtubevideo.js | 89 +++++++---------------- static/partials/youtubevideo_sandbox.html | 82 ++++++++++++++++++++- 2 files changed, 104 insertions(+), 67 deletions(-) diff --git a/static/js/directives/youtubevideo.js b/static/js/directives/youtubevideo.js index 986cb1ed..6290f1aa 100644 --- a/static/js/directives/youtubevideo.js +++ b/static/js/directives/youtubevideo.js @@ -26,9 +26,13 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial var YOUTUBE_IFRAME_API_URL = "//www.youtube.com/iframe_api"; + var origin = $window.location.protocol + "//" + $window.location.host; + var Sandbox = function(iframe) { this.iframe = iframe; - this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(sandboxTemplate); + var template = sandboxTemplate; + template = template.replace(/__PARENT__ORIGIN__/g, origin); + this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(template); this.target = this.iframe.contentWindow; }; @@ -75,21 +79,28 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial this.sandbox.postMessage("seekTo", msg); }; + SandboxPlayer.prototype.setVolume = function(volume) { + this.sandbox.postMessage("setVolume", {"volume": volume}); + + }; + SandboxPlayer.prototype.getCurrentTime = function() { // TODO(fancycode): implement me return 0; }; + SandboxPlayer.prototype.getPlayerState = function() { + // TODO(fancycode): implement me + return null; + } + var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var addedIframeScript = false; var player = null; var playerReady = null; var isPaused = null; - var seekDetector = null; var playReceivedNow = null; - var prevTime = null; - var prevNow = null; var initialState = null; var sandbox = new Sandbox($("#youtubeplayer", $element)[0]); @@ -98,6 +109,10 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial var isYouTubeIframeAPIReady = isYouTubeIframeAPIReadyDefer.promise; var onPostMessage = function(event) { + if (event.origin !== "null" || event.source !== sandbox.target) { + // the sandboxed data-url iframe has "null" as origin + return; + } var msg = event.data; var data = msg[msg.type] || {}; switch (msg.type) { @@ -119,8 +134,8 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial break; case "youtube.event": $scope.$apply(function(scope) { - console.log("State change", data.event); - scope.$emit(data.event); + console.log("State change", data); + scope.$emit(data.event, data.position); }); break; default: @@ -190,82 +205,34 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial return null; } - var startDetectSeek = function() { - // TODO(fancycode): seek detection should be implemented in the sandbox - /* - var checkSeek = function() { - if (!player) { - return; - } - var now = new Date(); - var time = player.getCurrentTime(); - if (prevTime === null) { - prevTime = time; - } - if (prevNow === null) { - prevNow = now; - } - var deltaTime = Math.abs(time - prevTime); - var deltaNow = (now - prevNow) * 0.001; - if (deltaTime > deltaNow * 1.1) { - safeApply($scope, function(scope) { - scope.$emit("youtube.seeked", time); - }); - } - prevNow = now; - prevTime = time; - }; - - if (!seekDetector) { - seekDetector = $window.setInterval(function() { - checkSeek(); - }, 1000); - } - checkSeek(); - */ - }; - - var stopDetectSeek = function() { - if (seekDetector) { - $window.clearInterval(seekDetector); - seekDetector = null; - } - prevNow = null; - }; - - $scope.$on("youtube.playing", function() { + $scope.$on("youtube.playing", function(event, position) { if (initialState === 2) { initialState = null; player.pauseVideo(); return; } - prevTime = null; - startDetectSeek(); if (isPaused) { isPaused = false; mediaStream.webrtc.callForEachCall(function(peercall) { mediaStreamSendYouTubeVideo(peercall, currentToken, { Type: "Resume", Resume: { - position: player.getCurrentTime() + position: position } }); }); } }); - $scope.$on("youtube.buffering", function() { + $scope.$on("youtube.buffering", function(event, position) { if (initialState === 2) { initialState = null; player.pauseVideo(); } - - startDetectSeek(); }); - $scope.$on("youtube.paused", function() { - stopDetectSeek(); + $scope.$on("youtube.paused", function(event, position) { if (!$scope.isPublisher || !currentToken) { return; } @@ -276,7 +243,7 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial mediaStreamSendYouTubeVideo(peercall, currentToken, { Type: "Pause", Pause: { - position: player.getCurrentTime() + position: position } }); }); @@ -284,7 +251,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial }); $scope.$on("youtube.ended", function() { - stopDetectSeek(); }); $scope.$on("youtube.seeked", function($event, position) { @@ -306,8 +272,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial playerReady.done(function() { $("#youtubeplayer").show(); $scope.playbackActive = true; - prevTime = null; - prevNow = null; isPaused = null; if (playReceivedNow) { var delta = ((new Date()) - playReceivedNow) * 0.001; @@ -585,7 +549,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial $scope.currentVideoUrl = null; $scope.currentVideoId = null; peers = {}; - stopDetectSeek(); playerReady = null; initialState = null; mediaStream.webrtc.e.off("statechange", updater); diff --git a/static/partials/youtubevideo_sandbox.html b/static/partials/youtubevideo_sandbox.html index 3b434ed8..bba0e6f1 100644 --- a/static/partials/youtubevideo_sandbox.html +++ b/static/partials/youtubevideo_sandbox.html @@ -24,17 +24,22 @@ - + + From 02bda0367de1cd89d1736048077b3f7c7f768d7e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 23 Apr 2015 16:48:29 +0200 Subject: [PATCH 061/121] Merge rule (found by Hound). --- src/styles/components/_youtubevideo.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles/components/_youtubevideo.scss b/src/styles/components/_youtubevideo.scss index aebde5ff..75645690 100644 --- a/src/styles/components/_youtubevideo.scss +++ b/src/styles/components/_youtubevideo.scss @@ -92,10 +92,10 @@ #youtubecontainer { // scss-lint:disable IdSelector position: relative; -} -#youtubecontainer.fullscreen { // scss-lint:disable IdSelector - width: 100%; + &.fullscreen { + width: 100%; + } } #youtubeplayerinfo { // scss-lint:disable IdSelector From 4db499cca39a38eb388e167fa1ffd5121b00c864 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Fri, 24 Apr 2015 10:21:18 +0200 Subject: [PATCH 062/121] MJPEG fix was backported to FF38. So we allow HD constraints starting with FF38 now. --- static/js/services/constraints.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/js/services/constraints.js b/static/js/services/constraints.js index 3a5883b5..29c3b02e 100644 --- a/static/js/services/constraints.js +++ b/static/js/services/constraints.js @@ -196,8 +196,8 @@ return { // Chrome supports it. FF supports new spec starting 38. See https://wiki.mozilla.org/Media/getUserMedia for FF details. audioVideo: isChrome || (isFirefox && version >= 38), - // HD constraints in Chrome no issue. In FF we MJPEG is fixed with 40 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1151628). - hdVideo: isChrome || (isFirefox && version >= 40), + // HD constraints in Chrome no issue. In FF we MJPEG is fixed with 38 (see https://bugzilla.mozilla.org/show_bug.cgi?id=1151628). + hdVideo: isChrome || (isFirefox && version >= 38), // Chrome supports this on Windows only. renderToAssociatedSink: isChrome && $window.navigator.platform.indexOf("Win") === 0, chrome: isChrome, From cbe9c0b51fb9733762388857fa8aa261e5dada0f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 11:34:18 +0200 Subject: [PATCH 063/121] Don't use global "encodeURI". --- static/js/services/sandbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/services/sandbox.js b/static/js/services/sandbox.js index 0bc5e9ef..d3f65a4a 100644 --- a/static/js/services/sandbox.js +++ b/static/js/services/sandbox.js @@ -26,7 +26,7 @@ define(["jquery", "underscore"], function($, _) { var Sandbox = function(iframe, template) { this.iframe = iframe; - this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(template); + this.iframe.src = "data:text/html;charset=utf-8," + $window.encodeURI(template); this.target = this.iframe.contentWindow; this.e = $({}); this.handler = _.bind(this.onPostMessageReceived, this); From c973103c31c154f748ab5ec4346f0e7d50c5d28c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 10:47:32 +0200 Subject: [PATCH 064/121] Run pdf.js rendering inside sandboxed iframe. --- src/styles/components/_presentation.scss | 11 +- static/js/directives/pdfcanvas.js | 211 +++++++---------- static/js/directives/presentation.js | 33 +-- static/js/sandboxes/pdf.js | 281 +++++++++++++++++++++++ static/js/sandboxes/youtube.js | 1 + static/js/services/sandbox.js | 20 ++ static/partials/pdfcanvas_sandbox.html | 33 +++ 7 files changed, 441 insertions(+), 149 deletions(-) create mode 100644 static/js/sandboxes/pdf.js create mode 100644 static/partials/pdfcanvas_sandbox.html diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index 09583e6c..b5f9a583 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -197,12 +197,13 @@ .canvasContainer { height: 100%; width: 100%; - } + overflow: hidden; - canvas { - display: block; - margin: 0 auto; - position: relative; + iframe { + border: 0; + width: 100%; + height: 100%; + } } .odfcanvas { diff --git a/static/js/directives/pdfcanvas.js b/static/js/directives/pdfcanvas.js index baf922c2..8c51ab15 100644 --- a/static/js/directives/pdfcanvas.js +++ b/static/js/directives/pdfcanvas.js @@ -20,9 +20,9 @@ */ "use strict"; -define(['require', 'underscore', 'jquery'], function(require, _, $) { +define(['require', 'underscore', 'jquery', 'text!partials/pdfcanvas_sandbox.html'], function(require, _, $, sandboxTemplate) { - return ["$window", "$compile", "translation", "safeApply", function($window, $compile, translation, safeApply) { + return ["$window", "$compile", "$http", "translation", "safeApply", 'restURL', 'sandbox', function($window, $compile, $http, translation, safeApply, restURL, sandbox) { var pdfjs = null; @@ -30,28 +30,69 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { var container = $($element); - var PDFCanvas = function(scope, canvases) { + var pdfCanvas; + + var template = sandboxTemplate; + template = template.replace(/__PARENT_ORIGIN__/g, $window.location.protocol + "//" + $window.location.host); + template = template.replace(/__PDFJS_SANDBOX_JS_URL__/g, restURL.createAbsoluteUrl(require.toUrl('sandboxes/pdf') + ".js")); + template = template.replace(/__PDFJS_URL__/g, restURL.createAbsoluteUrl(require.toUrl('pdf') + ".js")); + template = template.replace(/__PDFJS_WORKER_URL__/g, restURL.createAbsoluteUrl(require.toUrl('pdf.worker') + ".js")); + template = template.replace(/__PDFJS_COMPATIBILITY_URL__/g, restURL.createAbsoluteUrl(require.toUrl('libs/pdf/compatibility') + ".js")); + var sandboxApi = sandbox.createSandbox($("iframe", container)[0], template); + + sandboxApi.e.on("message", function(event, message) { + var msg = message.data; + var data = msg[msg.type] || {}; + switch (msg.type) { + case "pdfjs.loading": + $scope.$apply(function(scope) { + scope.$emit("presentationLoading", data.source); + }); + break; + case "pdfjs.loaded": + pdfCanvas._pdfLoaded(data.source, data.doc); + break; + case "pdfjs.loadError": + pdfCanvas._pdfLoadError(data.source, data.error); + break; + case "pdfjs.pageLoaded": + pdfCanvas._pageLoaded(data.page); + break; + case "pdfjs.pageLoadError": + pdfCanvas._pageLoadError(data.page, data.error); + break; + case "pdfjs.renderingPage": + $scope.$apply(function(scope) { + scope.$emit("presentationPageRendering", data.page); + }); + break; + case "pdfjs.pageRendered": + pdfCanvas._pageRendered(data.page); + break; + case "pdfjs.pageRenderError": + pdfCanvas._pageRenderError(data.page, data.error); + break; + case "pdfjs.keyUp": + $scope.$apply(function(scope) { + scope.$emit("keyUp", data.key); + }); + break; + default: + console.log("Unknown message received", message); + break; + } + }); + + var PDFCanvas = function(scope) { this.scope = scope; - this.canvases = canvases; this.doc = null; - this.currentPage = null; this.currentPageNumber = null; this.pendingPageNumber = null; - this.renderTask = null; this.url = null; }; - PDFCanvas.prototype._close = function() { - this._stopRendering(); - if (this.currentPage) { - this.currentPage.destroy(); - this.currentPage = null; - } - if (this.doc) { - this.doc.cleanup(); - this.doc.destroy(); - this.doc = null; - } + PDFCanvas.prototype.close = function() { + sandboxApi.postMessage("closeFile", {"close": true}); if (this.url) { URL.revokeObjectURL(this.url); this.url = null; @@ -59,20 +100,13 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { this.pendingPageNumber = null; this.currentPageNumber = -1; this.maxPageNumber = -1; - // clear visible canvas so it's empty when we show the next document - var canvas = this.canvases[this.scope.canvasIndex]; - canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); - }; - - PDFCanvas.prototype.close = function() { - this._close(); }; PDFCanvas.prototype.open = function(presentation) { this.scope.$emit("presentationOpening", presentation); presentation.open(_.bind(function(source) { console.log("Loading PDF from", source); - this._close(); + this.close(); if (typeof source === "string") { // got a url this._openFile(source); @@ -100,7 +134,6 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { this.doc = doc; this.maxPageNumber = doc.numPages; this.currentPageNumber = -1; - console.log("PDF loaded", doc); scope.$emit("presentationLoaded", source, doc); }, this)); }; @@ -127,43 +160,30 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { }, this)); }; - PDFCanvas.prototype._doOpenFile = function(source) { - this.scope.$emit("presentationLoading", source); - pdfjs.getDocument(source).then(_.bind(function(doc) { - this._pdfLoaded(source, doc); - }, this), _.bind(function(error, exception) { - this._pdfLoadError(source, error, exception); - }, this)); - }; - PDFCanvas.prototype._openFile = function(source) { - if (pdfjs === null) { - // load pdf.js lazily - require(['pdf'], _.bind(function(pdf) { - pdf.workerSrc = require.toUrl('pdf.worker') + ".js"; - - console.log("Using pdf.js " + pdf.version + " (build " + pdf.build + ")"); - - pdfjs = pdf; - - this._doOpenFile(source); + if (typeof(source) === "string") { + // we can't load urls from inside the sandbox, do so here and transmit the contents + $http.get(source, { + responseType: "arraybuffer" + }).then(_.bind(function(response) { + this._openFile(response.data); + }, this), _.bind(function(error) { + this._pdfLoadError(source, error); }, this)); - } else { - this._doOpenFile(source); + return; } + + console.log("Opening file", source); + sandboxApi.postMessage("openFile", {"source": source}); }; - PDFCanvas.prototype._pageLoaded = function(page, pageObject) { + PDFCanvas.prototype._pageLoaded = function(page) { this.scope.$apply(_.bind(function(scope) { - console.log("Got page", pageObject); - scope.$emit("presentationPageLoaded", page, pageObject); - this.currentPage = pageObject; - this.drawPage(pageObject); + scope.$emit("presentationPageLoaded", page); }, this)); }; - PDFCanvas.prototype._pageLoadError = function(page, error, exception) { - console.error("Could not load page", page, error, exception); + PDFCanvas.prototype._pageLoadError = function(page, error) { var loadErrorMessage; if (error) { loadErrorMessage = translation._("An error occurred while loading the PDF page (%s).", error); @@ -181,36 +201,19 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { } console.log("Showing page", page, "/", this.maxPageNumber); - if (this.currentPage) { - this.currentPage.destroy(); - this.currentPage = null; - } this.currentPageNumber = page; this.scope.$emit("presentationPageLoading", page); - this.doc.getPage(page).then(_.bind(function(pageObject) { - this._pageLoaded(page, pageObject); - }, this), _.bind(function(error, exception) { - this._pageLoadError(page, error, exception); - }, this)); + sandboxApi.postMessage("loadPage", {"page": page}); }; - PDFCanvas.prototype._pageRendered = function(pageObject) { - this.renderTask = null; + PDFCanvas.prototype._pageRendered = function(page) { this.scope.$apply(_.bind(function(scope) { - console.log("Rendered page", pageObject.pageNumber); - this.scope.$emit("presentationPageRendered", pageObject.pageNumber, this.maxPageNumber); - // ...and flip the buffers... - scope.canvasIndex = 1 - scope.canvasIndex; + this.scope.$emit("presentationPageRendered", page, this.maxPageNumber); this.showQueuedPage(); }, this)); }; - PDFCanvas.prototype._pageRenderError = function(pageObject, error, exception) { - if (error === "cancelled") { - return; - } - console.error("Could not render page", pageObject, error, exception); - this.renderTask = null; + PDFCanvas.prototype._pageRenderError = function(page, error) { var loadErrorMessage; if (error) { loadErrorMessage = translation._("An error occurred while rendering the PDF page (%s).", error); @@ -218,59 +221,12 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { loadErrorMessage = translation._("An unknown error occurred while rendering the PDF page."); } this.scope.$apply(_.bind(function(scope) { - scope.$emit("presentationPageRenderError", pageObject.pageNumber, this.maxPageNumber, loadErrorMessage); - }, this)); - }; - - PDFCanvas.prototype._stopRendering = function() { - if (this.renderTask) { - if (this.renderTask.internalRenderTask && this.renderTask.internalRenderTask.cancel) { - this.renderTask.internalRenderTask.cancel(); - } - this.renderTask = null; - } - } - - PDFCanvas.prototype.drawPage = function(pageObject) { - var pdfView = pageObject.view; - var pdfWidth = pdfView[2] - pdfView[0]; - var pdfHeight = pdfView[3] - pdfView[1]; - var w = container.width(); - var h = container.height(); - var scale = w / pdfWidth; - if (pdfHeight * scale > h) { - scale = container.height() / pdfHeight; - } - - // use double-buffering to avoid flickering while - // the new page is rendered... - var canvas = this.canvases[1 - this.scope.canvasIndex]; - var viewport = pageObject.getViewport(scale); - canvas.width = Math.round(viewport.width); - canvas.height = Math.round(viewport.height); - var renderContext = { - canvasContext: canvas.getContext("2d"), - viewport: viewport - }; - - console.log("Rendering page", pageObject); - this.scope.$emit("presentationPageRendering", pageObject.pageNumber); - - // TODO(fancycode): also render images in different resolutions for subscribed peers and send to them when ready - this._stopRendering(); - var renderTask = pageObject.render(renderContext); - this.renderTask = renderTask; - renderTask.promise.then(_.bind(function() { - this._pageRendered(pageObject); - }, this), _.bind(function(error, exception) { - this._pageRenderError(pageObject, error, exception); + scope.$emit("presentationPageRenderError", page, this.maxPageNumber, loadErrorMessage); }, this)); }; PDFCanvas.prototype.redrawPage = function() { - if (this.currentPage !== null) { - this.drawPage(this.currentPage); - } + sandboxApi.postMessage("redrawPage", {"redraw": true}); }; PDFCanvas.prototype.showPage = function(page) { @@ -290,10 +246,7 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { } }; - $scope.canvasIndex = 0; - - var canvases = container.find("canvas"); - var pdfCanvas = new PDFCanvas($scope, canvases); + pdfCanvas = new PDFCanvas($scope); $scope.$watch("currentPresentation", function(presentation, previousPresentation) { if (presentation) { @@ -333,7 +286,7 @@ define(['require', 'underscore', 'jquery'], function(require, _, $) { return { restrict: 'E', replace: true, - template: '
', + template: '
', controller: controller }; diff --git a/static/js/directives/presentation.js b/static/js/directives/presentation.js index 82ef8709..bc01604d 100644 --- a/static/js/directives/presentation.js +++ b/static/js/directives/presentation.js @@ -715,6 +715,21 @@ define(['jquery', 'underscore', 'text!partials/presentation.html', 'bigscreen'], }); }); + $scope.$on("keyUp", function(event, keyCode) { + switch (keyCode) { + case 37: + // left arrow + $scope.prevPage(); + break; + case 39: + // right arrow + case 32: + // space + $scope.nextPage(); + break; + } + }) + $(document).on("keyup", function(event) { if (!$scope.layout.presentation) { return; @@ -722,22 +737,10 @@ define(['jquery', 'underscore', 'text!partials/presentation.html', 'bigscreen'], if ($(event.target).is("input,textarea,select")) { return; } - $scope.$apply(function() { - switch (event.keyCode) { - case 37: - // left arrow - $scope.prevPage(); - event.preventDefault(); - break; - case 39: - // right arrow - case 32: - // space - $scope.nextPage(); - event.preventDefault(); - break; - } + $scope.$apply(function(scope) { + scope.$emit("keyUp", event.keyCode); }); + event.preventDefault(); }); $scope.$watch("layout.presentation", function(newval, oldval) { diff --git a/static/js/sandboxes/pdf.js b/static/js/sandboxes/pdf.js new file mode 100644 index 00000000..d38f45cd --- /dev/null +++ b/static/js/sandboxes/pdf.js @@ -0,0 +1,281 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2015 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +"use strict"; +(function () { + + var script = document.getElementsByTagName("script")[0]; + var PARENT_ORIGIN = script.getAttribute("data-parent-origin"); + var PDFJS_URL = script.getAttribute("data-pdfjs-url"); + var PDFJS_WORKER_URL = script.getAttribute("data-pdfjs-worker-url"); + var PDFJS_COMPATIBILITY_URL = script.getAttribute("data-pdfjs-compatibility-url"); + var container = document.getElementById("container"); + + var pdfScript = null; + var pdfjs = null; + + var PdfJsSandbox = function(window) { + this.head = document.getElementsByTagName('head')[0]; + this.canvases = document.getElementsByTagName('canvas'); + this.window = window; + this.doc = null; + this.currentPage = null; + this.canvasIndex = 0; + this.renderTask = null; + }; + + PdfJsSandbox.prototype.postMessage = function(type, message) { + var msg = {"type": type}; + msg[type] = message; + this.window.parent.postMessage(msg, PARENT_ORIGIN); + }; + + PdfJsSandbox.prototype.openFile = function(source) { + if (!pdfScript) { + var that = this; + var compat = document.createElement('script'); + compat.type = "text/javascript"; + compat.src = PDFJS_COMPATIBILITY_URL; + this.head.appendChild(compat); + + pdfScript = document.createElement('script'); + pdfScript.type = "text/javascript"; + pdfScript.src = PDFJS_URL; + pdfScript.onerror = function(evt) { + that.postMessage("pdfjs.error", {"msgid": "loadScriptFailed"}); + that.head.removeChild(pdfScript); + pdfScript = null; + }; + pdfScript.onload = function(evt) { + pdfjs = that.window.PDFJS; + if (PDFJS_WORKER_URL) { + // NOTE: the worker script won't actually be run inside a + // real Worker object as it can't be loaded cross-domain + // from the sandboxed iframe ("data:" vs. "https"). + pdfjs.workerSrc = PDFJS_WORKER_URL; + } + console.log("Using pdf.js " + pdfjs.version + " (build " + pdfjs.build + ")"); + that._doOpenFile(source); + }; + this.head.appendChild(pdfScript); + } else { + this._doOpenFile(source); + } + }; + + PdfJsSandbox.prototype.closeFile = function() { + this._stopRendering(); + if (this.currentPage) { + this.currentPage.destroy(); + this.currentPage = null; + } + if (this.doc) { + this.doc.cleanup(); + this.doc.destroy(); + this.doc = null; + } + // clear visible canvas so it's empty when we show the next document + var canvas = this.canvases[this.canvasIndex]; + canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); + }; + + PdfJsSandbox.prototype._doOpenFile = function(source) { + var that = this; + this.postMessage("pdfjs.loading", {"source": source}); + pdfjs.getDocument(source).then(function(doc) { + that._pdfLoaded(source, doc); + }, function(error, exception) { + that._pdfLoadError(source, error, exception); + }); + }; + + PdfJsSandbox.prototype._pdfLoaded = function(source, doc) { + console.log("PDF loaded", doc); + this.doc = doc; + this.postMessage("pdfjs.loaded", {"source": source, "doc": {"numPages": doc.numPages}}); + }; + + PdfJsSandbox.prototype._pdfLoadError = function(source, error, exception) { + this.postMessage("pdfjs.loadError", {"source": source, "error": error}); + }; + + PdfJsSandbox.prototype.loadPage = function(page) { + if (this.currentPage) { + this.currentPage.destroy(); + this.currentPage = null; + } + var that = this; + this.doc.getPage(page).then(function(pageObject) { + that._pageLoaded(page, pageObject); + }, function(error, exception) { + that._pageLoadError(page, error, exception); + }); + }; + + PdfJsSandbox.prototype._pageLoaded = function(page, pageObject) { + console.log("Got page", pageObject); + this.currentPage = pageObject; + this.postMessage("pdfjs.pageLoaded", {"page": page}); + this.drawPage(pageObject); + }; + + PdfJsSandbox.prototype._pageLoadError = function(page, error, exception) { + console.error("Could not load page", page, error, exception); + this.postMessage("pdfjs.pageLoadError", {"page": page, "error": error}); + }; + + PdfJsSandbox.prototype._stopRendering = function() { + if (this.renderTask) { + if (this.renderTask.internalRenderTask && this.renderTask.internalRenderTask.cancel) { + this.renderTask.internalRenderTask.cancel(); + } + this.renderTask = null; + } + } + + PdfJsSandbox.prototype.drawPage = function(pageObject) { + var pdfView = pageObject.view; + var pdfWidth = pdfView[2] - pdfView[0]; + var pdfHeight = pdfView[3] - pdfView[1]; + var w = container.offsetWidth; + var h = container.offsetHeight; + var scale = w / pdfWidth; + if (pdfHeight * scale > h) { + scale = container.offsetHeight / pdfHeight; + } + + // use double-buffering to avoid flickering while + // the new page is rendered... + var canvas = this.canvases[1 - this.canvasIndex]; + var viewport = pageObject.getViewport(scale); + canvas.width = Math.round(viewport.width); + canvas.height = Math.round(viewport.height); + var renderContext = { + canvasContext: canvas.getContext("2d"), + viewport: viewport + }; + + console.log("Rendering page", pageObject); + this.postMessage("pdfjs.renderingPage", {"page": pageObject.pageNumber}); + + // TODO(fancycode): also render images in different resolutions for subscribed peers and send to them when ready + this._stopRendering(); + var renderTask = pageObject.render(renderContext); + this.renderTask = renderTask; + var that = this; + renderTask.promise.then(function() { + that._pageRendered(pageObject); + }, function(error, exception) { + that._pageRenderError(pageObject, error, exception); + }); + }; + + PdfJsSandbox.prototype._pageRendered = function(pageObject) { + this.renderTask = null; + console.log("Rendered page", pageObject.pageNumber); + this.postMessage("pdfjs.pageRendered", {"page": pageObject.pageNumber}); + // ...and flip the buffers... + this.canvases[this.canvasIndex].style.display = "none"; + this.canvasIndex = 1 - this.canvasIndex; + this.canvases[this.canvasIndex].style.display = "block"; + }; + + PdfJsSandbox.prototype._pageRenderError = function(pageObject, error, exception) { + if (error === "cancelled") { + return; + } + console.error("Could not render page", pageObject, error, exception); + this.renderTask = null; + this.postMessage("pdfjs.pageRenderError", {"page": pageObject.pageNumber, "error": error}); + }; + + PdfJsSandbox.prototype.redrawPage = function() { + if (this.currentPage !== null) { + this.drawPage(this.currentPage); + } + }; + + var sandbox = new PdfJsSandbox(window); + + window.addEventListener("message", function(event) { + if (event.origin !== PARENT_ORIGIN) { + // only accept messages from spreed-webrtc + return; + } + var msg = event.data; + var data = msg[msg.type] || {}; + switch (msg.type) { + case "openFile": + sandbox.openFile(data.source); + break; + case "closeFile": + sandbox.closeFile(); + break; + case "loadPage": + sandbox.loadPage(data.page); + break; + case "redrawPage": + sandbox.redrawPage(); + break; + default: + console.log("Unknown message received", event); + break; + } + }, false); + + document.addEventListener("keyup", function(event) { + sandbox.postMessage("pdfjs.keyUp", {"key": event.keyCode}); + event.preventDefault(); + }); + + var toggleFullscreen = function(elem) { + var fullScreenElement = document.fullscreenElement || document.msFullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.webkitCurrentFullScreenElement; + if (fullScreenElement) { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } + } else { + if (elem.requestFullscreen) { + elem.requestFullscreen(); + } else if (elem.webkitRequestFullscreen) { + elem.webkitRequestFullscreen(); + } else if (elem.mozRequestFullScreen) { + elem.mozRequestFullScreen(); + } else if (elem.msRequestFullscreen) { + elem.msRequestFullscreen(); + } + } + }; + + container.addEventListener("dblclick", function(event) { + toggleFullscreen(container); + }); + + console.log("pdf.js sandbox ready."); + sandbox.postMessage("ready", {"ready": true}); + +})(); diff --git a/static/js/sandboxes/youtube.js b/static/js/sandboxes/youtube.js index b09e7cbf..4a182730 100644 --- a/static/js/sandboxes/youtube.js +++ b/static/js/sandboxes/youtube.js @@ -244,5 +244,6 @@ }, false); console.log("YouTube sandbox ready."); + sandbox.postMessage("ready", {"ready": true}); })(); diff --git a/static/js/services/sandbox.js b/static/js/services/sandbox.js index d3f65a4a..c9a17e01 100644 --- a/static/js/services/sandbox.js +++ b/static/js/services/sandbox.js @@ -30,6 +30,8 @@ define(["jquery", "underscore"], function($, _) { this.target = this.iframe.contentWindow; this.e = $({}); this.handler = _.bind(this.onPostMessageReceived, this); + this.ready = false; + this.pending_messages = []; $window.addEventListener("message", this.handler, false); }; @@ -46,10 +48,28 @@ define(["jquery", "underscore"], function($, _) { return; } + if (event.data.type === "ready") { + this.ready = true; + this._sendPendingMessages(); + } + this.e.triggerHandler("message", [event]); }; + Sandbox.prototype._sendPendingMessages = function() { + var i; + for (i=0; i + + + pdf.js Sandbox + + + +
+ +
+ + + From 8dfd371c6f4378530c89a66e623f1429b3ed04c3 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 10:50:16 +0200 Subject: [PATCH 065/121] Build pdf sandbox. --- build/build.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build.js b/build/build.js index 69ce4508..bee846a5 100644 --- a/build/build.js +++ b/build/build.js @@ -83,6 +83,13 @@ override: { skipModuleInsertion: true } + }, + { + name: 'sandboxes/pdf', + dir: './out/sandboxes', + override: { + skipModuleInsertion: true + } } ] }) From f91084ed96961760f2da97922536aae4b91530ac Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 10:57:23 +0200 Subject: [PATCH 066/121] Changed ordering (found by Hound). --- src/styles/components/_presentation.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/components/_presentation.scss b/src/styles/components/_presentation.scss index b5f9a583..70bd697f 100644 --- a/src/styles/components/_presentation.scss +++ b/src/styles/components/_presentation.scss @@ -201,8 +201,8 @@ iframe { border: 0; - width: 100%; height: 100%; + width: 100%; } } From a1288820bdc933c1e3af33a3c706909c6c2c7b93 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 11:51:57 +0200 Subject: [PATCH 067/121] Ignore "ready" message here. --- static/js/directives/pdfcanvas.js | 2 ++ static/js/directives/youtubevideo.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/static/js/directives/pdfcanvas.js b/static/js/directives/pdfcanvas.js index 8c51ab15..e4a11bfc 100644 --- a/static/js/directives/pdfcanvas.js +++ b/static/js/directives/pdfcanvas.js @@ -44,6 +44,8 @@ define(['require', 'underscore', 'jquery', 'text!partials/pdfcanvas_sandbox.html var msg = message.data; var data = msg[msg.type] || {}; switch (msg.type) { + case "ready": + break; case "pdfjs.loading": $scope.$apply(function(scope) { scope.$emit("presentationLoading", data.source); diff --git a/static/js/directives/youtubevideo.js b/static/js/directives/youtubevideo.js index 9b8b8b6d..3ab4b928 100644 --- a/static/js/directives/youtubevideo.js +++ b/static/js/directives/youtubevideo.js @@ -115,6 +115,8 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo var msg = message.data; var data = msg[msg.type] || {}; switch (msg.type) { + case "ready": + break; case "youtube.apiReady": $scope.$apply(function() { console.log("YouTube IFrame ready"); From f59eb17cf33c4414bfd261bf04873ee6184ecad3 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 13:52:53 +0200 Subject: [PATCH 068/121] Destroy sandbox API when scope is destroyed. --- static/js/directives/pdfcanvas.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/js/directives/pdfcanvas.js b/static/js/directives/pdfcanvas.js index e4a11bfc..b425b2a7 100644 --- a/static/js/directives/pdfcanvas.js +++ b/static/js/directives/pdfcanvas.js @@ -266,6 +266,7 @@ define(['require', 'underscore', 'jquery', 'text!partials/pdfcanvas_sandbox.html $scope.$on("$destroy", function() { pdfCanvas.close(); pdfCanvas = null; + sandboxApi.destroy(); }); $scope.$watch("currentPageNumber", function(page, oldValue) { From 33f0ae2071703e958b4c4ffe487c7385911e3088 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 15:15:37 +0200 Subject: [PATCH 069/121] Setup CSP for pdf.js sandbox. --- static/partials/pdfcanvas_sandbox.html | 1 + 1 file changed, 1 insertion(+) diff --git a/static/partials/pdfcanvas_sandbox.html b/static/partials/pdfcanvas_sandbox.html index dc20166e..3750d8e3 100644 --- a/static/partials/pdfcanvas_sandbox.html +++ b/static/partials/pdfcanvas_sandbox.html @@ -2,6 +2,7 @@ pdf.js Sandbox + + + +
+
+
+ + + From caa8e6c4a418c069c7fcbaa129d231831d44d7dc Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 14:36:33 +0200 Subject: [PATCH 072/121] Removed debug output. --- static/js/sandboxes/webodf.js | 1 - 1 file changed, 1 deletion(-) diff --git a/static/js/sandboxes/webodf.js b/static/js/sandboxes/webodf.js index 0dd7af7a..ba5f7257 100644 --- a/static/js/sandboxes/webodf.js +++ b/static/js/sandboxes/webodf.js @@ -63,7 +63,6 @@ } // we're loading typed arrays in the sandbox - console.log("LoadXML", path); var bb = new Blob([new Uint8Array(path)]); var f = new FileReader(); f.onload = function(e) { From 5ae175cc88384170e96c0a43e5c8e5d9958d6832 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 24 Apr 2015 14:51:28 +0200 Subject: [PATCH 073/121] Setup CSP for WebODF sandbox. --- static/partials/odfcanvas_sandbox.html | 1 + 1 file changed, 1 insertion(+) diff --git a/static/partials/odfcanvas_sandbox.html b/static/partials/odfcanvas_sandbox.html index 6421930b..abe06482 100644 --- a/static/partials/odfcanvas_sandbox.html +++ b/static/partials/odfcanvas_sandbox.html @@ -2,6 +2,7 @@ WebODF Sandbox +