diff --git a/akka-bbb-apps/.dockerignore b/akka-bbb-apps/.dockerignore deleted file mode 100644 index c9c5676735..0000000000 --- a/akka-bbb-apps/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -Dockerfile - diff --git a/akka-bbb-apps/.gitignore b/akka-bbb-apps/.gitignore index 28cb15fcec..81dcd42538 100644 --- a/akka-bbb-apps/.gitignore +++ b/akka-bbb-apps/.gitignore @@ -48,4 +48,5 @@ lib_managed/ .cache bin/ src/main/resources/ +.bsp/ diff --git a/akka-bbb-apps/Dockerfile b/akka-bbb-apps/Dockerfile deleted file mode 100644 index e8adc296c1..0000000000 --- a/akka-bbb-apps/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM bbb-common-message AS builder - -ARG COMMON_VERSION=0.0.1-SNAPSHOT - -COPY . /source - -RUN cd /source \ - && find -name build.sbt -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-message[^\"]*\"[ ]*%[ ]*\)\"[^\"]*\"\(.*\)|\1\"$COMMON_VERSION\"\2|g" {} \; \ - && sbt compile - -RUN apt-get update \ - && apt-get -y install fakeroot - -RUN cd /source \ - && sbt debian:packageBin - -# FROM ubuntu:16.04 -FROM openjdk:8-jre-slim-stretch - -COPY --from=builder /source/target/*.deb /root/ - -RUN dpkg -i /root/*.deb - -CMD ["/usr/share/bbb-apps-akka/bin/bbb-apps-akka"] diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala index b39ba0d5a2..61725cd6aa 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationConversionCompletedSysPubMsgHdlr.scala @@ -15,12 +15,13 @@ trait PresentationConversionCompletedSysPubMsgHdlr { ): MeetingState2x = { val meetingId = liveMeeting.props.meetingProp.intId + val temporaryPresentationId = msg.body.presentation.temporaryPresentationId val newState = for { pod <- PresentationPodsApp.getPresentationPod(state, msg.body.podId) pres <- pod.getPresentation(msg.body.presentation.id) } yield { - val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres) + val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres, temporaryPresentationId) PresentationSender.broadcastPresentationConversionCompletedEvtMsg( bus, diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala index 9a46379fbd..6279530256 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationPodsApp.scala @@ -58,7 +58,7 @@ object PresentationPodsApp { ) } - PresentationVO(p.id, p.name, p.current, + PresentationVO(p.id, "", p.name, p.current, pages.toVector, p.downloadable, p.removable) } @@ -74,7 +74,7 @@ object PresentationPodsApp { state.update(podManager) } - def translatePresentationToPresentationVO(pres: PresentationInPod): PresentationVO = { + def translatePresentationToPresentationVO(pres: PresentationInPod, temporaryPresentationId: String): PresentationVO = { val pages = pres.pages.values.map { page => PageVO( id = page.id, @@ -90,7 +90,7 @@ object PresentationPodsApp { heightRatio = page.heightRatio ) } - PresentationVO(pres.id, pres.name, pres.current, pages.toVector, pres.downloadable, pres.removable) + PresentationVO(pres.id, temporaryPresentationId, pres.name, pres.current, pages.toVector, pres.downloadable, pres.removable) } def setCurrentPresentationInPod(state: MeetingState2x, podId: String, nextCurrentPresId: String): Option[PresentationPod] = { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationUploadTokenReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationUploadTokenReqMsgHdlr.scala index 9ced41b323..003fb310bd 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationUploadTokenReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/presentationpod/PresentationUploadTokenReqMsgHdlr.scala @@ -19,7 +19,7 @@ trait PresentationUploadTokenReqMsgHdlr extends RightsManagementTrait { val envelope = BbbCoreEnvelope(PresentationUploadTokenPassRespMsg.NAME, routing) val header = BbbClientMsgHeader(PresentationUploadTokenPassRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId) - val body = PresentationUploadTokenPassRespMsgBody(msg.body.podId, token, msg.body.filename) + val body = PresentationUploadTokenPassRespMsgBody(msg.body.podId, token, msg.body.filename, msg.body.tmpPresId) val event = PresentationUploadTokenPassRespMsg(header, body) val msgEvent = BbbCommonEnvCoreMsg(envelope, event) bus.outGW.send(msgEvent) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SelectRandomViewerReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SelectRandomViewerReqMsgHdlr.scala index 762012dc4c..85858f2dfd 100644 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SelectRandomViewerReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SelectRandomViewerReqMsgHdlr.scala @@ -50,7 +50,6 @@ trait SelectRandomViewerReqMsgHdlr extends RightsManagementTrait { Users2x.setUserExempted(liveMeeting.users2x, pickedUser, true) } } - val userIds = users.map { case (v) => v.intId } broadcastEvent(msg, userIds, pickedUser) } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala index 88a06ea09e..7024da02cf 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingAfterReconnectReqMsgHdlr.scala @@ -15,12 +15,12 @@ trait UserJoinMeetingAfterReconnectReqMsgHdlr extends HandlerHelpers with UserJo def handleUserJoinMeetingAfterReconnectReqMsg(msg: UserJoinMeetingAfterReconnectReqMsg, state: MeetingState2x): MeetingState2x = { log.info("Received user joined after reconnecting. user {} meetingId={}", msg.body.userId, msg.header.meetingId) - Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId) match { case Some(reconnectingUser) => if (reconnectingUser.userLeftFlag.left) { log.info("Resetting flag that user left meeting. user {}", msg.body.userId) // User has reconnected. Just reset it's flag. ralam Oct 23, 2018 + sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false) Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId) } state diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala index cd8011ff15..ad4d5fbe88 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserJoinMeetingReqMsgHdlr.scala @@ -2,9 +2,9 @@ package org.bigbluebutton.core.apps.users import org.bigbluebutton.common2.msgs.UserJoinMeetingReqMsg import org.bigbluebutton.core.apps.breakout.BreakoutHdlrHelpers -import org.bigbluebutton.core.models.{ Users2x, VoiceUsers } import org.bigbluebutton.core.domain.MeetingState2x -import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting, MeetingActor, OutMsgRouter } +import org.bigbluebutton.core.models.{Users2x, VoiceUsers} +import org.bigbluebutton.core.running.{HandlerHelpers, LiveMeeting, MeetingActor, OutMsgRouter} trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers { this: MeetingActor => @@ -20,8 +20,10 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers { if (reconnectingUser.userLeftFlag.left) { log.info("Resetting flag that user left meeting. user {}", msg.body.userId) // User has reconnected. Just reset it's flag. ralam Oct 23, 2018 + sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false) Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId) } + state case None => val newState = userJoinMeeting(outGW, msg.body.authToken, msg.body.clientType, liveMeeting, state) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala index 6be39e1d9d..6f3b721ca8 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/UserLeaveReqMsgHdlr.scala @@ -3,9 +3,9 @@ package org.bigbluebutton.core.apps.users import org.bigbluebutton.common2.msgs.UserLeaveReqMsg import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x } -import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } +import org.bigbluebutton.core.running.{ HandlerHelpers, MeetingActor, OutMsgRouter } -trait UserLeaveReqMsgHdlr { +trait UserLeaveReqMsgHdlr extends HandlerHelpers { this: MeetingActor => val outGW: OutMsgRouter @@ -19,6 +19,8 @@ trait UserLeaveReqMsgHdlr { // Just flag that user has left as the user might be reconnecting. // An audit will remove this user if it hasn't rejoined after a certain period of time. // ralam oct 23, 2018 + sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, true) + Users2x.setUserLeftFlag(liveMeeting.users2x, msg.body.userId) } if (msg.body.loggedOut) { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala index 1ca5247838..4a370da359 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala @@ -2,6 +2,7 @@ package org.bigbluebutton.core.models import com.softwaremill.quicklens._ import org.bigbluebutton.core.util.TimeUtil +import org.bigbluebutton.core2.message.senders.MsgBuilder object Users2x { def findWithIntId(users: Users2x, intId: String): Option[UserState] = { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/MeetingConfigurationEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/MeetingConfigurationEvent.scala new file mode 100755 index 0000000000..917a32a632 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/MeetingConfigurationEvent.scala @@ -0,0 +1,34 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see . + * + */ + +package org.bigbluebutton.core.record.events + +class MeetingConfigurationEvent extends StarterConfigurationEvent { + import MeetingConfigurationEvent._ + + setEvent("MeetingConfigurationEvent") + + def setWebcamsOnlyForModerator(webcamsOnlyForModerator: Boolean) { + eventMap.put(WEBCAMS_ONLY_FOR_MODERATOR, webcamsOnlyForModerator.toString) + } +} + +object MeetingConfigurationEvent { + val WEBCAMS_ONLY_FOR_MODERATOR = "webcamsOnlyForModerator" +} \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/StarterConfigurationEvent.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/StarterConfigurationEvent.scala new file mode 100755 index 0000000000..b452bb8163 --- /dev/null +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/record/events/StarterConfigurationEvent.scala @@ -0,0 +1,24 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2017 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see . + * + */ + +package org.bigbluebutton.core.record.events + +trait StarterConfigurationEvent extends RecordEvent { + setModule("CONFIG") +} \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala index a0bdcafb45..052e78035f 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala @@ -25,6 +25,20 @@ trait HandlerHelpers extends SystemConfiguration { } } + def sendUserLeftFlagUpdatedEvtMsg( + outGW: OutMsgRouter, + liveMeeting: LiveMeeting, + intId: String, + leftFlag: Boolean + ): Unit = { + for { + u <- Users2x.findWithIntId(liveMeeting.users2x, intId) + } yield { + val userLeftFlagMeetingEvent = MsgBuilder.buildUserLeftFlagUpdatedEvtMsg(liveMeeting.props.meetingProp.intId, u.intId, leftFlag) + outGW.send(userLeftFlagMeetingEvent) + } + } + def userJoinMeeting(outGW: OutMsgRouter, authToken: String, clientType: String, liveMeeting: LiveMeeting, state: MeetingState2x): MeetingState2x = { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala index baedf130c4..a68c8bd6ad 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala @@ -286,6 +286,16 @@ object MsgBuilder { BbbCommonEnvCoreMsg(envelope, event) } + def buildUserLeftFlagUpdatedEvtMsg(meetingId: String, userId: String, userLeftFlag: Boolean): BbbCommonEnvCoreMsg = { + val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId) + val envelope = BbbCoreEnvelope(UserLeftFlagUpdatedEvtMsg.NAME, routing) + val header = BbbClientMsgHeader(UserLeftFlagUpdatedEvtMsg.NAME, meetingId, userId) + val body = UserLeftFlagUpdatedEvtMsgBody(userId, userLeftFlag) + val event = UserLeftFlagUpdatedEvtMsg(header, body) + + BbbCommonEnvCoreMsg(envelope, event) + } + def buildUserInactivityInspectMsg(meetingId: String, userId: String, responseDelay: Long): BbbCommonEnvCoreMsg = { val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId) val envelope = BbbCoreEnvelope(UserInactivityInspectMsg.NAME, routing) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala index a106261155..d0bbd0a395 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/RedisRecorderActor.scala @@ -116,6 +116,7 @@ class RedisRecorderActor( case m: RecordStatusResetSysMsg => handleRecordStatusResetSysMsg(m) case m: WebcamsOnlyForModeratorChangedEvtMsg => handleWebcamsOnlyForModeratorChangedEvtMsg(m) case m: MeetingEndingEvtMsg => handleEndAndKickAllSysMsg(m) + case m: MeetingCreatedEvtMsg => handleStarterConfigurations(m) // Recording case m: RecordingChapterBreakSysMsg => handleRecordingChapterBreakSysMsg(m) @@ -622,4 +623,10 @@ class RedisRecorderActor( log.error("recording database is not available.") } + private def handleStarterConfigurations(msg: MeetingCreatedEvtMsg): Unit = { + val ev = new MeetingConfigurationEvent() + ev.setWebcamsOnlyForModerator(msg.body.props.usersProp.webcamsOnlyForModerator) + record(msg.body.props.meetingProp.intId, ev.toMap().asJava) + } + } diff --git a/akka-bbb-fsesl/Dockerfile b/akka-bbb-fsesl/Dockerfile deleted file mode 100644 index ff06041d93..0000000000 --- a/akka-bbb-fsesl/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM bbb-fsesl-client AS builder - -ARG COMMON_VERSION=0.0.1-SNAPSHOT - -COPY . /source - -RUN cd /source \ - && find -name build.sbt -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-message[^\"]*\"[ ]*%[ ]*\)\"[^\"]*\"\(.*\)|\1\"$COMMON_VERSION\"\2|g" {} \; \ - && find -name build.sbt -exec sed -i "s|\(.*org.bigbluebutton.*bbb-fsesl-client[^\"]*\"[ ]*%[ ]*\)\"[^\"]*\"\(.*\)|\1\"$COMMON_VERSION\"\2|g" {} \; \ - && sbt compile - -RUN apt-get update \ - && apt-get -y install fakeroot - -RUN cd /source \ - && sbt debian:packageBin - -FROM openjdk:8-jre-slim-stretch - -COPY --from=builder /source/target/*.deb /root/ - -RUN dpkg -i /root/*.deb - -COPY wait-for-it.sh /usr/local/bin/ - -CMD ["/usr/share/bbb-fsesl-akka/bin/bbb-fsesl-akka"] diff --git a/bbb-common-message/.gitignore b/bbb-common-message/.gitignore index 82f02806ec..732576600c 100644 --- a/bbb-common-message/.gitignore +++ b/bbb-common-message/.gitignore @@ -53,4 +53,5 @@ akka-patterns-store/ lib_managed/ .cache bin/ +.bsp/ diff --git a/bbb-common-message/Dockerfile b/bbb-common-message/Dockerfile deleted file mode 100644 index 2231599153..0000000000 --- a/bbb-common-message/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM sbt:0.13.8 - -ARG COMMON_VERSION - -COPY . /bbb-common-message - -RUN cd /bbb-common-message \ - && sed -i "s|\(version := \)\".*|\1\"$COMMON_VERSION\"|g" build.sbt \ - && echo 'publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository")))' | tee -a build.sbt \ - && sbt compile \ - && sbt publish \ - && sbt publishLocal - diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Presentation.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Presentation.scala index 30c0afc33f..e2e8c4ce10 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Presentation.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/domain/Presentation.scala @@ -1,6 +1,6 @@ package org.bigbluebutton.common2.domain -case class PresentationVO(id: String, name: String, current: Boolean = false, +case class PresentationVO(id: String, temporaryPresentationId: String, name: String, current: Boolean = false, pages: Vector[PageVO], downloadable: Boolean, removable: Boolean) case class PageVO(id: String, num: Int, thumbUri: String = "", swfUri: String, diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PresentationPodsMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PresentationPodsMsgs.scala index 899849ba36..2f8474fa07 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PresentationPodsMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PresentationPodsMsgs.scala @@ -13,7 +13,7 @@ case class RemovePresentationPodPubMsgBody(podId: String) object PresentationUploadTokenReqMsg { val NAME = "PresentationUploadTokenReqMsg" } case class PresentationUploadTokenReqMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenReqMsgBody) extends StandardMsg -case class PresentationUploadTokenReqMsgBody(podId: String, filename: String) +case class PresentationUploadTokenReqMsgBody(podId: String, filename: String, tmpPresId: String) object GetAllPresentationPodsReqMsg { val NAME = "GetAllPresentationPodsReqMsg" } case class GetAllPresentationPodsReqMsg(header: BbbClientMsgHeader, body: GetAllPresentationPodsReqMsgBody) extends StandardMsg @@ -113,13 +113,14 @@ case class PresentationConversionRequestReceivedSysMsg( body: PresentationConversionRequestReceivedSysMsgBody ) extends StandardMsg case class PresentationConversionRequestReceivedSysMsgBody( - podId: String, - presentationId: String, - current: Boolean, - presName: String, - downloadable: Boolean, - removable: Boolean, - authzToken: String + podId: String, + presentationId: String, + temporaryPresentationId: String, + current: Boolean, + presName: String, + downloadable: Boolean, + removable: Boolean, + authzToken: String ) object PresentationPageConversionStartedSysMsg { val NAME = "PresentationPageConversionStartedSysMsg" } @@ -181,7 +182,7 @@ case class PdfConversionInvalidErrorEvtMsgBody(podId: String, messageKey: String object PresentationUploadTokenPassRespMsg { val NAME = "PresentationUploadTokenPassRespMsg" } case class PresentationUploadTokenPassRespMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenPassRespMsgBody) extends StandardMsg -case class PresentationUploadTokenPassRespMsgBody(podId: String, authzToken: String, filename: String) +case class PresentationUploadTokenPassRespMsgBody(podId: String, authzToken: String, filename: String, tmpPresId: String) object PresentationUploadTokenFailRespMsg { val NAME = "PresentationUploadTokenFailRespMsg" } case class PresentationUploadTokenFailRespMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenFailRespMsgBody) extends StandardMsg diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala index 2eb81daff0..85143ca27b 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/UsersMsgs.scala @@ -70,6 +70,20 @@ case class UserLeftMeetingEvtMsg( ) extends BbbCoreMsg case class UserLeftMeetingEvtMsgBody(intId: String, eject: Boolean, ejectedBy: String, reason: String, reasonCode: String) +object UserLeftFlagUpdatedEvtMsg { + val NAME = "UserLeftFlagUpdatedEvtMsg" + def apply(meetingId: String, userId: String, body: UserLeftFlagUpdatedEvtMsgBody): UserLeftFlagUpdatedEvtMsg = { + val header = BbbClientMsgHeader(UserLeftFlagUpdatedEvtMsg.NAME, meetingId, userId) + UserLeftFlagUpdatedEvtMsg(header, body) + } +} + +case class UserLeftFlagUpdatedEvtMsg( + header: BbbClientMsgHeader, + body: UserLeftFlagUpdatedEvtMsgBody +) extends BbbCoreMsg +case class UserLeftFlagUpdatedEvtMsgBody(intId: String, userLeftFlag: Boolean) + object UserJoinedMeetingEvtMsg { val NAME = "UserJoinedMeetingEvtMsg" def apply(meetingId: String, userId: String, body: UserJoinedMeetingEvtMsgBody): UserJoinedMeetingEvtMsg = { diff --git a/bbb-common-web/.gitignore b/bbb-common-web/.gitignore index 82f02806ec..732576600c 100644 --- a/bbb-common-web/.gitignore +++ b/bbb-common-web/.gitignore @@ -53,4 +53,5 @@ akka-patterns-store/ lib_managed/ .cache bin/ +.bsp/ diff --git a/bbb-common-web/Dockerfile b/bbb-common-web/Dockerfile deleted file mode 100644 index 874219a3ba..0000000000 --- a/bbb-common-web/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM bbb-common-message - -ARG COMMON_VERSION - -COPY . /bbb-common-web - -RUN cd /bbb-common-web \ - && sed -i "s|\(version := \)\".*|\1\"$COMMON_VERSION\"|g" build.sbt \ - && find -name build.sbt -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-message[^\"]*\"[ ]*%[ ]*\)\"[^\"]*\"\(.*\)|\1\"$COMMON_VERSION\"\2|g" {} \; \ - && echo 'publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository")))' | tee -a build.sbt \ - && sbt compile \ - && sbt publish \ - && sbt publishLocal diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java index 9ebf1cd9dc..8aa872c7f8 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/MeetingService.java @@ -60,6 +60,7 @@ import org.bigbluebutton.api.messaging.converters.messages.DeletedRecordingMessa import org.bigbluebutton.api.messaging.messages.*; import org.bigbluebutton.api2.IBbbWebApiGWApp; import org.bigbluebutton.api2.domain.UploadedTrack; +import org.bigbluebutton.common2.msgs.MeetingCreatedEvtMsg; import org.bigbluebutton.common2.redis.RedisStorageService; import org.bigbluebutton.presentation.PresentationUrlDownloadService; import org.bigbluebutton.presentation.imp.SwfSlidesGenerationProgressNotifier; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java index 0db8e24e05..3a7699e185 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java @@ -817,11 +817,11 @@ public class ParamsProcessorUtil { return DigestUtils.sha1Hex(extMeetingId); } - public String processPassword(String pass) { - return StringUtils.isEmpty(pass) ? RandomStringUtils.randomAlphanumeric(8) : pass; - } + public String processPassword(String pass) { + return StringUtils.isEmpty(pass) ? RandomStringUtils.randomAlphanumeric(8) : pass; + } - public boolean hasChecksumAndQueryString(String checksum, String queryString) { + public boolean hasChecksumAndQueryString(String checksum, String queryString) { return (! StringUtils.isEmpty(checksum) && StringUtils.isEmpty(queryString)); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/Util.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/Util.java index c0c272ebad..1c5bff4445 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/Util.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/Util.java @@ -2,6 +2,7 @@ package org.bigbluebutton.api; import java.io.File; import java.io.IOException; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -45,7 +46,8 @@ public final class Util { public static String generatePresentationId(String presFilename) { long timestamp = System.currentTimeMillis(); - return DigestUtils.sha1Hex(presFilename) + "-" + timestamp; + String uuid = UUID.randomUUID().toString(); + return DigestUtils.sha1Hex(presFilename + uuid) + "-" + timestamp; } public static String createNewFilename(String presId, String fileExt) { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java index ab537b39de..587ab0db72 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java @@ -49,8 +49,8 @@ public class Meeting { private boolean forciblyEnded = false; private String telVoice; private String webVoice; - private String moderatorPass; - private String viewerPass; + private String moderatorPass = ""; + private String viewerPass = ""; private int learningDashboardCleanupDelayInMinutes; private String learningDashboardAccessToken; private ArrayList disabledFeatures; @@ -115,9 +115,17 @@ public class Meeting { name = builder.name; extMeetingId = builder.externalId; intMeetingId = builder.internalId; - viewerPass = builder.viewerPass; - moderatorPass = builder.moderatorPass; disabledFeatures = builder.disabledFeatures; + if (builder.viewerPass == null){ + viewerPass = ""; + } else { + viewerPass = builder.viewerPass; + } + if (builder.moderatorPass == null){ + moderatorPass = ""; + } else { + moderatorPass = builder.moderatorPass; + } learningDashboardCleanupDelayInMinutes = builder.learningDashboardCleanupDelayInMinutes; learningDashboardAccessToken = builder.learningDashboardAccessToken; maxUsers = builder.maxUsers; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ModeratorPasswordConstraint.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ModeratorPasswordConstraint.java deleted file mode 100755 index c26f01d758..0000000000 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ModeratorPasswordConstraint.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bigbluebutton.api.model.constraint; - -import org.bigbluebutton.api.model.validator.ModeratorPasswordValidator; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Constraint(validatedBy = ModeratorPasswordValidator.class) -@Target(TYPE) -@Retention(RUNTIME) -public @interface ModeratorPasswordConstraint { - - String key() default "invalidPassword"; - String message() default "The supplied moderator password is incorrect"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java index 49de69718e..55feff00df 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java @@ -29,7 +29,6 @@ public class EndMeeting extends RequestWithChecksum { private String meetingID; @PasswordConstraint - @NotEmpty(message = "You must provide the moderator password") private String password; @Valid diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java index 115c3d232a..b629d9c8bb 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java @@ -38,7 +38,6 @@ public class JoinMeeting extends RequestWithChecksum { private String fullName; @PasswordConstraint - @NotEmpty(key = "invalidPassword", message = "You must provide either the moderator or attendee password") private String password; @IsBooleanConstraint(message = "Guest must be a boolean value (true or false)") diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/ModeratorPassword.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/ModeratorPassword.java index 6bffcba57e..01f108cb3d 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/ModeratorPassword.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/ModeratorPassword.java @@ -1,6 +1,3 @@ package org.bigbluebutton.api.model.shared; -import org.bigbluebutton.api.model.constraint.ModeratorPasswordConstraint; - -@ModeratorPasswordConstraint public class ModeratorPassword extends Password {} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Password.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Password.java index 81052e835e..9b44c7b1f0 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Password.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Password.java @@ -7,7 +7,6 @@ public abstract class Password { @NotEmpty(message = "You must provide the meeting ID") protected String meetingID; - @NotEmpty(message = "You must provide the password for the call") protected String password; public String getMeetingID() { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/JoinPasswordValidator.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/JoinPasswordValidator.java index 1a67497495..0bebd3b16d 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/JoinPasswordValidator.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/JoinPasswordValidator.java @@ -36,18 +36,10 @@ public class JoinPasswordValidator implements ConstraintValidator { - - private static Logger log = LoggerFactory.getLogger(ModeratorPasswordValidator.class); - - - @Override - public void initialize(ModeratorPasswordConstraint constraintAnnotation) {} - - @Override - public boolean isValid(ModeratorPassword moderatorPassword, ConstraintValidatorContext context) { - log.info("Validating password {} for meeting with ID {}", - moderatorPassword.getPassword(), moderatorPassword.getMeetingID()); - - if(moderatorPassword.getMeetingID() == null) { - return false; - } - - Meeting meeting = ServiceUtils.findMeetingFromMeetingID(moderatorPassword.getMeetingID()); - - if(meeting == null) { - return false; - } - - String actualPassword = meeting.getModeratorPassword(); - String providedPassword = moderatorPassword.getPassword(); - - if(providedPassword == null) { - return false; - } - - log.info("Actual password: {}", actualPassword); - log.info("Provided password: {}", providedPassword); - - if(!providedPassword.equals(actualPassword)) { - return false; - } - - return true; - } -} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PasswordValidator.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PasswordValidator.java index 5210e5a6a3..fa124ce3c2 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PasswordValidator.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PasswordValidator.java @@ -19,15 +19,11 @@ public class PasswordValidator implements ConstraintValidator 64) { - log.info("Passwords must be between 2 and 64 characters in length"); - return false; + if (password != null && !password.isEmpty()){ + if (password.length() < 2 || password.length() > 64) { + log.info("Passwords must be between 2 and 64 characters in length"); + return false; + } } return true; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java index c6cb98758c..e70f1c809b 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java @@ -148,6 +148,7 @@ public class DocumentConversionServiceImp implements DocumentConversionService { pres.getPodId(), pres.getMeetingId(), pres.getId(), + pres.getTemporaryPresentationId(), pres.getName(), pres.getAuthzToken(), pres.isDownloadable(), diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/UploadedPresentation.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/UploadedPresentation.java index 2510d1750a..2aa2fac5ec 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/UploadedPresentation.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/UploadedPresentation.java @@ -26,6 +26,7 @@ public final class UploadedPresentation { private final String podId; private final String meetingId; private final String id; + private final String temporaryPresentationId; private final String name; private final boolean uploadFailed; private final ArrayList uploadFailReason; @@ -44,6 +45,7 @@ public final class UploadedPresentation { public UploadedPresentation(String podId, String meetingId, String id, + String temporaryPresentationId, String name, String baseUrl, Boolean current, @@ -53,6 +55,7 @@ public final class UploadedPresentation { this.podId = podId; this.meetingId = meetingId; this.id = id; + this.temporaryPresentationId = temporaryPresentationId; this.name = name; this.baseUrl = baseUrl; this.isDownloadable = false; @@ -62,6 +65,19 @@ public final class UploadedPresentation { this.uploadFailReason = uploadFailReason; } + public UploadedPresentation(String podId, + String meetingId, + String id, + String name, + String baseUrl, + Boolean current, + String authzToken, + Boolean uploadFailed, + ArrayList uploadFailReason) { + this(podId, meetingId, id, "", name, baseUrl, + current, authzToken, uploadFailed, uploadFailReason); + } + public File getUploadedFile() { return uploadedFile; } @@ -82,6 +98,10 @@ public final class UploadedPresentation { return id; } + public String getTemporaryPresentationId() { + return temporaryPresentationId; + } + public String getName() { return name; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SwfSlidesGenerationProgressNotifier.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SwfSlidesGenerationProgressNotifier.java index 5b6bc11fa6..c1cfb50d80 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SwfSlidesGenerationProgressNotifier.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SwfSlidesGenerationProgressNotifier.java @@ -85,7 +85,7 @@ public class SwfSlidesGenerationProgressNotifier { } DocPageCompletedProgress progress = new DocPageCompletedProgress(pres.getPodId(), pres.getMeetingId(), - pres.getId(), pres.getId(), + pres.getId(), pres.getTemporaryPresentationId(), pres.getId(), pres.getName(), "notUsedYet", "notUsedYet", pres.isDownloadable(), pres.isRemovable(), ConversionMessageConstants.CONVERSION_COMPLETED_KEY, pres.getNumberOfPages(), generateBasePresUrl(pres), pres.isCurrent()); diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocConversionRequestReceived.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocConversionRequestReceived.java index 6a093bc1b5..b64c2a4129 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocConversionRequestReceived.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocConversionRequestReceived.java @@ -4,6 +4,7 @@ public class DocConversionRequestReceived implements IDocConversionMsg { public final String podId; public final String meetingId; public final String presId; + public final String temporaryPresentationId; public final String filename; public final String authzToken; public final Boolean downloadable; @@ -13,6 +14,7 @@ public class DocConversionRequestReceived implements IDocConversionMsg { public DocConversionRequestReceived(String podId, String meetingId, String presId, + String temporaryPresentationId, String filename, String authzToken, Boolean downloadable, @@ -21,6 +23,7 @@ public class DocConversionRequestReceived implements IDocConversionMsg { this.podId = podId; this.meetingId = meetingId; this.presId = presId; + this.temporaryPresentationId = temporaryPresentationId; this.filename = filename; this.authzToken = authzToken; this.downloadable = downloadable; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocPageCompletedProgress.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocPageCompletedProgress.java index eca31b3dad..4f96873e0b 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocPageCompletedProgress.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/messages/DocPageCompletedProgress.java @@ -4,6 +4,7 @@ public class DocPageCompletedProgress implements IDocConversionMsg { public final String podId; public final String meetingId; public final String presId; + public final String temporaryPresentationId; public final String presInstance; public final String filename; public final String uploaderId; @@ -15,13 +16,14 @@ public class DocPageCompletedProgress implements IDocConversionMsg { public final String presBaseUrl; public final Boolean current; - public DocPageCompletedProgress(String podId, String meetingId, String presId, String presInstance, + public DocPageCompletedProgress(String podId, String meetingId, String presId, String temporaryPresentationId, String presInstance, String filename, String uploaderId, String authzToken, Boolean downloadable, Boolean removable, String key, Integer numPages, String presBaseUrl, Boolean current) { this.podId = podId; this.meetingId = meetingId; this.presId = presId; + this.temporaryPresentationId = temporaryPresentationId; this.presInstance = presInstance; this.filename = filename; this.uploaderId = uploaderId; diff --git a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala index f402b0fb07..8d897c7043 100755 --- a/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala +++ b/bbb-common-web/src/main/scala/org/bigbluebutton/api2/MsgBuilder.scala @@ -157,7 +157,7 @@ object MsgBuilder { val header = BbbClientMsgHeader(PresentationConversionCompletedSysPubMsg.NAME, msg.meetingId, msg.authzToken) val pages = generatePresentationPages(msg.presId, msg.numPages.intValue(), msg.presBaseUrl) - val presentation = PresentationVO(msg.presId, msg.filename, + val presentation = PresentationVO(msg.presId, msg.temporaryPresentationId, msg.filename, current = msg.current.booleanValue(), pages.values.toVector, msg.downloadable.booleanValue(), msg.removable.booleanValue()) val body = PresentationConversionCompletedSysPubMsgBody(podId = msg.podId, messageKey = msg.key, @@ -228,6 +228,7 @@ object MsgBuilder { val body = PresentationConversionRequestReceivedSysMsgBody( podId = msg.podId, presentationId = msg.presId, + temporaryPresentationId = msg.temporaryPresentationId, current = msg.current, presName = msg.filename, downloadable = msg.downloadable, diff --git a/bbb-fsesl-client/Dockerfile b/bbb-fsesl-client/Dockerfile deleted file mode 100644 index c9fd93a841..0000000000 --- a/bbb-fsesl-client/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM bbb-common-message - -ARG COMMON_VERSION - -COPY . /bbb-fsesl-client - -RUN cd /bbb-fsesl-client \ - && sed -i "s|\(version := \)\".*|\1\"$COMMON_VERSION\"|g" build.sbt \ - && find -name build.sbt -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-message[^\"]*\"[ ]*%[ ]*\)\"[^\"]*\"\(.*\)|\1\"$COMMON_VERSION\"\2|g" {} \; \ - && echo 'publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository")))' | tee -a build.sbt \ - && sbt compile \ - && sbt publish \ - && sbt publishLocal diff --git a/bbb-learning-dashboard/package-lock.json b/bbb-learning-dashboard/package-lock.json index 69ea8c98e4..303f534df1 100644 --- a/bbb-learning-dashboard/package-lock.json +++ b/bbb-learning-dashboard/package-lock.json @@ -81,9 +81,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", - "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "dependencies": { "eslint-scope": "^5.1.1", "eslint-visitor-keys": "^2.1.0", @@ -151,14 +151,14 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", - "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7" @@ -186,9 +186,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz", - "integrity": "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dependencies": { "@babel/helper-compilation-targets": "^7.13.0", "@babel/helper-module-imports": "^7.12.13", @@ -226,24 +226,12 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -261,11 +249,11 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -525,13 +513,16 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz", - "integrity": "sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", + "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.9", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.16.7" + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/plugin-syntax-decorators": "^7.17.0", + "charcodes": "^0.2.0" }, "engines": { "node": ">=6.9.0" @@ -774,9 +765,9 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz", - "integrity": "sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", + "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1432,14 +1423,14 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.7.tgz", - "integrity": "sha512-2FoHiSAWkdq4L06uaDN3rS43i6x28desUVxq+zAFuE6kbWYQeiLPJI5IC7Sg9xKYVcrBKSQkVUfH6aeQYbl9QA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", + "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", "semver": "^6.3.0" }, @@ -1450,6 +1441,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", @@ -1522,9 +1525,9 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.7.tgz", - "integrity": "sha512-Hzx1lvBtOCWuCEwMmYOfpQpO7joFeXLgoPuzZZBtTxXqSqUGUubvFGZv2ygo1tB5Bp9q6PXV3H0E/kf7KM0RLA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -1760,9 +1763,9 @@ } }, "node_modules/@babel/types": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", - "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -2835,9 +2838,9 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, "node_modules/@rushstack/eslint-patch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.0.tgz", - "integrity": "sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", + "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==" }, "node_modules/@sinonjs/commons": { "version": "1.8.3", @@ -3644,13 +3647,13 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz", - "integrity": "sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz", + "integrity": "sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q==", "dependencies": { - "@typescript-eslint/experimental-utils": "5.9.0", - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/type-utils": "5.9.0", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/type-utils": "5.20.0", + "@typescript-eslint/utils": "5.20.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -3684,9 +3687,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3698,16 +3701,11 @@ } }, "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz", - "integrity": "sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.20.0.tgz", + "integrity": "sha512-w5qtx2Wr9x13Dp/3ic9iGOGmVXK5gMwyc8rwVgZU46K9WTjPZSyPvdER9Ycy+B5lNHvoz+z2muWhUvlTpQeu+g==", "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/typescript-estree": "5.9.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/utils": "5.20.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3720,31 +3718,14 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.0.tgz", - "integrity": "sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.20.0.tgz", + "integrity": "sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w==", "dependencies": { - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/typescript-estree": "5.9.0", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", "debug": "^4.3.2" }, "engines": { @@ -3764,12 +3745,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz", - "integrity": "sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz", + "integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==", "dependencies": { - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/visitor-keys": "5.9.0" + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3780,11 +3761,11 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz", - "integrity": "sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.20.0.tgz", + "integrity": "sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw==", "dependencies": { - "@typescript-eslint/experimental-utils": "5.9.0", + "@typescript-eslint/utils": "5.20.0", "debug": "^4.3.2", "tsutils": "^3.21.0" }, @@ -3805,9 +3786,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.0.tgz", - "integrity": "sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz", + "integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -3817,12 +3798,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz", - "integrity": "sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz", + "integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==", "dependencies": { - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/visitor-keys": "5.9.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -3843,9 +3824,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3856,12 +3837,52 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz", - "integrity": "sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==", + "node_modules/@typescript-eslint/utils": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz", + "integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==", "dependencies": { - "@typescript-eslint/types": "5.9.0", + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz", + "integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==", + "dependencies": { + "@typescript-eslint/types": "5.20.0", "eslint-visitor-keys": "^3.0.0" }, "engines": { @@ -3873,9 +3894,9 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -4362,9 +4383,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -4877,14 +4898,24 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.1", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" }, "bin": { @@ -4892,10 +4923,6 @@ }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/bser": { @@ -4995,13 +5022,19 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001297", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001297.tgz", - "integrity": "sha512-6bbIbowYG8vFs/Lk4hU9jFt7NknGDleVAciK916tp6ft1j+D//ZwwL6LbF1wXMQ32DMSjeuUV8suhh6dlmFjcA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -5032,6 +5065,14 @@ "node": ">=10" } }, + "node_modules/charcodes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", + "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/check-types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", @@ -5328,11 +5369,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.2.tgz", - "integrity": "sha512-qZEzVQ+5Qh6cROaTPFLNS4lkvQ6mBzE3R6A6EEpssj7Zr2egMHgsy4XapdifqJDGC9CBiNv7s+ejI96rLNQFdg==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.2.tgz", + "integrity": "sha512-Fns9lU06ZJ07pdfmPMu7OnkIKGPKDzXKIiuGlSvHHapwqMUF2QnnsWwtueFZtSyZEilP0o6iUeHQwpn7LxtLUw==", "dependencies": { - "browserslist": "^4.19.1", + "browserslist": "^4.20.2", "semver": "7.0.0" }, "funding": { @@ -6224,9 +6265,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.37", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.37.tgz", - "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==" + "version": "1.4.118", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz", + "integrity": "sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==" }, "node_modules/emittery": { "version": "0.8.1", @@ -6642,9 +6683,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/eslint-plugin-jest": { - "version": "25.3.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.3.4.tgz", - "integrity": "sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==", + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0" }, @@ -6751,11 +6792,11 @@ } }, "node_modules/eslint-plugin-testing-library": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.0.1.tgz", - "integrity": "sha512-8ZV4HbbacvOwu+adNnGpYd8E64NRcil2a11aFAbc/TZDUB/xxK2c8Z+LoeoHUbxNBGbTUdpAE4YUugxK85pcwQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.3.1.tgz", + "integrity": "sha512-OfF4dlG/q6ck6DL3P8Z0FPdK0dU5K57gsBu7eUcaVbwYKaNzjgejnXiM9CCUevppORkvfek+9D3Uj/9ZZ8Vz8g==", "dependencies": { - "@typescript-eslint/experimental-utils": "^5.5.0" + "@typescript-eslint/utils": "^5.13.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0", @@ -7274,9 +7315,9 @@ } }, "node_modules/filesize": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.6.tgz", - "integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", "engines": { "node": ">= 0.4.0" } @@ -7461,9 +7502,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz", + "integrity": "sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g==", "dependencies": { "@babel/code-frame": "^7.8.3", "@types/json-schema": "^7.0.5", @@ -7598,9 +7639,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8289,9 +8330,9 @@ } }, "node_modules/immer": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz", - "integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -8900,12 +8941,12 @@ } }, "node_modules/jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "dependencies": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, @@ -8913,13 +8954,77 @@ "jake": "bin/cli.js" }, "engines": { - "node": "*" + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/jake/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest": { "version": "27.4.7", @@ -11262,9 +11367,9 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" }, "node_modules/node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -11721,6 +11826,73 @@ "node": ">= 6" } }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -13034,9 +13206,9 @@ } }, "node_modules/react-dev-utils": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", - "integrity": "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", "dependencies": { "@babel/code-frame": "^7.16.0", "address": "^1.1.2", @@ -13057,7 +13229,7 @@ "open": "^8.4.0", "pkg-up": "^3.1.0", "prompts": "^2.4.2", - "react-error-overlay": "^6.0.10", + "react-error-overlay": "^6.0.11", "recursive-readdir": "^2.2.2", "shell-quote": "^1.7.3", "strip-ansi": "^6.0.1", @@ -13196,14 +13368,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/react-dev-utils/node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -13212,73 +13376,6 @@ "node": ">=8" } }, - "node_modules/react-dev-utils/node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, "node_modules/react-dev-utils/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -13304,9 +13401,9 @@ } }, "node_modules/react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "node_modules/react-intl": { "version": "5.20.10", @@ -13348,9 +13445,9 @@ } }, "node_modules/react-scripts": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", - "integrity": "sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", "dependencies": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", @@ -13368,7 +13465,7 @@ "dotenv": "^10.0.0", "dotenv-expand": "^5.1.0", "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.0", + "eslint-config-react-app": "^7.0.1", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.0", @@ -13385,7 +13482,7 @@ "postcss-preset-env": "^7.0.1", "prompts": "^2.4.2", "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.0", + "react-dev-utils": "^12.0.1", "react-refresh": "^0.11.0", "resolve": "^1.20.0", "resolve-url-loader": "^4.0.0", @@ -13420,15 +13517,15 @@ } }, "node_modules/react-scripts/node_modules/@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.2.0", + "espree": "^9.3.1", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.0.4", @@ -13439,9 +13536,9 @@ } }, "node_modules/react-scripts/node_modules/@humanwhocodes/config-array": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", - "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -13524,23 +13621,22 @@ } }, "node_modules/react-scripts/node_modules/eslint": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.6.0.tgz", - "integrity": "sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", "dependencies": { - "@eslint/eslintrc": "^1.0.5", + "@eslint/eslintrc": "^1.2.2", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", + "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.1.0", - "espree": "^9.3.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -13548,7 +13644,7 @@ "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", @@ -13559,9 +13655,7 @@ "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", "regexpp": "^3.2.0", - "semver": "^7.2.1", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0", @@ -13578,9 +13672,9 @@ } }, "node_modules/react-scripts/node_modules/eslint-config-react-app": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.0.tgz", - "integrity": "sha512-xyymoxtIt1EOsSaGag+/jmcywRuieQoA2JbPCjnw9HukFj9/97aGPoZVFioaotzk1K5Qt9sHO5EutZbkrAXS0g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", "dependencies": { "@babel/core": "^7.16.0", "@babel/eslint-parser": "^7.16.3", @@ -13622,9 +13716,9 @@ } }, "node_modules/react-scripts/node_modules/eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -13651,30 +13745,30 @@ } }, "node_modules/react-scripts/node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/react-scripts/node_modules/espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dependencies": { "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/react-scripts/node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -13691,9 +13785,9 @@ } }, "node_modules/react-scripts/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dependencies": { "type-fest": "^0.20.2" }, @@ -13712,6 +13806,14 @@ "node": ">=8" } }, + "node_modules/react-scripts/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "engines": { + "node": ">= 4" + } + }, "node_modules/react-scripts/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -13724,9 +13826,9 @@ } }, "node_modules/react-scripts/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16693,9 +16795,9 @@ } }, "@babel/eslint-parser": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", - "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "requires": { "eslint-scope": "^5.1.1", "eslint-visitor-keys": "^2.1.0", @@ -16741,14 +16843,14 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", - "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7" @@ -16764,9 +16866,9 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz", - "integrity": "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "requires": { "@babel/helper-compilation-targets": "^7.13.0", "@babel/helper-module-imports": "^7.12.13", @@ -16795,21 +16897,12 @@ } }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "requires": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { @@ -16821,11 +16914,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { @@ -17004,13 +17097,16 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz", - "integrity": "sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", + "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.17.9", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.16.7" + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/plugin-syntax-decorators": "^7.17.0", + "charcodes": "^0.2.0" } }, "@babel/plugin-proposal-dynamic-import": { @@ -17160,9 +17256,9 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz", - "integrity": "sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", + "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", "requires": { "@babel/helper-plugin-utils": "^7.16.7" } @@ -17566,16 +17662,27 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.7.tgz", - "integrity": "sha512-2FoHiSAWkdq4L06uaDN3rS43i6x28desUVxq+zAFuE6kbWYQeiLPJI5IC7Sg9xKYVcrBKSQkVUfH6aeQYbl9QA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", + "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", "requires": { "@babel/helper-module-imports": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.4.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", "semver": "^6.3.0" + }, + "dependencies": { + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + } + } } }, "@babel/plugin-transform-shorthand-properties": { @@ -17620,9 +17727,9 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.7.tgz", - "integrity": "sha512-Hzx1lvBtOCWuCEwMmYOfpQpO7joFeXLgoPuzZZBtTxXqSqUGUubvFGZv2ygo1tB5Bp9q6PXV3H0E/kf7KM0RLA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", "requires": { "@babel/helper-create-class-features-plugin": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -17807,9 +17914,9 @@ } }, "@babel/types": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", - "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "requires": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -18576,9 +18683,9 @@ } }, "@rushstack/eslint-patch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.0.tgz", - "integrity": "sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", + "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==" }, "@sinonjs/commons": { "version": "1.8.3", @@ -19218,13 +19325,13 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz", - "integrity": "sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz", + "integrity": "sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q==", "requires": { - "@typescript-eslint/experimental-utils": "5.9.0", - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/type-utils": "5.9.0", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/type-utils": "5.20.0", + "@typescript-eslint/utils": "5.20.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -19239,9 +19346,9 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -19249,14 +19356,81 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz", - "integrity": "sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.20.0.tgz", + "integrity": "sha512-w5qtx2Wr9x13Dp/3ic9iGOGmVXK5gMwyc8rwVgZU46K9WTjPZSyPvdER9Ycy+B5lNHvoz+z2muWhUvlTpQeu+g==", + "requires": { + "@typescript-eslint/utils": "5.20.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.20.0.tgz", + "integrity": "sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w==", + "requires": { + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", + "debug": "^4.3.2" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz", + "integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==", + "requires": { + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.20.0.tgz", + "integrity": "sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw==", + "requires": { + "@typescript-eslint/utils": "5.20.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz", + "integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==" + }, + "@typescript-eslint/typescript-estree": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz", + "integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==", + "requires": { + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz", + "integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==", "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/typescript-estree": "5.9.0", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -19271,78 +19445,19 @@ } } }, - "@typescript-eslint/parser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.0.tgz", - "integrity": "sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==", - "requires": { - "@typescript-eslint/scope-manager": "5.9.0", - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/typescript-estree": "5.9.0", - "debug": "^4.3.2" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz", - "integrity": "sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==", - "requires": { - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/visitor-keys": "5.9.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz", - "integrity": "sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==", - "requires": { - "@typescript-eslint/experimental-utils": "5.9.0", - "debug": "^4.3.2", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.0.tgz", - "integrity": "sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==" - }, - "@typescript-eslint/typescript-estree": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz", - "integrity": "sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==", - "requires": { - "@typescript-eslint/types": "5.9.0", - "@typescript-eslint/visitor-keys": "5.9.0", - "debug": "^4.3.2", - "globby": "^11.0.4", - "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, "@typescript-eslint/visitor-keys": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz", - "integrity": "sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz", + "integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==", "requires": { - "@typescript-eslint/types": "5.9.0", + "@typescript-eslint/types": "5.20.0", "eslint-visitor-keys": "^3.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" } } }, @@ -19735,9 +19850,9 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { "lodash": "^4.17.14" } @@ -20133,14 +20248,14 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.1", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" } }, @@ -20217,9 +20332,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001297", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001297.tgz", - "integrity": "sha512-6bbIbowYG8vFs/Lk4hU9jFt7NknGDleVAciK916tp6ft1j+D//ZwwL6LbF1wXMQ32DMSjeuUV8suhh6dlmFjcA==" + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==" }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -20241,6 +20356,11 @@ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" }, + "charcodes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", + "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==" + }, "check-types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", @@ -20473,11 +20593,11 @@ "integrity": "sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw==" }, "core-js-compat": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.2.tgz", - "integrity": "sha512-qZEzVQ+5Qh6cROaTPFLNS4lkvQ6mBzE3R6A6EEpssj7Zr2egMHgsy4XapdifqJDGC9CBiNv7s+ejI96rLNQFdg==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.2.tgz", + "integrity": "sha512-Fns9lU06ZJ07pdfmPMu7OnkIKGPKDzXKIiuGlSvHHapwqMUF2QnnsWwtueFZtSyZEilP0o6iUeHQwpn7LxtLUw==", "requires": { - "browserslist": "^4.19.1", + "browserslist": "^4.20.2", "semver": "7.0.0" }, "dependencies": { @@ -21116,17 +21236,17 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "ejs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", + "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", "requires": { - "jake": "^10.6.1" + "jake": "^10.8.5" } }, "electron-to-chromium": { - "version": "1.4.37", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.37.tgz", - "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==" + "version": "1.4.118", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz", + "integrity": "sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==" }, "emittery": { "version": "0.8.1", @@ -21528,9 +21648,9 @@ } }, "eslint-plugin-jest": { - "version": "25.3.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.3.4.tgz", - "integrity": "sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==", + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", "requires": { "@typescript-eslint/experimental-utils": "^5.0.0" } @@ -21601,11 +21721,11 @@ "requires": {} }, "eslint-plugin-testing-library": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.0.1.tgz", - "integrity": "sha512-8ZV4HbbacvOwu+adNnGpYd8E64NRcil2a11aFAbc/TZDUB/xxK2c8Z+LoeoHUbxNBGbTUdpAE4YUugxK85pcwQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.3.1.tgz", + "integrity": "sha512-OfF4dlG/q6ck6DL3P8Z0FPdK0dU5K57gsBu7eUcaVbwYKaNzjgejnXiM9CCUevppORkvfek+9D3Uj/9ZZ8Vz8g==", "requires": { - "@typescript-eslint/experimental-utils": "^5.5.0" + "@typescript-eslint/utils": "^5.13.0" } }, "eslint-scope": { @@ -21887,17 +22007,35 @@ } }, "filelist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", + "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "filesize": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.6.tgz", - "integrity": "sha512-sHvRqTiwdmcuzqet7iVwsbwF6UrV3wIgDf2SHNdY1Hgl8PC45HZg/0xtdw6U2izIV4lccnrY9ftl6wZFNdjYMg==" + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" }, "fill-range": { "version": "7.0.1", @@ -22027,9 +22165,9 @@ "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, "fork-ts-checker-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz", + "integrity": "sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g==", "requires": { "@babel/code-frame": "^7.8.3", "@types/json-schema": "^7.0.5", @@ -22115,9 +22253,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -22614,9 +22752,9 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" }, "immer": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz", - "integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA==" + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" }, "import-fresh": { "version": "3.3.0", @@ -23029,20 +23167,63 @@ } }, "jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "requires": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -24755,9 +24936,9 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" }, "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==" }, "normalize-path": { "version": "3.0.0", @@ -25076,6 +25257,54 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==" }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + } + } + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -25915,9 +26144,9 @@ } }, "react-dev-utils": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", - "integrity": "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", "requires": { "@babel/code-frame": "^7.16.0", "address": "^1.1.2", @@ -25938,7 +26167,7 @@ "open": "^8.4.0", "pkg-up": "^3.1.0", "prompts": "^2.4.2", - "react-error-overlay": "^6.0.10", + "react-error-overlay": "^6.0.11", "recursive-readdir": "^2.2.2", "shell-quote": "^1.7.3", "strip-ansi": "^6.0.1", @@ -26023,64 +26252,11 @@ "p-limit": "^3.0.2" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "requires": { - "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -26102,9 +26278,9 @@ } }, "react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "react-intl": { "version": "5.20.10", @@ -26134,9 +26310,9 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, "react-scripts": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", - "integrity": "sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", "requires": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", @@ -26154,7 +26330,7 @@ "dotenv": "^10.0.0", "dotenv-expand": "^5.1.0", "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.0", + "eslint-config-react-app": "^7.0.1", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.0", @@ -26172,7 +26348,7 @@ "postcss-preset-env": "^7.0.1", "prompts": "^2.4.2", "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.0", + "react-dev-utils": "^12.0.1", "react-refresh": "^0.11.0", "resolve": "^1.20.0", "resolve-url-loader": "^4.0.0", @@ -26189,15 +26365,15 @@ }, "dependencies": { "@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.2.0", + "espree": "^9.3.1", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.0.4", @@ -26205,9 +26381,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", - "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -26260,23 +26436,22 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "eslint": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.6.0.tgz", - "integrity": "sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", "requires": { - "@eslint/eslintrc": "^1.0.5", + "@eslint/eslintrc": "^1.2.2", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", + "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.1.0", - "espree": "^9.3.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -26284,7 +26459,7 @@ "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", @@ -26295,9 +26470,7 @@ "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", "regexpp": "^3.2.0", - "semver": "^7.2.1", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0", @@ -26305,16 +26478,16 @@ }, "dependencies": { "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" } } }, "eslint-config-react-app": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.0.tgz", - "integrity": "sha512-xyymoxtIt1EOsSaGag+/jmcywRuieQoA2JbPCjnw9HukFj9/97aGPoZVFioaotzk1K5Qt9sHO5EutZbkrAXS0g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", "requires": { "@babel/core": "^7.16.0", "@babel/eslint-parser": "^7.16.3", @@ -26342,9 +26515,9 @@ } }, "eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -26359,19 +26532,19 @@ } }, "espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "requires": { "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" + "eslint-visitor-keys": "^3.3.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" } } }, @@ -26384,9 +26557,9 @@ } }, "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "requires": { "type-fest": "^0.20.2" } @@ -26396,6 +26569,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -26405,9 +26583,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } diff --git a/bbb-learning-dashboard/src/App.js b/bbb-learning-dashboard/src/App.js index bff6d1806f..a28b71a091 100644 --- a/bbb-learning-dashboard/src/App.js +++ b/bbb-learning-dashboard/src/App.js @@ -49,7 +49,7 @@ class App extends React.Component { downloadButton.setAttribute('disabled', 'true'); downloadButton.style.cursor = 'not-allowed'; - link.setAttribute('href', `data:application/octet-stream,${encodeURIComponent(data)}`); + link.setAttribute('href', `data:text/csv;charset=UTF-8,${encodeURIComponent(data)}`); link.setAttribute('download', filename); link.style.display = 'none'; document.body.appendChild(link); @@ -87,14 +87,19 @@ class App extends React.Component { const cDecoded = decodeURIComponent(document.cookie); const cArr = cDecoded.split('; '); cArr.forEach((val) => { - if (val.indexOf(`${cookieName}=`) === 0) learningDashboardAccessToken = val.substring((`${cookieName}=`).length); + if (val.indexOf(`${cookieName}=`) === 0) { + learningDashboardAccessToken = val.substring((`${cookieName}=`).length); + } }); // Extend AccessToken lifetime by 7d (in each access) if (learningDashboardAccessToken !== '') { const cookieExpiresDate = new Date(); cookieExpiresDate.setTime(cookieExpiresDate.getTime() + (3600000 * 24 * 7)); - document.cookie = `ld-${meetingId}=${learningDashboardAccessToken}; expires=${cookieExpiresDate.toGMTString()}; path=/;SameSite=None;Secure`; + const value = `ld-${meetingId}=${learningDashboardAccessToken};`; + const expire = `expires=${cookieExpiresDate.toGMTString()};`; + const args = 'path=/;SameSite=None;Secure'; + document.cookie = `${value} ${expire} ${args}`; } } diff --git a/bbb-learning-dashboard/src/components/Card.jsx b/bbb-learning-dashboard/src/components/Card.jsx index b0e985e24c..fd19f1dc19 100644 --- a/bbb-learning-dashboard/src/components/Card.jsx +++ b/bbb-learning-dashboard/src/components/Card.jsx @@ -34,7 +34,12 @@ function Card(props) { } return ( -
+

{ number } diff --git a/bbb-learning-dashboard/src/components/StatusTable.jsx b/bbb-learning-dashboard/src/components/StatusTable.jsx index b8d501ae48..c9fa9ffe40 100644 --- a/bbb-learning-dashboard/src/components/StatusTable.jsx +++ b/bbb-learning-dashboard/src/components/StatusTable.jsx @@ -104,6 +104,61 @@ class StatusTable extends React.Component { const isRTL = document.dir === 'rtl'; + function makeLineThrough(userPeriod, period) { + const { registeredOn, leftOn } = userPeriod; + const boundaryLeft = period.start; + const boundaryRight = period.end; + const interval = period.end - period.start; + let roundedLeft = registeredOn >= boundaryLeft + && registeredOn <= boundaryRight ? 'rounded-l' : ''; + let roundedRight = leftOn >= boundaryLeft + && leftOn <= boundaryRight ? 'rounded-r' : ''; + let offsetLeft = 0; + let offsetRight = 0; + if (registeredOn >= boundaryLeft && registeredOn <= boundaryRight) { + offsetLeft = ((registeredOn - boundaryLeft) * 100) / interval; + } + if (leftOn >= boundaryLeft && leftOn <= boundaryRight) { + offsetRight = ((boundaryRight - leftOn) * 100) / interval; + } + let width = ''; + if (offsetLeft === 0 && offsetRight >= 99) { + width = 'w-1.5'; + } + if (offsetRight === 0 && offsetLeft >= 99) { + width = 'w-1.5'; + } + if (offsetLeft && offsetRight) { + const variation = offsetLeft - offsetRight; + if (variation > -1 && variation < 1) { + width = 'w-1.5'; + } + } + if (isRTL) { + const aux = roundedRight; + + if (roundedLeft !== '') roundedRight = 'rounded-r'; + else roundedRight = ''; + + if (aux !== '') roundedLeft = 'rounded-l'; + else roundedLeft = ''; + } + const redress = '(0.375rem / 2)'; + return ( +

+ ); + } + return ( @@ -134,6 +189,8 @@ class StatusTable extends React.Component { { periods.map((period) => { const { slide, start, end } = period; const padding = isRTL ? 'paddingLeft' : 'paddingRight'; + const URLPrefix = `/bigbluebutton/presentation/${meetingId}/${meetingId}`; + const { presentationId, pageNum } = slide || {}; return ( - Spacebar + {intl.formatMessage(intlMessages.togglePanKey)}{intl.formatMessage(intlMessages.togglePan)} )); shortcutItems.push(( - Enter + {intl.formatMessage(intlMessages.toggleFullscreenKey)}{intl.formatMessage(intlMessages.toggleFullscreen)} )); shortcutItems.push(( - Right Arrow + {intl.formatMessage(intlMessages.nextSlideKey)}{intl.formatMessage(intlMessages.nextSlideDesc)} )); shortcutItems.push(( - Left Arrow + {intl.formatMessage(intlMessages.previousSlideKey)}{intl.formatMessage(intlMessages.previousSlideDesc)} )); diff --git a/bigbluebutton-html5/imports/ui/components/sidebar-content/component.jsx b/bigbluebutton-html5/imports/ui/components/sidebar-content/component.jsx index 3fd42a7207..c07c3d12d7 100644 --- a/bigbluebutton-html5/imports/ui/components/sidebar-content/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/sidebar-content/component.jsx @@ -123,6 +123,10 @@ const SidebarContent = (props) => { width, height, }} + handleStyles={{ + left: { height: '100vh' }, + right: { height: '100vh' }, + }} > {sidebarContentPanel === PANELS.CHAT && ( diff --git a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx index 7655af144a..42e10cbb49 100644 --- a/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/status-notifier/component.jsx @@ -62,7 +62,9 @@ class StatusNotifier extends Component { switch (status) { case 'raiseHand': - if (emojiUsers.length === 0) return toast.dismiss(this.statusNotifierId); + if (emojiUsers.length === 0) { + return this.statusNotifierId ? toast.dismiss(this.statusNotifierId) : null; + } if (raiseHandAudioAlert && emojiUsers.length > prevProps.emojiUsers.length) { this.audio.play(); diff --git a/bigbluebutton-html5/imports/ui/components/user-avatar/styles.js b/bigbluebutton-html5/imports/ui/components/user-avatar/styles.js index 1cfa77e09f..1f604f188a 100644 --- a/bigbluebutton-html5/imports/ui/components/user-avatar/styles.js +++ b/bigbluebutton-html5/imports/ui/components/user-avatar/styles.js @@ -65,9 +65,12 @@ const Talking = styled.div` right: 0; bottom: 0; left: 0; - background-color: currentColor; border-radius: inherit; + ${({ talking }) => talking && css` + background-color: currentColor; + `} + ${({ talking, animations }) => talking && animations && css` animation: ${pulse} 1s infinite ease-in; `} diff --git a/bigbluebutton-html5/imports/ui/components/user-list/captions-list-item/styles.js b/bigbluebutton-html5/imports/ui/components/user-list/captions-list-item/styles.js index 418d66d9fe..d9cf463aff 100644 --- a/bigbluebutton-html5/imports/ui/components/user-list/captions-list-item/styles.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/captions-list-item/styles.js @@ -1,8 +1,8 @@ import styled from 'styled-components'; -import Styled from '/imports/ui/components/user-list/styles'; +import StyledContent from '/imports/ui/components/user-list/user-list-content/styles'; -const ListItem = styled(Styled.ListItem)``; +const ListItem = styled(StyledContent.ListItem)``; export default { ListItem, diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js index 505857dc35..8a48c3754a 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/service.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js @@ -213,7 +213,7 @@ const getUsers = () => { }; const formatUsers = (contextUsers, videoUsers, whiteboardUsers) => { - let users = contextUsers.filter((user) => !user.loggedOut); + let users = contextUsers.filter((user) => user.loggedOut === false && user.left === false); const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { role: 1, locked: 1 } }); if (currentUser && currentUser.role === ROLE_VIEWER && currentUser.locked) { diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx index b8374ce81f..0017d62731 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx @@ -81,6 +81,8 @@ class UserParticipants extends Component { this.handleClickSelectedUser, ); } + + window.addEventListener('beforeunload', () => Session.set('dropdownOpenUserId', null)); } shouldComponentUpdate(nextProps) { diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/component.jsx index 3b1922eb74..518718f342 100644 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/component.jsx @@ -208,6 +208,16 @@ class UserListItem extends PureComponent { this.seperator = _.uniqueId('action-separator-'); } + componentDidUpdate() { + const { user, selectedUserId } = this.props; + const { selected } = this.state; + if (selectedUserId === user?.userId && !selected) { + this.setState({ selected: true }); + } else if (selectedUserId !== user?.userId && selected) { + this.setState({ selected: false }); + } + } + handleScroll() { this.setState({ isActionsOpen: false, @@ -646,6 +656,7 @@ class UserListItem extends PureComponent { userLastBreakout, isMe, isRTL, + selectedUserId, } = this.props; const { @@ -814,7 +825,7 @@ class UserListItem extends PureComponent { isActionsOpen={isActionsOpen} selected={selected === true} tabIndex={-1} - onClick={() => this.setState({ selected: true })} + onClick={() => this.setState({ selected: true }, () => Session.set('dropdownOpenUserId', user.userId))} onKeyPress={() => { }} role="button" > @@ -824,7 +835,8 @@ class UserListItem extends PureComponent { } actions={actions} selectedEmoji={user.emoji} - onCloseCallback={() => this.setState({ selected: false, showNestedOptions: false })} + onCloseCallback={() => this.setState({ selected: false }, () => Session.set('dropdownOpenUserId', null))} + open={selectedUserId === user.userId} /> ); } diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/container.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/container.jsx index dc0a8c393c..e5d93a482a 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/container.jsx @@ -56,5 +56,6 @@ export default withTracker(({ user }) => { getEmojiList: UserListService.getEmojiList(), getEmoji: UserListService.getEmoji(), usersProp: UserListService.getUsersProp(), + selectedUserId: Session.get('dropdownOpenUserId'), }; })(UserListItemContainer); diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx index f7b292fe93..217b1e6b9a 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx @@ -281,6 +281,7 @@ class UserOptions extends PureComponent { // description: , onClick: this.onSaveUserNames, icon: 'download', + dataTest: 'downloadUserNamesList', }); } diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx index a50d8aa118..a9fe9dd118 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx @@ -29,7 +29,10 @@ const { baseTimeout: CAMERA_SHARE_FAILED_WAIT_TIME = 15000, maxTimeout: MAX_CAMERA_SHARE_FAILED_WAIT_TIME = 60000, } = Meteor.settings.public.kurento.cameraTimeouts || {}; -const CAMERA_QUALITY_THRESHOLDS_ENABLED = Meteor.settings.public.kurento.cameraQualityThresholds.enabled; +const { + enabled: CAMERA_QUALITY_THRESHOLDS_ENABLED = true, + privilegedStreams: CAMERA_QUALITY_THR_PRIVILEGED = true, +} = Meteor.settings.public.kurento.cameraQualityThresholds; const PING_INTERVAL = 15000; const SIGNAL_CANDIDATES = Meteor.settings.public.kurento.signalCandidates; @@ -256,7 +259,7 @@ class VideoProvider extends Component { findAllPrivilegedStreams () { const { streams } = this.props; - // Privileged streams are: floor holders + // Privileged streams are: floor holders, pinned users return streams.filter(stream => stream.floor || stream.pin); } @@ -267,9 +270,11 @@ class VideoProvider extends Component { Object.values(this.webRtcPeers) .filter(peer => peer.isPublisher) .forEach((peer) => { + // Conditions which make camera revert their original profile // 1) Threshold 0 means original profile/inactive constraint - // 2) Privileged streams are: floor holders - const exempt = threshold === 0 || privilegedStreams.some(vs => vs.stream === peer.stream) + // 2) Privileged streams + const exempt = threshold === 0 + || (CAMERA_QUALITY_THR_PRIVILEGED && privilegedStreams.some(vs => vs.stream === peer.stream)) const profileToApply = exempt ? peer.originalProfileId : profile; VideoService.applyCameraProfile(peer, profileToApply); }); diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/service.js b/bigbluebutton-html5/imports/ui/components/video-provider/service.js index 479a3fbe38..4f71ed98d0 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/service.js +++ b/bigbluebutton-html5/imports/ui/components/video-provider/service.js @@ -30,7 +30,11 @@ const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const ROLE_VIEWER = Meteor.settings.public.user.role_viewer; const MIRROR_WEBCAM = Meteor.settings.public.app.mirrorOwnWebcam; const PIN_WEBCAM = Meteor.settings.public.kurento.enableVideoPin; -const CAMERA_QUALITY_THRESHOLDS = Meteor.settings.public.kurento.cameraQualityThresholds.thresholds || []; +const { + thresholds: CAMERA_QUALITY_THRESHOLDS = [], + applyConstraints: CAMERA_QUALITY_THR_CONSTRAINTS = false, + debounceTime: CAMERA_QUALITY_THR_DEBOUNCE = 2500, +} = Meteor.settings.public.kurento.cameraQualityThresholds; const { paginationToggleEnabled: PAGINATION_TOGGLE_ENABLED, pageChangeDebounceTime: PAGE_CHANGE_DEBOUNCE_TIME, @@ -726,10 +730,15 @@ class VideoService { this.exitVideo(); } + getStatus() { + if (this.isConnecting) return 'videoConnecting'; + if (this.isConnected) return 'connected'; + return 'disconnected'; + } + disableReason() { const locks = { videoLocked: this.isUserLocked(), - videoConnecting: this.isConnecting, camCapReached: this.hasCapReached() && !this.hasVideoStream(), meteorDisconnected: !Meteor.status().connected }; @@ -832,59 +841,58 @@ class VideoService { return { ...constraints, width: trackSettings.width, - height: trackSettings.height + height: trackSettings.height, }; - } else { - return constraints; } + + return constraints; } applyCameraProfile (peer, profileId) { - const profile = CAMERA_PROFILES.find(targetProfile => targetProfile.id === profileId); + const profile = CAMERA_PROFILES.find((targetProfile) => targetProfile.id === profileId); - if (!profile) { - logger.warn({ - logCode: 'video_provider_noprofile', - extraInfo: { profileId }, - }, `Apply failed: no camera profile found.`); - return; - } - - // Profile is currently applied or it's better than the original user's profile, - // skip - if (peer.currentProfileId === profileId + // When this should be skipped: + // 1 - Badly defined profile + // 2 - Badly defined peer (ie {}) + // 3 - The target profile is already applied + // 4 - The targetr profile is better than the original profile + if (!profile + || peer == null + || peer.peerConnection == null + || peer.currentProfileId === profileId || this.isProfileBetter(profileId, peer.originalProfileId)) { return; } const { bitrate, constraints } = profile; - if (bitrate) { - this.applyBitrate(peer, bitrate); - } + if (bitrate) this.applyBitrate(peer, bitrate); - if (constraints && typeof constraints === 'object') { - peer.peerConnection.getSenders().forEach(sender => { + if (CAMERA_QUALITY_THR_CONSTRAINTS + && constraints + && typeof constraints === 'object' + ) { + peer.peerConnection.getSenders().forEach((sender) => { const { track } = sender; - if (track && track.kind === 'video' && typeof track.applyConstraints === 'function') { - let normalizedVideoConstraints = this.reapplyResolutionIfNeeded(track, constraints); + if (track && track.kind === 'video' && typeof track.applyConstraints === 'function') { + const normalizedVideoConstraints = this.reapplyResolutionIfNeeded(track, constraints); track.applyConstraints(normalizedVideoConstraints) - .then(() => { - logger.info({ - logCode: 'video_provider_profile_applied', - extraInfo: { profileId }, - }, `New camera profile applied: ${profileId}`); - peer.currentProfileId = profileId; - }) - .catch(error => { + .catch((error) => { logger.warn({ - logCode: 'video_provider_profile_apply_failed', + logCode: 'video_provider_constraintchange_failed', extraInfo: { errorName: error.name, errorCode: error.code }, }, 'Error applying camera profile'); }); } }); } + + logger.info({ + logCode: 'video_provider_profile_applied', + extraInfo: { profileId }, + }, `New camera profile applied: ${profileId}`); + + peer.currentProfileId = profileId; } getThreshold (numberOfPublishers) { @@ -989,6 +997,7 @@ export default { getAuthenticatedURL: () => videoService.getAuthenticatedURL(), isLocalStream: cameraId => videoService.isLocalStream(cameraId), hasVideoStream: () => videoService.hasVideoStream(), + getStatus: () => videoService.getStatus(), disableReason: () => videoService.disableReason(), playStart: cameraId => videoService.playStart(cameraId), getCameraProfile: () => videoService.getCameraProfile(), @@ -1005,7 +1014,11 @@ export default { onBeforeUnload: () => videoService.onBeforeUnload(), notify: message => notify(message, 'error', 'video'), updateNumberOfDevices: devices => videoService.updateNumberOfDevices(devices), - applyCameraProfile: (peer, newProfile) => videoService.applyCameraProfile(peer, newProfile), + applyCameraProfile: _.debounce( + videoService.applyCameraProfile.bind(videoService), + CAMERA_QUALITY_THR_DEBOUNCE, + { leading: false, trailing: true }, + ), getThreshold: (numberOfPublishers) => videoService.getThreshold(numberOfPublishers), isPaginationEnabled: () => videoService.isPaginationEnabled(), getNumberOfPages: () => videoService.getNumberOfPages(), diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-button/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-button/component.jsx index 55d1450aeb..e7e0f26bf0 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-button/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-button/component.jsx @@ -50,50 +50,62 @@ const JOIN_VIDEO_DELAY_MILLISECONDS = 500; const propTypes = { intl: PropTypes.object.isRequired, hasVideoStream: PropTypes.bool.isRequired, + status: PropTypes.string.isRequired, mountVideoPreview: PropTypes.func.isRequired, - forceMountVideoPreview: PropTypes.func.isRequired, }; const JoinVideoButton = ({ intl, hasVideoStream, + status, disableReason, mountVideoPreview, - forceMountVideoPreview, }) => { const { isMobile } = deviceInfo; - const shouldEnableWebcamSelectorButton = ENABLE_WEBCAM_SELECTOR_BUTTON - && hasVideoStream - && !isMobile; - const exitVideo = () => hasVideoStream - && !isMobile - && (!VideoService.isMultipleCamerasEnabled() || shouldEnableWebcamSelectorButton); const isMobileSharingCamera = hasVideoStream && isMobile; + const isDesktopSharingCamera = hasVideoStream && !isMobile; + const shouldEnableWebcamSelectorButton = ENABLE_WEBCAM_SELECTOR_BUTTON + && isDesktopSharingCamera; + const exitVideo = () => isDesktopSharingCamera && (!VideoService.isMultipleCamerasEnabled() + || shouldEnableWebcamSelectorButton); const handleOnClick = debounce(() => { if (!validIOSVersion()) { return VideoService.notify(intl.formatMessage(intlMessages.iOSWarning)); } - if (exitVideo()) { - VideoService.exitVideo(); - } else if (isMobileSharingCamera) { - forceMountVideoPreview(); - } else { - mountVideoPreview(); + switch (status) { + case 'videoConnecting': + VideoService.stopVideo(); + break; + case 'connected': + default: + if (exitVideo()) { + VideoService.exitVideo(); + } else { + mountVideoPreview(isMobileSharingCamera); + } } }, JOIN_VIDEO_DELAY_MILLISECONDS); const handleOpenAdvancedOptions = (e) => { e.stopPropagation(); - forceMountVideoPreview(); + mountVideoPreview(isMobileSharingCamera); }; - let label = exitVideo() - ? intl.formatMessage(intlMessages.leaveVideo) - : intl.formatMessage(intlMessages.joinVideo); + const getMessageFromStatus = () => { + let statusMessage = status; + if (status !== 'videoConnecting') { + statusMessage = exitVideo() ? 'leaveVideo' : 'joinVideo'; + } + return statusMessage; + }; - if (disableReason) label = intl.formatMessage(intlMessages[disableReason]); + const label = disableReason + ? intl.formatMessage(intlMessages[disableReason]) + : intl.formatMessage(intlMessages[getMessageFromStatus()]); + + const isSharing = hasVideoStream || status === 'videoConnecting'; const renderEmojiButton = () => ( shouldEnableWebcamSelectorButton @@ -114,9 +126,9 @@ const JoinVideoButton = ({ data-test={hasVideoStream ? 'leaveVideo' : 'joinVideo'} onClick={handleOnClick} hideLabel - color={hasVideoStream ? 'primary' : 'default'} - icon={hasVideoStream ? 'video' : 'video_off'} - ghost={!hasVideoStream} + color={isSharing ? 'primary' : 'default'} + icon={isSharing ? 'video' : 'video_off'} + ghost={!isSharing} size="lg" circle disabled={!!disableReason} diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-button/container.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-button/container.jsx index bef569424f..bfcb3c6815 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-button/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-button/container.jsx @@ -10,17 +10,17 @@ const JoinVideoOptionsContainer = (props) => { const { hasVideoStream, disableReason, + status, intl, mountModal, ...restProps } = props; - const mountVideoPreview = () => { mountModal(); }; - const forceMountVideoPreview = () => { mountModal(); }; + const mountVideoPreview = (force) => { mountModal(); }; return ( ); @@ -29,4 +29,5 @@ const JoinVideoOptionsContainer = (props) => { export default withModalMounter(injectIntl(withTracker(() => ({ hasVideoStream: VideoService.hasVideoStream(), disableReason: VideoService.disableReason(), + status: VideoService.getStatus(), }))(JoinVideoOptionsContainer))); diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx index aac238c700..1a123f04ac 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx @@ -11,6 +11,7 @@ import { unsubscribeFromStreamStateChange, } from '/imports/ui/services/bbb-webrtc-sfu/stream-state-service'; import Settings from '/imports/ui/services/settings'; +import VideoService from '/imports/ui/components/video-provider/service'; import Styled from './styles'; const VideoListItem = (props) => { @@ -21,7 +22,7 @@ const VideoListItem = (props) => { const [videoIsReady, setVideoIsReady] = useState(false); const [isStreamHealthy, setIsStreamHealthy] = useState(false); - const [isMirrored, setIsMirrored] = useState(false); + const [isMirrored, setIsMirrored] = useState(VideoService.mirrorOwnWebcam(user?.userId)); const videoTag = useRef(); const videoContainer = useRef(); @@ -146,13 +147,14 @@ const VideoListItem = (props) => { muted mirrored={isMirrored} unhealthyStream={shouldRenderReconnect} + data-test={isMirrored ? 'mirroredVideoContainer' : 'videoContainer'} ref={videoTag} autoPlay playsInline /> - {shouldRenderReconnect && } + {shouldRenderReconnect && } ); }; @@ -183,6 +185,7 @@ VideoListItem.propTypes = { muted: PropTypes.bool.isRequired, listenOnly: PropTypes.bool.isRequired, talking: PropTypes.bool.isRequired, + joined: PropTypes.bool.isRequired, }).isRequired, focused: PropTypes.bool.isRequired, }; diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/container.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/container.jsx index 63bf3422d5..8431b47989 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/container.jsx @@ -32,7 +32,11 @@ export default withTracker((props) => { return { voiceUser: VoiceUsers.findOne({ intId: userId }, - { fields: { muted: 1, listenOnly: 1, talking: 1 } }), + { + fields: { + muted: 1, listenOnly: 1, talking: 1, joined: 1, + }, + }), user: Users.findOne({ intId: userId }, { fields: { diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/styles.js b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/styles.js index c390363965..43e0de4e5a 100644 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/styles.js +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/styles.js @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled, { keyframes, css } from 'styled-components'; import { colorPrimary, colorBlack, @@ -6,6 +6,15 @@ import { } from '/imports/ui/stylesheets/styled-components/palette'; import { TextElipsis } from '/imports/ui/stylesheets/styled-components/placeholders'; +const rotate360 = keyframes` + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +`; + const Content = styled.div` position: relative; display: flex; @@ -96,37 +105,23 @@ const Reconnecting = styled.div` position: absolute; height: 100%; width: 100%; - object-fit: contain; + display: flex; font-size: 2.5rem; - text-align: center; - white-space: nowrap; z-index: 1; - - &::after { - content: ''; - display: inline-block; - height: 100%; - vertical-align: middle; - margin: 0 -0.25em 0 0; - - [dir="rtl"] & { - margin: 0 0 0 -0.25em; - } - } - - &::before { - content: "\\e949"; - /* ascii code for the ellipsis character */ - font-family: 'bbb-icons' !important; - display: inline-block; - - ${({ animations }) => animations && ` - animation: spin 4s infinite linear; - `} - } - + align-items: center; + justify-content: center; background-color: transparent; color: ${colorWhite}; + + &::before { + font-family: 'bbb-icons' !important; + content: "\\e949"; + /* ascii code for the ellipsis character */ + display: inline-block; + ${({ animations }) => animations && css` + animation: ${rotate360} 2s infinite linear; + `} + } `; const VideoContainer = styled.div` diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/user-status/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/user-status/component.jsx index 12fbef4da8..b6e887b112 100644 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/user-status/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/user-status/component.jsx @@ -20,13 +20,10 @@ const UserStatus = (props) => { export default UserStatus; -UserStatus.defaultProps = { -}; - UserStatus.propTypes = { voiceUser: PropTypes.shape({ listenOnly: PropTypes.bool.isRequired, muted: PropTypes.bool.isRequired, - joined: PropTypes.bool, + joined: PropTypes.bool.isRequired, }).isRequired, }; diff --git a/bigbluebutton-html5/imports/ui/components/waiting-users/component.jsx b/bigbluebutton-html5/imports/ui/components/waiting-users/component.jsx index d8d5c940ed..8aabbeb171 100755 --- a/bigbluebutton-html5/imports/ui/components/waiting-users/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/waiting-users/component.jsx @@ -344,9 +344,7 @@ const WaitingUsers = (props) => {

) : null} - {existPendingUsers && ( -
-
+ {intl.formatMessage(intlMessages.optionTitle)} { buttonsData.map((buttonData) => renderButton( @@ -354,8 +352,6 @@ const WaitingUsers = (props) => { buttonData, )) } -
- {allowRememberChoice ? ( @@ -364,8 +360,7 @@ const WaitingUsers = (props) => { ) : null} -
- )} + {renderPendingUsers( intl.formatMessage(intlMessages.pendingUsers, { 0: authenticatedUsers.length }), diff --git a/bigbluebutton-html5/imports/ui/components/waiting-users/styles.js b/bigbluebutton-html5/imports/ui/components/waiting-users/styles.js index 8c0ae32198..c93790c077 100644 --- a/bigbluebutton-html5/imports/ui/components/waiting-users/styles.js +++ b/bigbluebutton-html5/imports/ui/components/waiting-users/styles.js @@ -126,6 +126,8 @@ const CustomButton = styled(Button)` margin: .3rem 0; font-weight: 400; font-size: ${fontSizeBase}; + overflow: hidden; + text-overflow: ellipsis; `; const Panel = styled.div` @@ -245,6 +247,10 @@ const ScrollableArea = styled(ScrollboxVertical)` padding-right: 0.25rem; `; +const ModeratorActions = styled.div` + padding: 0 .2rem; +`; + export default { ListItem, UserContentContainer, @@ -266,4 +272,5 @@ export default { LobbyMessage, RememberContainer, ScrollableArea, + ModeratorActions, }; diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/annotations/poll/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/annotations/poll/component.jsx index 25044d31e7..b610e69fa7 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/annotations/poll/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/annotations/poll/component.jsx @@ -637,7 +637,7 @@ class PollDrawComponent extends Component { } ariaResultLabel = `${intl.formatMessage(intlMessages.pollResultAria)}: `; - textArray.map((t, idx) => { + textArray.forEach((t, idx) => { const pollLine = t.slice(0, -1); ariaResultLabel += `${idx > 0 ? ' |' : ''} ${pollLine.join(' | ')}`; }); diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/styles.js b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/styles.js index 2d277b7e97..21b47b10bd 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/styles.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/styles.js @@ -6,7 +6,7 @@ import { colorDanger, colorWhite, colorGrayDark, - colorGrayLighter, + toolbarButtonBorderColor, } from '/imports/ui/stylesheets/styled-components/palette'; import { toolbarButtonWidth, @@ -16,6 +16,8 @@ import { smPaddingX, toolbarMargin, toolbarButtonBorderRadius, + toolbarItemOutlineOffset, + toolbarButtonBorder, } from '/imports/ui/stylesheets/styled-components/general'; import { smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints'; @@ -87,11 +89,11 @@ const ToolbarWrapper = styled.div` pointer-events: all; .toolbarButtonWrapper > button { - outline-offset: -.19rem; - border-bottom: 1px solid ${colorGrayLighter}; + outline-offset: ${toolbarItemOutlineOffset}; + border-bottom: ${toolbarButtonBorder} solid ${toolbarButtonBorderColor}; } - .toolbarButtonWrapper:first-child > button { + & > .toolbarButtonWrapper:first-child > button { border-top-left-radius: ${toolbarButtonBorderRadius}; border-top-right-radius: ${toolbarButtonBorderRadius}; diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/toolbar-menu-item/styles.js b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/toolbar-menu-item/styles.js index c03f4ae428..d060de3d78 100644 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/toolbar-menu-item/styles.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/toolbar-menu-item/styles.js @@ -3,8 +3,6 @@ import styled from 'styled-components'; import { toolbarButtonWidth, toolbarButtonHeight, - toolbarItemOutlineOffset, - toolbarButtonBorder, toolbarButtonBorderRadius, toolbarItemTrianglePadding, } from '/imports/ui/stylesheets/styled-components/general'; @@ -25,22 +23,6 @@ const ButtonWrapper = styled.div` min-height: ${toolbarButtonHeight}; position: relative; - & > button { - outline-offset: ${toolbarItemOutlineOffset}; - border-bottom: ${toolbarButtonBorder} solid ${toolbarButtonBorderColor}; - } - - &:first-child > button { - border-top-left-radius: ${toolbarButtonBorderRadius}; - border-top-right-radius: ${toolbarButtonBorderRadius}; - } - - &:last-child > button { - border-bottom: 0; - border-bottom-left-radius: ${toolbarButtonBorderRadius}; - border-bottom-right-radius: ${toolbarButtonBorderRadius}; - } - ${({ showCornerTriangle }) => showCornerTriangle && ` &::before { content: ''; diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js index a2c54cb19a..cf6ad59528 100755 --- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js +++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js @@ -437,7 +437,6 @@ class AudioManager { this.inputDevice = { id: 'default' }; } - window.parent.postMessage({ response: 'notInAudio' }, '*'); window.removeEventListener('audioPlayFailed', this.handlePlayElementFailed); const bridge = diff --git a/bigbluebutton-html5/package-lock.json b/bigbluebutton-html5/package-lock.json index a60d3efdf0..e961086ef5 100644 --- a/bigbluebutton-html5/package-lock.json +++ b/bigbluebutton-html5/package-lock.json @@ -133,20 +133,20 @@ "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==" }, "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", - "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", "dev": true, "requires": { - "core-js-pure": "^3.0.0", + "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" } }, @@ -313,43 +313,48 @@ } }, "@browser-bunyan/console-formatted-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@browser-bunyan/console-formatted-stream/-/console-formatted-stream-1.6.2.tgz", - "integrity": "sha512-RFY4VG5+ewPG5A4LC3uN4AC8MIXEjlUJ568VlXhdMDfV9/LUrUX1LUbf0UmFQ3OhI2jqbeC31XwP0gBIrwbXpw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@browser-bunyan/console-formatted-stream/-/console-formatted-stream-1.8.0.tgz", + "integrity": "sha512-Lg5SC2uXrvZ6aLwLZT6SErfN1Is4NcrTOb5km4BW/BfL8Lv0CfpsYuhuD7ltdURL6awTYBUiT+BwhKw1Xd9glQ==", "requires": { - "@browser-bunyan/levels": "^1.6.0" + "@browser-bunyan/levels": "^1.8.0" } }, "@browser-bunyan/console-plain-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@browser-bunyan/console-plain-stream/-/console-plain-stream-1.6.0.tgz", - "integrity": "sha512-92j8/Lk7yD6F4JKygWd7g9++QoNiEIj1MAP5zMGVk0g1ssPs3vqK1F+HgWfzYaHccREJ6S553imX9Ll5OAn2nA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@browser-bunyan/console-plain-stream/-/console-plain-stream-1.8.0.tgz", + "integrity": "sha512-S0WNsH5zvMfkbayIx90wANGHQ8l3Bvd7mjgy95/bYmUzcI+Mwkv2eJcSufdTP/MbdHBhjv/lEdLDOXEPBi+w3A==", "requires": { - "@browser-bunyan/levels": "^1.6.0" + "@browser-bunyan/levels": "^1.8.0" } }, "@browser-bunyan/console-raw-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@browser-bunyan/console-raw-stream/-/console-raw-stream-1.6.0.tgz", - "integrity": "sha512-OqPe4uy/rGOL8ZRiq3iwGM/YIGWKd2ne+8cxWSsMbcLL5hr66IOhzr3nwhyRsSo58JbWDC3K/IaJDyoOTcwrdA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@browser-bunyan/console-raw-stream/-/console-raw-stream-1.8.0.tgz", + "integrity": "sha512-6M/xEiNckbFslQMaS1BHAxvuvN1Wtbh/aq4UzQD3fjEPFCxtubvf4KyzwPxUXA5CXq7leVZ+cibEUCRBsm5bzg==", "requires": { - "@browser-bunyan/levels": "^1.6.0" + "@browser-bunyan/levels": "^1.8.0" } }, "@browser-bunyan/levels": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@browser-bunyan/levels/-/levels-1.6.0.tgz", - "integrity": "sha512-wte6nXXZH62Y/RGysYRlOkKxuJn+4S8xEamMF0fDncxxy0SriCHYwGPyWGF0FWYWmRzbZuEkp7dNebBf9Xfeeg==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@browser-bunyan/levels/-/levels-1.8.0.tgz", + "integrity": "sha512-f9oSDik8kAl+4rhVyHqIr012P1boHFUKc7D9nzA5+lDsFoP90UQnDwpseqBdF2mTaWYju10E7h+GdH8u+7MHOQ==" }, "@browser-bunyan/server-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@browser-bunyan/server-stream/-/server-stream-1.6.1.tgz", - "integrity": "sha512-dSUpVQ0MXHmQkUJ+4WVmXZmH0tjLQKokEazrvNyrgw2Dk2oCzYMC60ztHmVIPwRff8jiZrA3nS9DkxBjVFzpHA==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@browser-bunyan/server-stream/-/server-stream-1.8.0.tgz", + "integrity": "sha512-Jccy9FuJbk/LW52M0SEEzHS5WbFpcP1XgsSzAvGbgSJDNw9S+6vLbVLJi/o/yABuhj6fWzLmACbvin1YJk4XJQ==" + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" }, "@dabh/diagnostics": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", - "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", "requires": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -385,15 +390,15 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, "@eslint/eslintrc": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", - "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^12.1.0", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", @@ -402,23 +407,14 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" } }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -464,6 +460,40 @@ "resolved": "https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-2.3.0.tgz", "integrity": "sha512-KWk80UPIzPmUg+P0rKh6TqspRw0G6eux1PuJr+zz47ftMaZ9QDwbGzHZbtzWkl5hgayM/qrKRutllRC7D/vVXQ==" }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@icons/material": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", @@ -485,15 +515,15 @@ } }, "@material-ui/core": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", - "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.11.4", - "@material-ui/system": "^4.12.1", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "@types/react-transition-group": "^4.2.0", "clsx": "^1.0.4", "hoist-non-react-statics": "^3.3.2", @@ -531,14 +561,14 @@ } }, "@material-ui/styles": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", - "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", "requires": { "@babel/runtime": "^7.4.4", "@emotion/hash": "^0.8.0", "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "clsx": "^1.0.4", "csstype": "^2.5.2", "hoist-non-react-statics": "^3.3.2", @@ -554,27 +584,27 @@ }, "dependencies": { "csstype": { - "version": "2.6.17", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz", - "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==" + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" } } }, "@material-ui/system": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", - "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "csstype": "^2.5.2", "prop-types": "^15.7.2" }, "dependencies": { "csstype": { - "version": "2.6.17", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz", - "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==" + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" } } }, @@ -584,9 +614,9 @@ "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" }, "@material-ui/utils": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", - "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", "requires": { "@babel/runtime": "^7.4.4", "prop-types": "^15.7.2", @@ -635,9 +665,9 @@ } }, "@types/react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-KibDWL6nshuOJ0fu8ll7QnV/LVTo3PzQ9aCPnRUYPfX7eZohHwLIdNHj7pftanREzHNP4/nJa8oeM73uSiavMQ==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", "requires": { "@types/react": "*" } @@ -654,9 +684,9 @@ "dev": true }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, "aggregate-error": { @@ -768,33 +798,22 @@ } }, "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - } - }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "is-string": "^1.0.7" }, "dependencies": { "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -803,15 +822,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -819,12 +838,109 @@ "unbox-primitive": "^1.0.1" } }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } + } + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -853,15 +969,88 @@ } }, "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } } }, "asn1": { @@ -896,9 +1085,9 @@ "dev": true }, "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "asynckit": { "version": "0.4.0", @@ -914,16 +1103,23 @@ } }, "autoprefixer": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.6.tgz", - "integrity": "sha512-8lChSmdU6dCNMCQopIf4Pe5kipkAGj/fvTMslCsih0uHpOrXOPUEVOmYMMqmw3cekQkSD7EhIeuYl5y0BLdKqg==", + "version": "10.4.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz", + "integrity": "sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==", "requires": { - "browserslist": "^4.16.6", - "caniuse-lite": "^1.0.30001230", - "colorette": "^1.2.2", - "fraction.js": "^4.1.1", + "browserslist": "^4.20.2", + "caniuse-lite": "^1.0.30001317", + "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", - "postcss-value-parser": "^4.1.0" + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + } } }, "autosize": { @@ -942,9 +1138,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axe-core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.1.tgz", - "integrity": "sha512-evY7DN8qSIbsW2H/TWQ1bX3sXN1d4MNb5Vb4n7BzPuCwRHdkZ1H2eNLuSh73EoQqkGKUtju2G2HCcjCfhvZIAA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true }, "axios": { @@ -1045,14 +1241,14 @@ } }, "browser-bunyan": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/browser-bunyan/-/browser-bunyan-1.6.3.tgz", - "integrity": "sha512-HRg+acpwO3dsY2RWgtjw2wPVHV+uzbCrdhUxD25+qo5NFSTpbfJekrRP0yFNypAhG5LwXFV1Dc5FIc8cxwU5rQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/browser-bunyan/-/browser-bunyan-1.8.0.tgz", + "integrity": "sha512-Et1TaRUm8m2oy4OTi69g0qAM8wqpofACUgkdBnj1Kq2aC8Wpl8w+lNevebPG6zKH2w0Aq+BHiAXWwjm0/QbkaQ==", "requires": { - "@browser-bunyan/console-formatted-stream": "^1.6.2", - "@browser-bunyan/console-plain-stream": "^1.6.0", - "@browser-bunyan/console-raw-stream": "^1.6.0", - "@browser-bunyan/levels": "^1.6.0" + "@browser-bunyan/console-formatted-stream": "^1.8.0", + "@browser-bunyan/console-plain-stream": "^1.8.0", + "@browser-bunyan/console-raw-stream": "^1.8.0", + "@browser-bunyan/levels": "^1.8.0" } }, "browser-or-node": { @@ -1061,15 +1257,15 @@ "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==" }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" } }, "call-bind": { @@ -1120,9 +1316,9 @@ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, "caniuse-lite": { - "version": "1.0.30001301", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz", - "integrity": "sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==" + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==" }, "caseless": { "version": "0.12.0", @@ -1143,6 +1339,16 @@ "type-detect": "^4.0.5" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -1210,12 +1416,12 @@ "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" }, "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" + "color-convert": "^1.9.3", + "color-string": "^1.6.0" } }, "color-convert": { @@ -1232,30 +1438,20 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", "requires": { - "color": "3.0.x", + "color": "^3.1.3", "text-hex": "1.0.x" } }, @@ -1296,9 +1492,9 @@ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" }, "core-js-pure": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.13.1.tgz", - "integrity": "sha512-wVlh0IAi2t1iOEh16y4u1TRk6ubd4KvLE8dlMi+3QUI6SfKphQUh7tAwihGGSQ8affxEXpVIPpOdf9kjR4v4Pw==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.2.tgz", + "integrity": "sha512-Lb+/XT4WC4PaCWWtZpNPaXmjiNDUe5CJuUtbkMrIM1kb1T/jJoAIp+bkVP/r5lHzMr+ZAAF8XHp7+my6Ol0ysQ==", "dev": true }, "core-util-is": { @@ -1403,9 +1599,9 @@ "integrity": "sha1-mYB4Ob5i7bRGtkWDLg2A6tb6GIg=" }, "damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, "dashdash": { @@ -1434,9 +1630,9 @@ } }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "deepmerge": { @@ -1533,9 +1729,9 @@ } }, "electron-to-chromium": { - "version": "1.3.743", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.743.tgz", - "integrity": "sha512-K2wXfo9iZQzNJNx67+Pld0DRF+9bYinj62gXCdgPhcu1vidwVuLPHQPPFnCdO55njWigXXpfBiT90jGUPbw8Zg==" + "version": "1.4.117", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.117.tgz", + "integrity": "sha512-ypZHxY+Sf/PXu7LVN+xoeanyisnJeSOy8Ki439L/oLueZb4c72FI45zXcK3gPpmTwyufh9m6NnbMLXnJh/0Fxg==" }, "emoji-regex": { "version": "8.0.0", @@ -1604,6 +1800,15 @@ "unbox-primitive": "^1.0.1" } }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -1626,13 +1831,14 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.27.0.tgz", - "integrity": "sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==", + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.1", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1649,7 +1855,7 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", + "glob-parent": "^5.1.2", "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", @@ -1672,50 +1878,10 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -1727,12 +1893,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1740,31 +1900,13 @@ "dev": true }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -1845,9 +1987,9 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -1855,29 +1997,106 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" + "esutils": "^2.0.2" } }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", + "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.16.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.4", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.3.5", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.7", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.2.1", + "language-tags": "^1.0.5", + "minimatch": "^3.0.4" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + } + } + }, + "eslint-plugin-react": { + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz", + "integrity": "sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "dependencies": { "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -1888,9 +2107,9 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -1899,15 +2118,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -1915,29 +2134,29 @@ "unbox-primitive": "^1.0.1" } }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true }, "is-regex": { "version": "1.1.4", @@ -1958,80 +2177,31 @@ "has-tostringtag": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true }, - "object.values": { + "object.entries": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1" } - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", - "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "aria-query": "^4.2.2", - "array-includes": "^3.1.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.0.2", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.6", - "emoji-regex": "^9.0.0", - "has": "^1.0.3", - "jsx-ast-utils": "^3.1.0", - "language-tags": "^1.0.5" - }, - "dependencies": { - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - } - } - }, - "eslint-plugin-react": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", - "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", - "dev": true, - "requires": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.values": "^1.1.4", - "prop-types": "^15.7.2", - "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.5" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } }, "resolve": { "version": "2.0.0-next.3", @@ -2042,13 +2212,19 @@ "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, "eslint-plugin-react-hooks": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", - "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.4.0.tgz", + "integrity": "sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ==", "dev": true }, "eslint-scope": { @@ -2119,9 +2295,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -2136,9 +2312,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -2257,11 +2433,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, "fastdom": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.10.tgz", @@ -2271,9 +2442,9 @@ } }, "fecha": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", - "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "fibers": { "version": "4.0.3", @@ -2365,9 +2536,9 @@ } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "fn.name": { @@ -2396,9 +2567,9 @@ } }, "fraction.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz", - "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" }, "fs.realpath": { "version": "1.0.0", @@ -2418,6 +2589,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", @@ -2492,9 +2669,9 @@ } }, "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -2854,9 +3031,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -2913,10 +3090,13 @@ "dev": true }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } }, "is-stream": { "version": "2.0.0", @@ -2952,11 +3132,6 @@ "call-bind": "^1.0.2" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3047,9 +3222,9 @@ } }, "jss": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.7.1.tgz", - "integrity": "sha512-5QN8JSVZR6cxpZNeGfzIjqPEP+ZJwJJfZbXmeABNdxiExyO+eJJDy6WDtqTf8SDKnbL5kZllEpAP71E/Lt7PXg==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.9.0.tgz", + "integrity": "sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==", "requires": { "@babel/runtime": "^7.3.1", "csstype": "^3.0.2", @@ -3058,79 +3233,79 @@ } }, "jss-plugin-camel-case": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.7.1.tgz", - "integrity": "sha512-+ioIyWvmAfgDCWXsQcW1NMnLBvRinOVFkSYJUgewQ6TynOcSj5F1bSU23B7z0p1iqK0PPHIU62xY1iNJD33WGA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.9.0.tgz", + "integrity": "sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==", "requires": { "@babel/runtime": "^7.3.1", "hyphenate-style-name": "^1.0.3", - "jss": "10.7.1" + "jss": "10.9.0" } }, "jss-plugin-default-unit": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.7.1.tgz", - "integrity": "sha512-tW+dfYVNARBQb/ONzBwd8uyImigyzMiAEDai+AbH5rcHg5h3TtqhAkxx06iuZiT/dZUiFdSKlbe3q9jZGAPIwA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.9.0.tgz", + "integrity": "sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.7.1" + "jss": "10.9.0" } }, "jss-plugin-global": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.7.1.tgz", - "integrity": "sha512-FbxCnu44IkK/bw8X3CwZKmcAnJqjAb9LujlAc/aP0bMSdVa3/MugKQRyeQSu00uGL44feJJDoeXXiHOakBr/Zw==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.9.0.tgz", + "integrity": "sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.7.1" + "jss": "10.9.0" } }, "jss-plugin-nested": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.7.1.tgz", - "integrity": "sha512-RNbICk7FlYKaJyv9tkMl7s6FFfeLA3ubNIFKvPqaWtADK0KUaPsPXVYBkAu4x1ItgsWx67xvReMrkcKA0jSXfA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.9.0.tgz", + "integrity": "sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.7.1", + "jss": "10.9.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-props-sort": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.7.1.tgz", - "integrity": "sha512-eyd5FhA+J0QrpqXxO7YNF/HMSXXl4pB0EmUdY4vSJI4QG22F59vQ6AHtP6fSwhmBdQ98Qd9gjfO+RMxcE39P1A==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.9.0.tgz", + "integrity": "sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.7.1" + "jss": "10.9.0" } }, "jss-plugin-rule-value-function": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.7.1.tgz", - "integrity": "sha512-fGAAImlbaHD3fXAHI3ooX6aRESOl5iBt3LjpVjxs9II5u9tzam7pqFUmgTcrip9VpRqYHn8J3gA7kCtm8xKwHg==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.9.0.tgz", + "integrity": "sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.7.1", + "jss": "10.9.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-vendor-prefixer": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.7.1.tgz", - "integrity": "sha512-1UHFmBn7hZNsHXTkLLOL8abRl8vi+D1EVzWD4WmLFj55vawHZfnH1oEz6TUf5Y61XHv0smdHabdXds6BgOXe3A==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.9.0.tgz", + "integrity": "sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==", "requires": { "@babel/runtime": "^7.3.1", "css-vendor": "^2.0.8", - "jss": "10.7.1" + "jss": "10.9.0" } }, "jsx-ast-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", - "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.2.tgz", + "integrity": "sha512-HDAyJ4MNQBboGpUnHAVUNJs6X0lh058s6FuixsFGP7MgJYpD6Vasd6nzSG5iIfXu1zAYlHJ/zsOKNlrenTUBnw==", "dev": true, "requires": { - "array-includes": "^3.1.2", + "array-includes": "^3.1.4", "object.assign": "^4.1.2" } }, @@ -3350,12 +3525,6 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3394,14 +3563,14 @@ } }, "logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.0.tgz", + "integrity": "sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "@colors/colors": "1.5.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" }, "dependencies": { @@ -3454,34 +3623,34 @@ "dev": true }, "meteor-node-stubs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.0.3.tgz", - "integrity": "sha512-JQwIWPfM/Oa2x1Ycwn1Q0wVVQ8b0bOLv+qs4RR/D12b5dPktLlPCRhMzWzRPncZVJtfsnKKBgPLdFmJYUqAwHg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.1.tgz", + "integrity": "sha512-7nn69joWB8Sd8T9i5+nWGJ9wWEdR5JtsweoHsbrjdnvNQiD9/qNJU7ld7m2yAUDkPp7NIJhfNTKq1lnS4vnOEg==", "requires": { - "assert": "^1.4.1", + "assert": "^2.0.0", "browserify-zlib": "^0.2.0", - "buffer": "^5.2.1", - "console-browserify": "^1.1.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", - "domain-browser": "^1.2.0", + "domain-browser": "^4.19.0", "elliptic": "^6.5.4", - "events": "^3.0.0", + "events": "^3.3.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.0", "process": "^0.11.10", "punycode": "^2.1.1", "querystring-es3": "^0.2.1", - "readable-stream": "^3.3.0", - "stream-browserify": "^2.0.2", - "stream-http": "^3.0.0", - "string_decoder": "^1.2.0", - "timers-browserify": "^2.0.10", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", "tty-browserify": "0.0.1", "url": "^0.11.0", - "util": "^0.11.1", - "vm-browserify": "^1.1.0" + "util": "^0.12.4", + "vm-browserify": "^1.1.2" }, "dependencies": { "asn1.js": { @@ -3501,22 +3670,19 @@ } }, "assert": { - "version": "1.5.0", + "version": "2.0.0", "bundled": true, "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "util": { - "version": "0.10.3", - "bundled": true, - "requires": { - "inherits": "2.0.1" - } - } + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" } }, + "available-typed-arrays": { + "version": "1.0.4", + "bundled": true + }, "base64-js": { "version": "1.5.1", "bundled": true @@ -3581,12 +3747,6 @@ "parse-asn1": "^5.1.5", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } } }, "browserify-zlib": { @@ -3597,11 +3757,11 @@ } }, "buffer": { - "version": "5.7.1", + "version": "6.0.3", "bundled": true, "requires": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "buffer-xor": { @@ -3612,6 +3772,14 @@ "version": "3.0.0", "bundled": true }, + "call-bind": { + "version": "1.0.2", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "cipher-base": { "version": "1.0.4", "bundled": true, @@ -3628,10 +3796,6 @@ "version": "1.0.0", "bundled": true }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, "create-ecdh": { "version": "4.0.4", "bundled": true, @@ -3686,6 +3850,13 @@ "randomfill": "^1.0.3" } }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "des.js": { "version": "1.0.1", "bundled": true, @@ -3710,7 +3881,7 @@ } }, "domain-browser": { - "version": "1.2.0", + "version": "4.19.0", "bundled": true }, "elliptic": { @@ -3729,13 +3900,44 @@ "bn.js": { "version": "4.12.0", "bundled": true - }, - "inherits": { - "version": "2.0.4", - "bundled": true } } }, + "es-abstract": { + "version": "1.18.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "bundled": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "bundled": true + }, "events": { "version": "3.3.0", "bundled": true @@ -3748,6 +3950,38 @@ "safe-buffer": "^5.1.1" } }, + "foreach": { + "version": "2.0.5", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "get-intrinsic": { + "version": "1.1.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "bundled": true + }, + "has-symbols": { + "version": "1.0.2", + "bundled": true + }, "hash-base": { "version": "3.1.0", "bundled": true, @@ -3755,12 +3989,6 @@ "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } } }, "hash.js": { @@ -3769,12 +3997,6 @@ "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } } }, "hmac-drbg": { @@ -3795,13 +4017,85 @@ "bundled": true }, "inherits": { + "version": "2.0.4", + "bundled": true + }, + "is-arguments": { + "version": "1.1.0", + "bundled": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.2", + "bundled": true + }, + "is-boolean-object": { + "version": "1.1.1", + "bundled": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "bundled": true + }, + "is-date-object": { + "version": "1.0.4", + "bundled": true + }, + "is-generator-function": { + "version": "1.0.9", + "bundled": true + }, + "is-nan": { + "version": "1.3.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { "version": "2.0.1", "bundled": true }, - "isarray": { - "version": "1.0.0", + "is-number-object": { + "version": "1.0.5", "bundled": true }, + "is-regex": { + "version": "1.1.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "bundled": true + }, + "is-symbol": { + "version": "1.0.4", + "bundled": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.5", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, "md5.js": { "version": "1.3.5", "bundled": true, @@ -3833,10 +4127,32 @@ "version": "1.0.1", "bundled": true }, - "object-assign": { - "version": "4.1.1", + "object-inspect": { + "version": "1.10.3", "bundled": true }, + "object-is": { + "version": "1.1.5", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "bundled": true + }, + "object.assign": { + "version": "4.1.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, "os-browserify": { "version": "0.3.0", "bundled": true @@ -3861,7 +4177,7 @@ "bundled": true }, "pbkdf2": { - "version": "3.1.1", + "version": "3.1.2", "bundled": true, "requires": { "create-hash": "^1.1.2", @@ -3875,10 +4191,6 @@ "version": "0.11.10", "bundled": true }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true - }, "public-encrypt": { "version": "4.0.3", "bundled": true, @@ -3931,12 +4243,6 @@ "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } } }, "ripemd160": { @@ -3968,59 +4274,37 @@ } }, "stream-browserify": { - "version": "2.0.2", + "version": "3.0.0", "bundled": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, "stream-http": { - "version": "3.1.1", + "version": "3.2.0", "bundled": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.4", "readable-stream": "^3.6.0", "xtend": "^4.0.2" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "bundled": true - } + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "string_decoder": { @@ -4041,6 +4325,16 @@ "version": "0.0.1", "bundled": true }, + "unbox-primitive": { + "version": "1.0.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "url": { "version": "0.11.0", "bundled": true, @@ -4056,16 +4350,15 @@ } }, "util": { - "version": "0.11.1", + "version": "0.12.4", "bundled": true, "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "bundled": true - } + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" } }, "util-deprecate": { @@ -4076,6 +4369,30 @@ "version": "1.1.2", "bundled": true }, + "which-boxed-primitive": { + "version": "1.0.2", + "bundled": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.4", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, "xtend": { "version": "4.0.2", "bundled": true @@ -4132,9 +4449,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==" }, "natural-compare": { "version": "1.4.0", @@ -4154,9 +4471,9 @@ "dev": true }, "node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==" }, "normalize-package-data": { "version": "2.5.0", @@ -4244,26 +4561,254 @@ } }, "object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } } }, "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } } }, "once": { @@ -4306,11 +4851,6 @@ "word-wrap": "^1.2.3" } }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -4417,6 +4957,11 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -4438,13 +4983,13 @@ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" }, "postcss": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz", - "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==", + "version": "8.4.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", + "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "requires": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" + "nanoid": "^3.3.1", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" } }, "postcss-modules-extract-imports": { @@ -4483,11 +5028,11 @@ } }, "postcss-nested": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.5.tgz", - "integrity": "sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", "requires": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^6.0.6" } }, "postcss-selector-parser": { @@ -4523,11 +5068,6 @@ "stream-parser": "~0.3.1" } }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -4543,20 +5083,15 @@ } }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -4720,9 +5255,9 @@ } }, "react-player": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.9.0.tgz", - "integrity": "sha512-jNUkTfMmUhwPPAktAdIqiBcVUKsFKrVGH6Ocutj6535CNfM91yrvWxHg6fvIX8Y/fjYUPoejddwh7qboNV9vGA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.10.0.tgz", + "integrity": "sha512-PccIqea9nxSHAdai6R+Yj9lp6tb2lyXWbaF6YVHi5uO4FiXYMKKr9rMXJrivwV5vXwQa65rYKBmwebsBmRTT3w==", "requires": { "deepmerge": "^4.0.0", "load-script": "^1.0.0", @@ -4821,20 +5356,6 @@ "lodash": "^4.0.1" } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "reconnecting-websocket": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", @@ -4870,24 +5391,25 @@ } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "request": { @@ -4984,6 +5506,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5153,9 +5680,9 @@ } }, "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, "spdx-correct": { "version": "3.1.1", @@ -5252,19 +5779,92 @@ } }, "string.prototype.matchall": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", - "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", + "regexp.prototype.flags": "^1.4.1", "side-channel": "^1.0.4" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + } } }, "string.prototype.trimend": { @@ -5366,24 +5966,46 @@ } } }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + } + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "requires": { "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { "ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -5392,49 +6014,11 @@ "uri-js": "^4.2.2" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } } } }, @@ -5486,14 +6070,6 @@ "popper.js": "^1.16.0" } }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -5568,12 +6144,6 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -5599,31 +6169,6 @@ "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.3.7.tgz", "integrity": "sha512-O94hcN9UDAPTC4Fsm3p6Og5PVlhTEeKqxJX3HuBbVSuevOSPLDZxowFUmx49/fnu9jpgY83Nd3TALJVDRtYzdQ==" }, - "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", - "requires": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5669,9 +6214,9 @@ } }, "wasm-check": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/wasm-check/-/wasm-check-2.0.2.tgz", - "integrity": "sha512-5mlFaQVLJDXVvea9RzD/tVs1NWJso+YTLn6D51BaFtEablRnO/PnRBFmjIHqC6xLyojG5Gwp/7LbcWZKR3+2vQ==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/wasm-check/-/wasm-check-2.0.3.tgz", + "integrity": "sha512-UbZqpDMO4TZskoVKDH3B9NqY+yJllDJX8I9lUU4nuQjBGeU57jCjjgCslP3r8xiE+yf5GTIfeGvznvubgCdbhw==" }, "which": { "version": "2.0.2", @@ -5701,19 +6246,20 @@ "integrity": "sha512-UMmSUoIQSir+XbBpTxOTS53uJ8s/lVhADCkEbhfRjUGFDPme/XGOb0sBWLx5sTz7Wx/2+TlAw1eK9O5lw5PiEw==" }, "winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz", + "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==", "requires": { "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.4.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.5.0" }, "dependencies": { "readable-stream": { @@ -5729,12 +6275,25 @@ } }, "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "requires": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.2.0" + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "word-wrap": { diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json index aea6c14c20..fd8af9f9e2 100755 --- a/bigbluebutton-html5/package.json +++ b/bigbluebutton-html5/package.json @@ -28,16 +28,16 @@ ] }, "dependencies": { - "@babel/runtime": "^7.13.10", - "@browser-bunyan/server-stream": "^1.6.1", + "@babel/runtime": "^7.17.9", + "@browser-bunyan/server-stream": "^1.8.0", "@jitsi/sdp-interop": "0.1.14", - "@material-ui/core": "^4.11.4", - "autoprefixer": "^10.2.5", + "@material-ui/core": "^4.12.4", + "autoprefixer": "^10.4.4", "axios": "^0.21.3", "babel-runtime": "~6.26.0", "bbb-diff": "^1.1.0", "bowser": "^2.11.0", - "browser-bunyan": "^1.6.3", + "browser-bunyan": "^1.8.0", "classnames": "^2.2.6", "eventemitter2": "~5.0.1", "fastdom": "^1.0.10", @@ -49,11 +49,11 @@ "langmap": "0.0.16", "lodash": "^4.17.21", "makeup-screenreader-trap": "0.0.5", - "meteor-node-stubs": "^1.0.3", - "postcss-nested": "^5.0.5", + "meteor-node-stubs": "^1.2.1", + "postcss-nested": "^5.0.6", "probe-image-size": "^4.1.1", "prom-client": "^13.2.0", - "prop-types": "^15.7.2", + "prop-types": "^15.8.1", "queue": "^6.0.2", "re-resizable": "^4.11.0", "react": "^16.14.0", @@ -65,7 +65,7 @@ "react-intl": "^3.12.1", "react-loading-skeleton": "^3.0.3", "react-modal": "~3.6.1", - "react-player": "^2.9.0", + "react-player": "^2.10.0", "react-render-in-browser": "^1.1.1", "react-tabs": "^2.3.1", "react-tether": "^2.0.7", @@ -82,23 +82,22 @@ "styled-components": "^5.3.3", "tippy.js": "^5.1.3", "use-context-selector": "^1.3.7", - "useragent": "^2.3.0", - "wasm-check": "^2.0.2", - "winston": "^3.3.3", + "wasm-check": "^2.0.3", + "winston": "^3.7.2", "yaml": "^1.7.2" }, "devDependencies": { "chai": "~4.2.0", - "eslint": "^7.23.0", + "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-airbnb-base": "^14.2.1", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.23.2", - "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.29.4", + "eslint-plugin-react-hooks": "^4.4.0", "husky": "^1.3.1", "lint-staged": "11.2.0", - "postcss": "^8.2.15", + "postcss": "^8.4.12", "postcss-modules-extract-imports": "^3.0.0", "postcss-modules-local-by-default": "^4.0.0", "postcss-modules-scope": "^3.0.0", diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml index fda73e7e3c..0fa8c9c6cc 100755 --- a/bigbluebutton-html5/private/config/settings.yml +++ b/bigbluebutton-html5/private/config/settings.yml @@ -212,9 +212,9 @@ public: wsConnectionTimeout: 4000 # Time in milis to wait for the browser to return a gUM call (used in video-preview) gUMTimeout: 20000 - # Experiment(al). Controls whether ICE candidates should be signaled. - # Applies to webcams, listen only and screen sharing. True is "stable behavior". - signalCandidates: true + # Controls whether ICE candidates should be signaled to bbb-webrtc-sfu. + # Enable this if you want to use Kurento as the media server. + signalCandidates: false # Forces relay usage only on Firefox. Applies to listen only, webcams and screenshare. forceRelayOnFirefox: false cameraTimeouts: @@ -276,38 +276,26 @@ public: name: low-u30 bitrate: 30 hidden: true - constraints: - frameRate: 3 - id: low-u25 name: low-u25 bitrate: 40 hidden: true - constraints: - frameRate: 3 - id: low-u20 name: low-u20 bitrate: 50 hidden: true - constraints: - frameRate: 5 - id: low-u15 name: low-u15 bitrate: 70 hidden: true - constraints: - frameRate: 8 - id: low-u12 name: low-u12 bitrate: 90 hidden: true - constraints: - frameRate: 10 - id: low-u8 name: low-u8 bitrate: 100 hidden: true - constraints: - frameRate: 10 - id: low name: Low default: false @@ -364,6 +352,12 @@ public: # that will be applied to all cameras when threshold is hit cameraQualityThresholds: enabled: true + # applyConstraints: whether profile constraints should be applied on profile changes + applyConstraints: false + # privilegedStreams: whether cameras should revert to their original profile on + # certain actions (eg floor changes, pin) + privilegedStreams: true + debounceTime: 2500 thresholds: - threshold: 8 profile: low-u8 @@ -833,3 +827,5 @@ private: path: '/metrics' # Whether default metrics for Node.js processes should be exported collectDefaultMetrics: false + # Whether redis metrics should be exported + collectRedisMetrics: false diff --git a/bigbluebutton-html5/public/locales/af.json b/bigbluebutton-html5/public/locales/af.json index 443e082bd6..e4333c2dd9 100644 --- a/bigbluebutton-html5/public/locales/af.json +++ b/bigbluebutton-html5/public/locales/af.json @@ -589,7 +589,6 @@ "app.lock-viewers.button.apply": "Pas toe", "app.lock-viewers.button.cancel": "Kanselleer", "app.lock-viewers.locked": "Gesluit", - "app.lock-viewers.unlocked": "Ontsluit", "app.guest-policy.ariaTitle": "Gasbeleid instellings modaal", "app.guest-policy.title": "Gasbeleid", "app.guest-policy.description": "Verander vergadering gasbeleid instellings", diff --git a/bigbluebutton-html5/public/locales/ar.json b/bigbluebutton-html5/public/locales/ar.json index d7d86fb945..c11cd48a58 100644 --- a/bigbluebutton-html5/public/locales/ar.json +++ b/bigbluebutton-html5/public/locales/ar.json @@ -132,6 +132,8 @@ "app.userList.userOptions.savedNames.title": "قائمة المستخدمين في الاجتماع {0} في {1}", "app.userList.userOptions.sortedFirstName.heading": "مرتبة حسب الاسم الأول:", "app.userList.userOptions.sortedLastName.heading": "مرتبة حسب الاسم الأخير:", + "app.userList.userOptions.hideViewersCursor": "مؤشرات المشاهد مقفلة", + "app.userList.userOptions.showViewersCursor": "مؤشرات المشاهد متاحة", "app.media.label": "الوسائط", "app.media.autoplayAlertDesc": "تمكين إستخدام", "app.media.screenshare.start": "بدأت مشاركة الشاشة", @@ -169,7 +171,7 @@ "app.presentation.changedSlideContent": "تغيير العرض إلى الشريحة: {0}", "app.presentation.emptySlideContent": "لا يوجد محتوى للشريحة الحالية", "app.presentation.options.fullscreen": "ملء الشاشة", - "app.presentation.options.exitFullscreen": "الخروج من وضع ملئ للشاشة", + "app.presentation.options.exitFullscreen": "الخروج من شاشة كاملة", "app.presentation.options.minimize": "تصغير", "app.presentation.options.snapshot": "لقطة من العرض الحالي", "app.presentation.options.downloading": "جارى التحميل...", @@ -327,16 +329,16 @@ "app.muteWarning.disableMessage": "كتم التنبيهات معطلة حتى إعادة الصوت", "app.muteWarning.tooltip": "انقر لإغلاق وتعطيل التحذير حتى إلغاء كتم الصوت التالي", "app.navBar.settingsDropdown.optionsLabel": "خيارات", - "app.navBar.settingsDropdown.fullscreenLabel": "جعل الشاشة الكاملة", + "app.navBar.settingsDropdown.fullscreenLabel": "جعل شاشة كاملة", "app.navBar.settingsDropdown.settingsLabel": "الإعدادات", "app.navBar.settingsDropdown.aboutLabel": "حول", "app.navBar.settingsDropdown.leaveSessionLabel": "اترك الاجتماع", - "app.navBar.settingsDropdown.exitFullscreenLabel": "الخروج من الشاشة الكاملة", - "app.navBar.settingsDropdown.fullscreenDesc": "جعل قائمة الاعدادات على الشاشة الكاملة", + "app.navBar.settingsDropdown.exitFullscreenLabel": "الخروج من شاشة كاملة", + "app.navBar.settingsDropdown.fullscreenDesc": "جعل قائمة الإعدادات على شاشة كاملة", "app.navBar.settingsDropdown.settingsDesc": "تغيير الإعدادات العامة", "app.navBar.settingsDropdown.aboutDesc": "مزيد من المعلومات عن التطبيق", "app.navBar.settingsDropdown.leaveSessionDesc": "مغادرة الإجتماع", - "app.navBar.settingsDropdown.exitFullscreenDesc": "الخروج من الشاشة الكاملة", + "app.navBar.settingsDropdown.exitFullscreenDesc": "الخروج من شاشة كاملة", "app.navBar.settingsDropdown.hotkeysLabel": "اختصارات لوحة المفاتيح", "app.navBar.settingsDropdown.hotkeysDesc": "قائمة اختصارات لوحة المفاتيح المتاحة", "app.navBar.settingsDropdown.helpLabel": "مساعدة", @@ -562,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "يرجى ملاحظة أنه سيظهر نافذة حوار في متصفحك ، مما يتطلب منك قبول مشاركة الميكروفون", "app.audio.audioSettings.microphoneSourceLabel": "مصدر الميكروفون", "app.audio.audioSettings.speakerSourceLabel": "مصدر مكبر الصوت", + "app.audio.audioSettings.testSpeakerLabel": "اختبر سمّاعتك", "app.audio.audioSettings.microphoneStreamLabel": "مستوى صوتك المتدفق ", "app.audio.audioSettings.retryLabel": "المحاولة مرة أخرى", "app.audio.listenOnly.backLabel": "الى الخلف", @@ -677,9 +680,13 @@ "app.shortcut-help.openDebugWindow": "افتح نافذة التصحيح", "app.shortcut-help.openStatus": "فتح قائمة الحالات", "app.shortcut-help.togglePan": "تشغيل لوحة الأدوات (مقدم)", - "app.shortcut-help.toggleFullscreen": "تبديل مِلء الشاشة (مقدم)", + "app.shortcut-help.toggleFullscreen": "تبديل الشاشة الكاملة (مقدم)", "app.shortcut-help.nextSlideDesc": "الشريحة التالية (مقدم)", "app.shortcut-help.previousSlideDesc": "الشريحة السابقة (مقدم)", + "app.shortcut-help.togglePanKey": "مفتاح المسافة", + "app.shortcut-help.toggleFullscreenKey": "مفتاح ألإدخال", + "app.shortcut-help.nextSlideKey": "مفتاح السهم الأيمن", + "app.shortcut-help.previousSlideKey": "مفتاح السهم الأيسر", "app.lock-viewers.title": "قفل المشاهدين", "app.lock-viewers.description": "تمكنك هذه الخيارات من تقييد المشاهدين من استخدام ميزات محددة.", "app.lock-viewers.featuresLable": "ميزة", @@ -695,7 +702,7 @@ "app.lock-viewers.button.apply": "تطبيق", "app.lock-viewers.button.cancel": "إلغاء", "app.lock-viewers.locked": "مقفل", - "app.lock-viewers.unlocked": "مفتوح", + "app.lock-viewers.hideViewersCursor": "رؤية مؤشرات المشاهدين الآخرين", "app.guest-policy.ariaTitle": "نهج إعدادات سياسة الضيف", "app.guest-policy.title": "سياسة الضيف", "app.guest-policy.description": "تغيير إعداد سياسة ضيف الاجتماع", @@ -801,7 +808,7 @@ "app.video.camCapReached": "لا يمكنك مشاركة المزيد من الكاميرات", "app.video.meetingCamCapReached": "وصل الاجتماع إلى حده من الكاميرات المتزامنة", "app.video.dropZoneLabel": "أفلت هنا", - "app.fullscreenButton.label": "جعل {0} على الشاشة الكاملة", + "app.fullscreenButton.label": "جعل {0} على شاشة كاملة", "app.fullscreenUndoButton.label": "تراجع عن {0} شاشة كاملة", "app.switchButton.expandLabel": "قم بتوسيع مشاركة الشاشة بالفيديو", "app.switchButton.shrinkLabel": "تقليص مشاركة الشاشة الفيديو", @@ -923,6 +930,8 @@ "app.externalVideo.refreshLabel": "تحديث مشغل الفيديو", "app.externalVideo.fullscreenLabel": "مشغل فديو", "app.externalVideo.noteLabel": "ملاحظة: لن تظهر مقاطع الفيديو الخارجية المشتركة في التسجيل. يتم دعم رابط ملفات الوسائط مثل YouTube و Vimeo و Instructure Media و Twitch و Dailymotion وملفات الوسائط (مثل https://example.com/xy.mp4).", + "app.externalVideo.subtitlesOn": "أطفئ", + "app.externalVideo.subtitlesOff": "تشغيل (إذا كان متاحًا)", "app.actionsBar.actionsDropdown.shareExternalVideo": "مشاركة فيديو خارجي", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "إيقاف مشاركة الفيديو الخارجي", "app.iOSWarning.label": "يرجى الترقية إلى iOS 12.2 أو اعلى", @@ -947,18 +956,19 @@ "playback.button.about.aria": "حول", "playback.button.clear.aria": "مسح البحث", "playback.button.close.aria": "إغلاق مشروط", - "playback.button.fullscreen.aria": "محتوى ملء الشاشة", + "playback.button.fullscreen.aria": "محتوى الشاشة الكاملة", "playback.button.restore.aria": "استعادة المحتوى", "playback.button.search.aria": "بحث", "playback.button.section.aria": "قسم جانبي", "playback.button.swap.aria": "تبادل المحتوى", + "playback.button.theme.aria": "تبديل منظر الشاشة", "playback.error.wrapper.aria": "مساحة الخطأ", "playback.loader.wrapper.aria": "مساحة المحمّل", "playback.player.wrapper.aria": "مساحة العرض", "playback.player.about.modal.shortcuts.title": "الاختصارات", "playback.player.about.modal.shortcuts.alt": "Alt", "playback.player.about.modal.shortcuts.shift": "Shift", - "playback.player.about.modal.shortcuts.fullscreen": "تبديل ملء الشاشة", + "playback.player.about.modal.shortcuts.fullscreen": "تبديل الشاشة الكاملة", "playback.player.about.modal.shortcuts.play": "تشغيل / وقف", "playback.player.about.modal.shortcuts.section": "تبديل القسم الجانبي", "playback.player.about.modal.shortcuts.seek.backward": "ما قبل", @@ -1035,15 +1045,17 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "صورة مصغرة للعرض", "app.learningDashboard.errors.invalidToken": "رمز جلسة غير صالح", "app.learningDashboard.errors.dataUnavailable": "البيانات لم تعد متوفرة", - "mobileApp.portals.list.empty.label": "الرجاء إضافة بوابات.", - "mobileApp.portals.list.add.button.label": "بوابة جديدة", + "mobileApp.portals.list.empty.addFirstPortal.label": "أضف بوابتك الخاصة باستخدام الزر أعلاه ،", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "أو استخدم خادمنا التجريبي.", + "mobileApp.portals.list.add.button.label": "أضف بوابة", "mobileApp.portals.fields.name.label": "اسم البوابة", "mobileApp.portals.fields.name.placeholder": "BigBlueButton التجريبي", "mobileApp.portals.fields.url.label": "عنوان رابط للخادم", - "mobileApp.portals.addPortalPopup.confirm.button.label": "أضف بوابة", + "mobileApp.portals.addPortalPopup.confirm.button.label": "حفظ", "mobileApp.portals.drawerNavigation.button.label": "البوابات", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "الحقول الفارغة", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "الاسم موجود بالفعل" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "حقول مطلوبة", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "الاسم مستخدم", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "حدث خطأ أثناء محاولة تحميل الصفحة - تحقق من الرابط واتصال الشبكة" } diff --git a/bigbluebutton-html5/public/locales/az.json b/bigbluebutton-html5/public/locales/az.json index 801e00b408..97ecfc56e5 100644 --- a/bigbluebutton-html5/public/locales/az.json +++ b/bigbluebutton-html5/public/locales/az.json @@ -543,7 +543,6 @@ "app.lock-viewers.button.apply": "Tətbiq et", "app.lock-viewers.button.cancel": "Ləğv et", "app.lock-viewers.locked": "Kilidlənib", - "app.lock-viewers.unlocked": "Kiliddən açılıb", "app.connection-status.ariaTitle": "Bağlantı vəziyyəti modaldır", "app.connection-status.title": "Bağlantı vəziyyəti", "app.connection-status.description": "İstifadəçilərin əlaqə vəziyyətinə baxın", diff --git a/bigbluebutton-html5/public/locales/bg_BG.json b/bigbluebutton-html5/public/locales/bg_BG.json index 2035ba4851..6c31ff1680 100644 --- a/bigbluebutton-html5/public/locales/bg_BG.json +++ b/bigbluebutton-html5/public/locales/bg_BG.json @@ -486,7 +486,6 @@ "app.lock-viewers.button.apply": "Приложи", "app.lock-viewers.button.cancel": "Отказ", "app.lock-viewers.locked": "Забранено", - "app.lock-viewers.unlocked": "Разрешено", "app.connection-status.title": "Статус на връзката", "app.connection-status.description": "Статус на връзката на потребителите", "app.connection-status.more": "още", diff --git a/bigbluebutton-html5/public/locales/bn.json b/bigbluebutton-html5/public/locales/bn.json index 3c9f356af4..d19f897fe5 100644 --- a/bigbluebutton-html5/public/locales/bn.json +++ b/bigbluebutton-html5/public/locales/bn.json @@ -616,7 +616,6 @@ "app.lock-viewers.button.apply": "প্রয়োগ করুন", "app.lock-viewers.button.cancel": "ক্যানকেল", "app.lock-viewers.locked": "লকড", - "app.lock-viewers.unlocked": "আনলক করা", "app.guest-policy.ariaTitle": "অতিথি নীতি সেটিংস মডেল", "app.guest-policy.title": "অতিথি নীতি", "app.guest-policy.description": "সভায় অতিথি নীতি সেটিং পরিবর্তন করুন", diff --git a/bigbluebutton-html5/public/locales/ca.json b/bigbluebutton-html5/public/locales/ca.json index 55979a1c8f..0af43545ed 100644 --- a/bigbluebutton-html5/public/locales/ca.json +++ b/bigbluebutton-html5/public/locales/ca.json @@ -695,7 +695,6 @@ "app.lock-viewers.button.apply": "Aplica", "app.lock-viewers.button.cancel": "Cancel·la", "app.lock-viewers.locked": "Bloquejat/da", - "app.lock-viewers.unlocked": "Desbloqueja", "app.guest-policy.ariaTitle": "Modalitat de configuració de la política de convidats", "app.guest-policy.title": "Política de convidats", "app.guest-policy.description": "Canviar la configuració de la política de convidats a les reunions", @@ -1034,15 +1033,10 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Presentació en miniatura.", "app.learningDashboard.errors.invalidToken": "Token de sessió no vàlid", "app.learningDashboard.errors.dataUnavailable": "Les dades ja no estan disponibles", - "mobileApp.portals.list.empty.label": "Si us plau, afegeixi portals.", - "mobileApp.portals.list.add.button.label": "Nou portal", "mobileApp.portals.fields.name.label": "Nom del portal", "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", "mobileApp.portals.fields.url.label": "URL del servidor", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Afegir portal", - "mobileApp.portals.drawerNavigation.button.label": "Portals", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Camps buits", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "El nom ja existeix" + "mobileApp.portals.drawerNavigation.button.label": "Portals" } diff --git a/bigbluebutton-html5/public/locales/cs_CZ.json b/bigbluebutton-html5/public/locales/cs_CZ.json index 6700e418b8..77126e7e72 100644 --- a/bigbluebutton-html5/public/locales/cs_CZ.json +++ b/bigbluebutton-html5/public/locales/cs_CZ.json @@ -651,7 +651,6 @@ "app.lock-viewers.button.apply": "Aplikovat", "app.lock-viewers.button.cancel": "Zrušit", "app.lock-viewers.locked": "Uzamčen", - "app.lock-viewers.unlocked": "Povoleno", "app.guest-policy.ariaTitle": "Panel nastavení Pravidla pro hosty", "app.guest-policy.title": "Pravidla pro hosty", "app.guest-policy.description": "Změnit nastavení pravidel pro hosty", diff --git a/bigbluebutton-html5/public/locales/da.json b/bigbluebutton-html5/public/locales/da.json index 02d3c94413..24231ff0d8 100644 --- a/bigbluebutton-html5/public/locales/da.json +++ b/bigbluebutton-html5/public/locales/da.json @@ -548,7 +548,6 @@ "app.lock-viewers.button.apply": "Anvend", "app.lock-viewers.button.cancel": "Afbestille", "app.lock-viewers.locked": "Låst", - "app.lock-viewers.unlocked": "Oplåst", "app.connection-status.ariaTitle": "Forbindelsesstatus modal", "app.connection-status.title": "Forbindelsesstatus", "app.connection-status.description": "Se brugernes forbindelsesstatus", diff --git a/bigbluebutton-html5/public/locales/de.json b/bigbluebutton-html5/public/locales/de.json index 4726f8032f..bab71d24f6 100644 --- a/bigbluebutton-html5/public/locales/de.json +++ b/bigbluebutton-html5/public/locales/de.json @@ -35,7 +35,7 @@ "app.captions.menu.ariaStartDesc": "Öffnet den Untertiteleditor und schließt diesen Dialog", "app.captions.menu.select": "Verfügbare Sprache auswählen", "app.captions.menu.ariaSelect": "Untertitelsprache", - "app.captions.menu.subtitle": "Bitte wählen Sie eine Sprache und einen Schriftstil für die Untertitel Ihrer Konferenz.", + "app.captions.menu.subtitle": "Bitte eine Sprache und einen Schriftstil für die Untertitel der Konferenz wählen.", "app.captions.menu.title": "Untertitel", "app.captions.menu.fontSize": "Größe", "app.captions.menu.fontColor": "Schriftfarbe", @@ -45,7 +45,7 @@ "app.captions.menu.cancelLabel": "Abbrechen", "app.captions.hide": "Untertitel verbergen", "app.captions.ownership": "Übernehmen", - "app.captions.ownershipTooltip": "Ihnen wird die Kontrolle der {0} Untertitel zugewiesen", + "app.captions.ownershipTooltip": "Verantwortung für die Kontrolle der {0} Untertitel erhalten", "app.captions.dictationStart": "Diktat starten", "app.captions.dictationStop": "Diktat stoppen", "app.captions.dictationOnDesc": "Schaltet die Spracherkennung ein", @@ -59,9 +59,9 @@ "app.notes.label": "Notizen", "app.notes.hide": "Notizen verbergen", "app.notes.locked": "Gesperrt", - "app.pads.hint": "Drücken Sie Esc, um die Symbolleiste des Pads auszuwählen", + "app.pads.hint": "Esc drücken, um die Symbolleiste des Pads auszuwählen", "app.user.activityCheck": "Teilnehmeraktivitätsprüfung", - "app.user.activityCheck.label": "Prüfen, ob der Teilnehmer noch in der Konferenz ist ({0})", + "app.user.activityCheck.label": "Prüfen, ob der:die Teilnehmer:in noch in der Konferenz ist ({0})", "app.user.activityCheck.check": "Prüfen", "app.userList.usersTitle": "Teilnehmer", "app.userList.participantsTitle": "Teilnehmer", @@ -86,11 +86,11 @@ "app.userList.menu.clearStatus.label": "Status zurücksetzen", "app.userList.menu.removeUser.label": "Teilnehmer entfernen", "app.userList.menu.removeConfirmation.label": "Teilnehmer entfernen ({0})", - "app.userlist.menu.removeConfirmation.desc": "Teilnehmer sperren, sodass eine erneute Teilnahme an dieser Konferenz nicht mehr möglich ist.", + "app.userlist.menu.removeConfirmation.desc": "Teilnehmer:in sperren, sodass eine erneute Teilnahme an dieser Konferenz nicht mehr möglich ist.", "app.userList.menu.muteUserAudio.label": "Teilnehmer stummschalten", "app.userList.menu.unmuteUserAudio.label": "Stummschaltung aufheben", - "app.userList.menu.webcamPin.label": "Webcam der Teilnehmer anheften", - "app.userList.menu.webcamUnpin.label": "Webcam der Teilnehmer lösen", + "app.userList.menu.webcamPin.label": "Webcam der Teilnehmer:in fixieren", + "app.userList.menu.webcamUnpin.label": "Webcam der Teilnehmer:in lösen", "app.userList.menu.giveWhiteboardAccess.label" : "Zugriff auf Whiteboard erlauben", "app.userList.menu.removeWhiteboardAccess.label": "Zugriff auf Whiteboard aufheben", "app.userList.menu.ejectUserCameras.label": "Kameras schließen", @@ -103,7 +103,7 @@ "app.userList.menu.makePresenter.label": "Zum Präsentator machen", "app.userList.userOptions.manageUsersLabel": "Teilnehmer verwalten", "app.userList.userOptions.muteAllLabel": "Alle Teilnehmer stummschalten", - "app.userList.userOptions.muteAllDesc": "Alle Teilnehmer der Konferenz werden stumm geschaltet", + "app.userList.userOptions.muteAllDesc": "Alle Teilnehmer:innen der Konferenz werden stumm geschaltet", "app.userList.userOptions.clearAllLabel": "Alle Statusicons löschen", "app.userList.userOptions.clearAllDesc": "Alle Statusicons der Teilnehmer löschen", "app.userList.userOptions.muteAllExceptPresenterLabel": "Alle Teilnehmer außer den Präsentator stummschalten", @@ -111,7 +111,7 @@ "app.userList.userOptions.unmuteAllLabel": "Konferenz-Stummschaltung aufheben", "app.userList.userOptions.unmuteAllDesc": "Hebt die Konferenz-Stummschaltung auf", "app.userList.userOptions.lockViewersLabel": "Teilnehmerrechte einschränken", - "app.userList.userOptions.lockViewersDesc": "Schränkt bestimmte Funktionen der Konferenzteilnehmer ein", + "app.userList.userOptions.lockViewersDesc": "Schränkt bestimmte Funktionen der Konferenzteilnehmer:innen ein", "app.userList.userOptions.guestPolicyLabel": "Gastzugang regeln", "app.userList.userOptions.guestPolicyDesc": "Grundregel für den Gastzugang ändern", "app.userList.userOptions.disableCam": "Teilnehmerwebcams sind deaktiviert", @@ -119,19 +119,21 @@ "app.userList.userOptions.disablePrivChat": "Privater Chat ist deaktiviert", "app.userList.userOptions.disablePubChat": "Öffentlicher Chat ist deaktiviert", "app.userList.userOptions.disableNotes": "Geteilte Notizen sind jetzt gesperrt", - "app.userList.userOptions.hideUserList": "Teilnehmerliste ist jetzt für die Teilnehmer ausgeblendet", + "app.userList.userOptions.hideUserList": "Liste der Teilnehmer:innen ist jetzt für diese ausgeblendet", "app.userList.userOptions.webcamsOnlyForModerator": "Nur Moderatoren können die Teilnehmerwebcams sehen (wegen eingeschränkter Rechteeinstellungen)", - "app.userList.content.participants.options.clearedStatus": "Status aller Teilnehmer zurückgesetzt", + "app.userList.content.participants.options.clearedStatus": "Status aller Teilnehmer:innen zurückgesetzt", "app.userList.userOptions.enableCam": "Teilnehmer dürfen ihre Webcams verwenden", "app.userList.userOptions.enableMic": "Teilnehmer dürfen ihre Mikrofone verwenden", "app.userList.userOptions.enablePrivChat": "Privater Chat ist erlaubt", - "app.userList.userOptions.enablePubChat": "Öffentlicher Chat ist erlaubt", + "app.userList.userOptions.enablePubChat": "Gemeinsamer Chat ist erlaubt", "app.userList.userOptions.enableNotes": "Geteilte Notizen sind jetzt erlaubt", - "app.userList.userOptions.showUserList": "Teilnehmerliste ist jetzt für die Teilnehmer sichtbar", - "app.userList.userOptions.enableOnlyModeratorWebcam": "Sie können Ihre Webcam jetzt freigeben, jeder wird Sie sehen.", + "app.userList.userOptions.showUserList": "Liste der Teilnehmer:innen ist für diese sichtbar", + "app.userList.userOptions.enableOnlyModeratorWebcam": "Webcam nun freigeben um für jede:n sichtbar zu sein.", "app.userList.userOptions.savedNames.title": "Liste der Teilnehmer in der Konferenz {0} vom {1}", "app.userList.userOptions.sortedFirstName.heading": "Sortiert nach Vorname:", "app.userList.userOptions.sortedLastName.heading": "Sortiert nach Nachname:", + "app.userList.userOptions.hideViewersCursor": "Cursor der Teilnehmer:innen sind gesperrt", + "app.userList.userOptions.showViewersCursor": "Cursor der Teilnehmer:innen sind freigegeben", "app.media.label": "Media", "app.media.autoplayAlertDesc": "Zugang erlauben", "app.media.screenshare.start": "Bildschirmfreigabe wurde gestartet", @@ -139,22 +141,22 @@ "app.media.screenshare.endDueToDataSaving": "Bildschirmübertragung im Datensparmodus gestoppt", "app.media.screenshare.unavailable": "Bildschirmfreigabe nicht verfügbar", "app.media.screenshare.notSupported": "Bildschirmfreigabe wird in diesem Browser nicht unterstützt.", - "app.media.screenshare.autoplayBlockedDesc": "Wir benötigen Ihre Zustimmung, um Ihnen den Bildschirm des Präsentators zu zeigen.", + "app.media.screenshare.autoplayBlockedDesc": "Wir benötigen deine/Ihre Zustimmung, um den Bildschirm des Präsentators zu zeigen.", "app.media.screenshare.autoplayAllowLabel": "Geteilten Bildschirm ansehen", "app.screenshare.presenterLoadingLabel": "Ihr Bildschirm wird freigegeben", "app.screenshare.viewerLoadingLabel": "Der Bildschirm des Präsentators wird geladen", "app.screenshare.presenterSharingLabel": "Der Bildschirm wird nun geteilt.", "app.screenshare.screenshareFinalError": "Fehler {0}. Bildschirm konnte nicht geteilt werden.", - "app.screenshare.screenshareRetryError": "Fehler {0}. Versuchen Sie, den Bildschirm erneut zu teilen.", - "app.screenshare.screenshareRetryOtherEnvError": "Fehler {0}. Der Bildschirm konnte nicht freigegeben werden. Versuchen Sie es mit einem anderen Browser oder einem anderen Gerät.", - "app.screenshare.screenshareUnsupportedEnv": "Fehler {0}. Ihr Browser wird nicht unterstützt. Benutzen Sie einen anderen Browser oder ein anderes Endgerät.", + "app.screenshare.screenshareRetryError": "Fehler {0}. Bitte versuchen, den Bildschirm erneut zu teilen.", + "app.screenshare.screenshareRetryOtherEnvError": "Fehler {0}. Der Bildschirm konnte nicht freigegeben werden. Bitte mit einem anderen Browser oder einem anderen Gerät probieren.", + "app.screenshare.screenshareUnsupportedEnv": "Fehler {0}. Dieser Browser wird nicht unterstützt. Bitte einen anderen Browser oder ein anderes Endgerät probieren.", "app.screenshare.screensharePermissionError": "Fehler {0}. Die Berechtigung zur Bildschirmfreigabe muss erteilt werden.", "app.meeting.ended": "Diese Konferenz wurde beendet", "app.meeting.meetingTimeRemaining": "Verbleibende Konferenzzeit: {0}", "app.meeting.meetingTimeHasEnded": "Die Zeit ist abgelaufen. Die Konferenz wird in Kürze beendet", "app.meeting.endedByUserMessage": "Diese Konferenz wurde durch {0} beendet", - "app.meeting.endedByNoModeratorMessageSingular": "Die Konferenz ist beendet, da nach einer Minute kein Moderator anwesend ist", - "app.meeting.endedByNoModeratorMessagePlural": "Die Konferenz ist beendet, da nach {0} Minuten kein Moderator anwesend ist", + "app.meeting.endedByNoModeratorMessageSingular": "Die Konferenz ist beendet, da nach einer Minute kein:e Moderator:in anwesend ist", + "app.meeting.endedByNoModeratorMessagePlural": "Die Konferenz ist beendet, da nach {0} Minuten kein:e Moderator:in anwesend ist", "app.meeting.endedMessage": "Sie werden zum Startbildschirm weitergeleitet", "app.meeting.alertMeetingEndsUnderMinutesSingular": "Konferenz endet in einer Minute.", "app.meeting.alertMeetingEndsUnderMinutesPlural": "Konferenz endet in {0} Minuten.", @@ -201,8 +203,8 @@ "app.presentation.presentationToolbar.goToSlide": "Folie {0}", "app.presentation.placeholder": "Es gibt derzeit keine aktive Präsentation", "app.presentationUploder.title": "Präsentation", - "app.presentationUploder.message": "Als Präsentator in BigBlueButton haben Sie die Möglichkeit Office-Dokumente oder PDF-Dateien hochzuladen. PDF-Dateien haben dabei die bessere Qualität. Bitte stellen Sie sicher, dass eine Präsentation durch das runde Markierungsfeld auf der rechten Seite ausgewählt ist.", - "app.presentationUploder.extraHint": "WICHTIG: Jede Datei darf {0} MB und {1} Seiten nicht überschreiten.", + "app.presentationUploder.message": "Präsentationen können als Office-Dokumente oder PDF-Dateien hochgeladen werden. PDF-Dateien haben dabei die bessere Qualität. Eine Präsentation muss dann durch das runde Markierungsfeld auf der rechten Seite ausgewählt sein.", + "app.presentationUploder.extraHint": "Jede Datei darf {0} MB und {1} Seiten nicht überschreiten.", "app.presentationUploder.uploadLabel": "Hochladen", "app.presentationUploder.confirmLabel": "Bestätigen", "app.presentationUploder.confirmDesc": "Änderungen speichern und Präsentation starten", @@ -214,8 +216,8 @@ "app.presentationUploder.browseImagesLabel": "oder nach Bildern suchen/aufnehmen", "app.presentationUploder.fileToUpload": "Bereit zum Hochladen...", "app.presentationUploder.currentBadge": "Aktuell", - "app.presentationUploder.rejectedError": "Die ausgewählten Dateien wurden zurückgewiesen. Bitte prüfen Sie die zulässigen Dateitypen.", - "app.presentationUploder.connectionClosedError": "Durch schlechte Verbindung unterbrochen. Bitte versuchen Sie es erneut.", + "app.presentationUploder.rejectedError": "Die ausgewählten Dateien wurden zurückgewiesen. Bitte die zulässigen Dateitypen prüfen.", + "app.presentationUploder.connectionClosedError": "Durch schlechte Verbindung unterbrochen. Bitte erneut versuchen.", "app.presentationUploder.upload.progress": "Hochladen ({0}%)", "app.presentationUploder.upload.413": "Datei ist zu groß, hat die Maximalgröße {0} MB überschritten", "app.presentationUploder.genericError": "Ups, irgendwas ist schiefgelaufen ...", @@ -228,14 +230,14 @@ "app.presentationUploder.conversion.generatedSlides": "Folien wurden generiert...", "app.presentationUploder.conversion.generatingSvg": "SVG-Bilder werden generiert...", "app.presentationUploder.conversion.pageCountExceeded": "Maximale Seitenanzahl von {0} Seiten wurde überschritten", - "app.presentationUploder.conversion.officeDocConversionInvalid": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte laden Sie eine PDF-Datei hoch.", - "app.presentationUploder.conversion.officeDocConversionFailed": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte laden Sie eine PDF-Datei hoch.", + "app.presentationUploder.conversion.officeDocConversionInvalid": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte eine PDF-Datei hochladen versuchen.", + "app.presentationUploder.conversion.officeDocConversionFailed": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte eine PDF-Datei hochladen.", "app.presentationUploder.conversion.pdfHasBigPage": "Die PDF-Datei konnte nicht konvertiert werden, bitte versuchen Sie die Datei zu optimieren. Die maximale Seitenzahl beträgt {0} Seiten.", "app.presentationUploder.conversion.timeout": "Ups, die Konvertierung hat zu lange gedauert", "app.presentationUploder.conversion.pageCountFailed": "Die Seitenanzahl konnte nicht ermittelt werden.", "app.presentationUploder.conversion.unsupportedDocument": "Dateityp wird nicht unterstützt", - "app.presentationUploder.isDownloadableLabel": "Das Herunterladen der Präsentation ist nicht zugelassen - klicken Sie darauf, um das Herunterladen der Präsentation zu erlauben", - "app.presentationUploder.isNotDownloadableLabel": "Das Herunterladen der Präsentation ist zugelassen - klicken Sie, um das Herunterladen der Präsentation zu verbieten", + "app.presentationUploder.isDownloadableLabel": "Das Herunterladen der Präsentation ist nicht zugelassen - hier das Herunterladen der Präsentation erlauben", + "app.presentationUploder.isNotDownloadableLabel": "Das Herunterladen der Präsentation ist zugelassen - hier das Herunterladen der Präsentation verbieten", "app.presentationUploder.removePresentationLabel": "Präsentation entfernen", "app.presentationUploder.setAsCurrentPresentation": "Diese Präsentation auswählen", "app.presentationUploder.tableHeading.filename": "Dateiname", @@ -250,13 +252,13 @@ "app.presentationUploder.clearErrorsDesc": "Löscht fehlgeschlagene Präsentationsuploads", "app.presentationUploder.uploadViewTitle": "Präsentation hochladen", "app.poll.pollPaneTitle": "Umfrage", - "app.poll.enableMultipleResponseLabel": "Mehrere Antworten pro Befragten zulassen?", + "app.poll.enableMultipleResponseLabel": "Mehrere Antworten pro Befragte:n zulassen?", "app.poll.quickPollTitle": "Schnellumfrage", "app.poll.hidePollDesc": "Versteckt das Umfragemenü", - "app.poll.quickPollInstruction": "Wählen Sie eine der unten stehenden Optionen, um die Umfrage zu starten.", - "app.poll.activePollInstruction": "Lassen Sie dieses Fenster offen, um auf die Antworten der Teilnehmer zu warten. Sobald Sie auf 'Umfrageergebnisse veröffentlichen' klicken, werden die Ergebnisse angezeigt und die Umfrage beendet.", - "app.poll.dragDropPollInstruction": "Um die Umfrageoptionen automatisch auszufüllen, ziehen Sie eine Textdatei mit den Umfrageoptionen per Drag&Drop in das hervorgehobene Feld", - "app.poll.customPollTextArea": "Füllen Sie die Umfrageoptionen aus", + "app.poll.quickPollInstruction": "Bitte eine der unten stehenden Optionen wählen, um die Umfrage zu starten.", + "app.poll.activePollInstruction": "Dieses Fenster offen lassen, um auf die Antworten der Teilnehmer:innen zu warten. Sobald auf 'Umfrageergebnisse veröffentlichen' geklickt wird, werden die Ergebnisse angezeigt und wird die Umfrage beendet.", + "app.poll.dragDropPollInstruction": "Um die Umfrageoptionen automatisch auszufüllen, eine Textdatei mit den Umfrageoptionen per Drag&Drop in das hervorgehobene Feld ziehen", + "app.poll.customPollTextArea": "Umfrageoptionen ausfüllen", "app.poll.publishLabel": "Umfrage veröffentlichen", "app.poll.cancelPollLabel": "Abbrechen", "app.poll.backLabel": "Umfrage starten", @@ -266,13 +268,13 @@ "app.poll.customPlaceholder": "Umfrageoption hinzufügen", "app.poll.noPresentationSelected": "Keine Präsentation ausgewählt! Bitte eine auswählen.", "app.poll.clickHereToSelect": "Zum Auswählen hier klicken", - "app.poll.question.label" : "Stellen Sie Ihre Frage...", - "app.poll.optionalQuestion.label" : "Stellen Sie Ihre Frage (optional)...", + "app.poll.question.label" : "Eine Frage stellen ...", + "app.poll.optionalQuestion.label" : "Eine Frage stellen (optional) ...", "app.poll.userResponse.label" : "Teilnehmerantwort", "app.poll.responseTypes.label" : "Antworttypen", "app.poll.optionDelete.label" : "Löschen", "app.poll.responseChoices.label" : "Antwortmöglichkeiten", - "app.poll.typedResponse.desc" : "Dem Teilnehmer wird ein Textfeld angezeigt, um seine Antwort einzutragen.", + "app.poll.typedResponse.desc" : "Den Teilnehmer:innen wird ein Textfeld angezeigt, um die Antwort einzutragen.", "app.poll.addItem.label" : "Element hinzufügen", "app.poll.start.label" : "Umfrage starten", "app.poll.secretPoll.label" : "Anonyme Umfrage", @@ -323,9 +325,9 @@ "app.connectingMessage": "Verbinde...", "app.waitingMessage": "Verbindung unterbrochen. Versuche in {0} Sekunden erneut zu verbinden...", "app.retryNow": "Jetzt erneut versuchen", - "app.muteWarning.label": "Klicken Sie auf {0}, um Ihre Stummschaltung aufzuheben.", + "app.muteWarning.label": "Auf {0} klicken, um die Stummschaltung aufzuheben.", "app.muteWarning.disableMessage": "Hinweis auf Stummschaltung deaktiviert, bis die Stummschaltung aufgehoben wird", - "app.muteWarning.tooltip": "Klicken Sie, um den Hinweis bis zur nächsten Aufhebung der Stummschaltung zu schließen", + "app.muteWarning.tooltip": "Klicken, um den Hinweis bis zur nächsten Aufhebung der Stummschaltung zu schließen", "app.navBar.settingsDropdown.optionsLabel": "Optionen", "app.navBar.settingsDropdown.fullscreenLabel": "Als Vollbild darstellen", "app.navBar.settingsDropdown.settingsLabel": "Einstellungen öffnen", @@ -350,11 +352,11 @@ "app.navBar.recording": "Diese Konferenz wird aufgezeichnet", "app.navBar.recording.on": "Aufzeichnung läuft", "app.navBar.recording.off": "Keine Aufnahme", - "app.navBar.emptyAudioBrdige": "Kein aktives Mikrofon. Bitte erlauben Sie Zugriff auf Ihr Mikrofon, um in der Aufzeichnung auch Ihr Audio zu hören.", + "app.navBar.emptyAudioBrdige": "Kein aktives Mikrofon. Bitte den Zugriff auf das Mikrofon erlauben, um in der Aufzeichnung auch den Ton zu hören.", "app.leaveConfirmation.confirmLabel": "Verlassen", "app.leaveConfirmation.confirmDesc": "Hiermit verlassen Sie die Konferenz", "app.endMeeting.title": "{0} beenden", - "app.endMeeting.description": "Mit dieser Aktion wird die Sitzung für {0} aktive(n) Teilnehmer beendet. Sind Sie sicher, dass Sie diese Sitzung beenden möchten?", + "app.endMeeting.description": "Mit dieser Aktion wird die Sitzung für {0} aktive(n) Teilnehmer:innen beendet. Sicher, dass die Sitzung beendet werden soll?", "app.endMeeting.noUserDescription": "Sind Sie sicher, dass Sie die Konferenz beenden wollen?", "app.endMeeting.contentWarning": "Chatnachrichten, geteilte Notizen, Whiteboard-Inhalte und geteilte Dokumente dieser Konferenz sind nicht mehr direkt zugänglich", "app.endMeeting.yesLabel": "Ja", @@ -391,7 +393,7 @@ "app.submenu.application.paginationEnabledLabel": "Seitenweises Anzeigen von Webcams", "app.submenu.application.layoutOptionLabel": "Layout-Modus", "app.submenu.notification.SectionTitle": "Benachrichtigungen", - "app.submenu.notification.Desc": "Definieren Sie, wie und was Ihnen mitgeteilt wird.", + "app.submenu.notification.Desc": "Bitte definieren, wie und was mitgeteilt werden soll.", "app.submenu.notification.audioAlertLabel": "Audio-Hinweise", "app.submenu.notification.pushAlertLabel": "Popup-Hinweise", "app.submenu.notification.messagesLabel": "Chatnachricht", @@ -400,7 +402,7 @@ "app.submenu.notification.guestWaitingLabel": "Gast im Warteraum", "app.submenu.audio.micSourceLabel": "Mikrofonauswahl", "app.submenu.audio.speakerSourceLabel": "Lautsprecherauswahl", - "app.submenu.audio.streamVolumeLabel": "Ihre Audiolautstärke", + "app.submenu.audio.streamVolumeLabel": "Eigene Audiolautstärke", "app.submenu.video.title": "Video", "app.submenu.video.videoSourceLabel": "Videoquelle ansehen", "app.submenu.video.videoOptionLabel": "Videoeingang auswählen", @@ -419,7 +421,7 @@ "app.settings.dataSavingTab.label": "Datensparmodus", "app.settings.dataSavingTab.webcam": "Webcams aktiviert", "app.settings.dataSavingTab.screenShare": "Bildschirmfreigabe aktiviert", - "app.settings.dataSavingTab.description": "Um Datentransfervolumen zu sparen, können Sie hier einstellen, was angezeigt wird.", + "app.settings.dataSavingTab.description": "Um Datentransfervolumen zu sparen, können hier eingestellt werden, was angezeigt wird.", "app.settings.save-notification.label": "Einstellungen wurden gespeichert", "app.statusNotifier.lowerHands": "Hände senken", "app.statusNotifier.lowerHandDescOneUser": "Hand von {0} senken", @@ -429,7 +431,7 @@ "app.statusNotifier.and": "und", "app.switch.onLabel": "AN", "app.switch.offLabel": "AUS", - "app.talkingIndicator.ariaMuteDesc" : "Auswählen, um Teilnehmer stummzuschalten", + "app.talkingIndicator.ariaMuteDesc" : "Auswählen, um Teilnehmer:in stummzuschalten", "app.talkingIndicator.isTalking" : "{0} spricht", "app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ sprechen", "app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ sprachen", @@ -453,8 +455,8 @@ "app.actionsBar.actionsDropdown.captionsDesc": "Untertitelfenster umschalten", "app.actionsBar.actionsDropdown.takePresenter": "Zum Präsentator werden", "app.actionsBar.actionsDropdown.takePresenterDesc": "Sich selbst zum neuen Präsentator machen", - "app.actionsBar.actionsDropdown.selectRandUserLabel": "Zufälligen Teilnehmer auswählen", - "app.actionsBar.actionsDropdown.selectRandUserDesc": "Wählt einen Teilnehmer nach dem Zufallsprinzip aus", + "app.actionsBar.actionsDropdown.selectRandUserLabel": "Zufällig auswählen", + "app.actionsBar.actionsDropdown.selectRandUserDesc": "Wählt eine:n Teilnehmer:in nach dem Zufallsprinzip aus.", "app.actionsBar.emojiMenu.statusTriggerLabel": "Status setzen", "app.actionsBar.emojiMenu.awayLabel": "Abwesend", "app.actionsBar.emojiMenu.awayDesc": "Ihren Status auf abwesend setzen", @@ -495,13 +497,13 @@ "app.audioNotification.audioFailedMessage": "Audioverbindung konnte nicht hergestellt werden", "app.audioNotification.mediaFailedMessage": "getUserMicMedia fehlgeschlagen, weil nur sichere Quellen erlaubt sind", "app.audioNotification.closeLabel": "Schließen", - "app.audioNotificaion.reconnectingAsListenOnly": "Mikrofone sind für Teilnehmer gesperrt, Sie werden nur zum Zuhören verbunden", + "app.audioNotificaion.reconnectingAsListenOnly": "Mikrofone sind für Teilnehmer:innen gesperrt, in dieser Konferenz ist nur Zuhören möglich", "app.breakoutJoinConfirmation.title": "Gruppenraum beitreten", - "app.breakoutJoinConfirmation.message": "Möchten Sie beitreten", + "app.breakoutJoinConfirmation.message": "Jetzt der Gruppe beitreten", "app.breakoutJoinConfirmation.confirmDesc": "Dem Gruppenraum beitreten", "app.breakoutJoinConfirmation.dismissLabel": "Abbrechen", "app.breakoutJoinConfirmation.dismissDesc": "Schließen und die Teilnahme im Gruppenraum verweigern", - "app.breakoutJoinConfirmation.freeJoinMessage": "Wählen Sie den Gruppenraum aus, dem sie beitreten wollen", + "app.breakoutJoinConfirmation.freeJoinMessage": "Gruppenraum auswählen, dem beigetreten werden soll", "app.breakoutTimeRemainingMessage": "Verbleibende Gruppenraumzeit: {0}", "app.breakoutWillCloseMessage": "Zeit abgelaufen. Der Gruppenraum wird in Kürze geschlossen.", "app.breakout.dropdown.manageDuration": "Dauer verwalten", @@ -513,12 +515,12 @@ "app.audioModal.listenOnlyLabel": "Nur zuhören", "app.audioModal.microphoneDesc": "Nimmt an der Audiokonferenz mit Mikrofon teil", "app.audioModal.listenOnlyDesc": "Nimmt an der Audiokonferenz nur als Zuhörer teil", - "app.audioModal.audioChoiceLabel": "Wie möchten Sie der Konferenz beitreten?", + "app.audioModal.audioChoiceLabel": "Wie der Konferenz beitreten?", "app.audioModal.iOSBrowser": "Audio/Video wird nicht unterstützt", "app.audioModal.iOSErrorDescription": "Gegenwärtig wird Audio und Video von Chrome für iOS nicht unterstützt.", "app.audioModal.iOSErrorRecommendation": "Wir empfehlen Safari iOS zu verwenden.", - "app.audioModal.audioChoiceDesc": "Wie möchten Sie der Konferenz beitreten?", - "app.audioModal.unsupportedBrowserLabel": "Sie scheinen einen Browser zu verwenden, der nicht vollständig unterstützt wird. Bitte verwenden Sie entweder {0} oder {1} für volle Unterstützung.", + "app.audioModal.audioChoiceDesc": "Wie der Konferenz beitreten?", + "app.audioModal.unsupportedBrowserLabel": "Der verwendete Browser wird scheinbar nicht vollständig unterstützt. Bitte entweder {0} oder {1} für eine gute Verbindung nehmen.", "app.audioModal.closeLabel": "Schließen", "app.audioModal.yes": "Ja", "app.audioModal.no": "Nein", @@ -526,28 +528,28 @@ "app.audioModal.no.arialabel" : "Echo ist nicht hörbar", "app.audioModal.echoTestTitle": "Dies ist ein persönlicher Echotest. Sprechen Sie ein paar Worte. Hören Sie sich selbst?", "app.audioModal.settingsTitle": "Audioeinstellungen ändern", - "app.audioModal.helpTitle": "Es gab ein Problem mit ihren Mediengeräten (Mikrofon/Webcam)", - "app.audioModal.helpText": "Haben Sie die Zugriffsrechte auf Ihr Mikrofon erteilt? Hinweis: Der Berechtigungsdialog dazu wird angezeigt, wenn Sie der Audiokonferenz beitreten. Dabei fragt Ihr Mediengerät nach der Zugriffserlaubnis. Bitte akzeptieren Sie diesen Dialog, um der Audiokonferenz beizutreten. Falls dies nicht zutrifft, dann verändern Sie bitte die Mikrofonberechtigung in Ihren Browsereinstellungen.", + "app.audioModal.helpTitle": "Es gab ein Problem mit den Mediengeräten (Mikrofon/Webcam)", + "app.audioModal.helpText": "Wurden die Zugriffsrechte auf das Mikrofon erteilt? Hinweis: Der Berechtigungsdialog dazu wird angezeigt, wenn der Audiokonferenz beigetreten wird. Dabei fragt der Browser nach einer Zugriffserlaubnis. Bitte diese akzeptieren, um der Audiokonferenz beizutreten. Falls dies nicht zutrifft, dann bitte die Mikrofonberechtigung in den Browsereinstellungen verändern.", "app.audioModal.help.noSSL": "Diese Seite ist nicht über HTTPS abgesichtert. Um Zugriff auf Ihr Mikrofon zu erlauben, muss die Webseite über HTTPS bereitgestellt werden. Bitte kontaktieren Sie den Serveradministrator.", - "app.audioModal.help.macNotAllowed": "Es scheint so, als ob Ihre Mac Systemeinstellungen die Mikrofonfreigabe blockiert. Öffnen Sie Systemeinstellungen > Sicherheit & Privatsphäre > Mikrofon und stellen Sie sicher, dass der von Ihnen verwendete Browser ausgewählt ist.", + "app.audioModal.help.macNotAllowed": "Es scheint so, als ob die Mac Systemeinstellungen die Mikrofonfreigabe blockiert. Öffnen die Systemeinstellungen öffnen > Sicherheit & Privatsphäre > Mikrofon und sicherstellen, dass der verwendete Browser ausgewählt ist.", "app.audioModal.audioDialTitle": "Mit dem Telefon teilnehmen", "app.audioDial.audioDialDescription": "Anrufen", - "app.audioDial.audioDialConfrenceText": "und geben Sie die Konferenz-PIN ein:", - "app.audioModal.autoplayBlockedDesc": "Wir benötigen Ihre Zustimmung für die Audiowiedergabe.", + "app.audioDial.audioDialConfrenceText": "und diese Konferenz-PIN eingeben:", + "app.audioModal.autoplayBlockedDesc": "Wir benötigen die Zustimmung für die Audiowiedergabe.", "app.audioModal.playAudio": "Audio wiedergeben", "app.audioModal.playAudio.arialabel" : "Audio wiedergeben", "app.audioDial.tipIndicator": "Tipp", - "app.audioDial.tipMessage": "Drücken Sie die '0' Taste Ihres Telefons, um sich stumm bzw. freizuschalten.", + "app.audioDial.tipMessage": "Mit der '0' Taste am Telefons sich stumm bzw. aktiv schalten.", "app.audioModal.connecting": "Audio-Verbindung wird hergestellt", - "app.audioManager.joinedAudio": "Sie sind der Konferenz beigetreten", + "app.audioManager.joinedAudio": "Konferenz beigetreten", "app.audioManager.joinedEcho": "Der Echotest wurde gestartet", - "app.audioManager.leftAudio": "Sie haben die Audiokonferenz verlassen", + "app.audioManager.leftAudio": "Audiokonferenz wurde verlassen", "app.audioManager.reconnectingAudio": "Versuche Audio neu zu verbinden", - "app.audioManager.genericError": "Fehler: Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut", + "app.audioManager.genericError": "Fehler: Es ist ein Fehler aufgetreten, bitte erneut versuchen.", "app.audioManager.connectionError": "Fehler: Verbindungsfehler", "app.audioManager.requestTimeout": "Fehler: Zeitüberschreitung beim Aufruf", "app.audioManager.invalidTarget": "Fehler: Beim Aufruf wurde ein ungültiges Ziel angegeben", - "app.audioManager.mediaError": "Fehler: Es gab ein Problem bei der Abfrage Ihrer Mediengeräte", + "app.audioManager.mediaError": "Fehler: Es gab ein Problem bei der Nutzung der Mediengeräte (Kamera/Mikrofon)", "app.audio.joinAudio": "Audio starten", "app.audio.leaveAudio": "Audio beenden", "app.audio.changeAudioDevice": "Audiogerät wechseln", @@ -559,22 +561,23 @@ "app.audio.speakers": "Lautsprecher", "app.audio.noDeviceFound": "Kein Gerät gefunden", "app.audio.audioSettings.titleLabel": "Audioeinstellungen auswählen", - "app.audio.audioSettings.descriptionLabel": "Ein Dialogfenster wird sich in Ihrem Browser öffnen, in dem Sie der Freigabe Ihres Mikrofons zustimmen müssen.", + "app.audio.audioSettings.descriptionLabel": "Ein Dialogfenster wird sich im Browser öffnen, in dem der Freigabe des Mikrofons zugestimmt werden muss.", "app.audio.audioSettings.microphoneSourceLabel": "Mikrofoneingang", "app.audio.audioSettings.speakerSourceLabel": "Lautsprecherausgang", - "app.audio.audioSettings.microphoneStreamLabel": "Lautstärke Ihres Audiosignals", + "app.audio.audioSettings.testSpeakerLabel": "Lautsprecher testen", + "app.audio.audioSettings.microphoneStreamLabel": "Lautstärke des Audiosignals", "app.audio.audioSettings.retryLabel": "Erneut versuchen", "app.audio.listenOnly.backLabel": "Zurück", "app.audio.listenOnly.closeLabel": "Schließen", - "app.audio.permissionsOverlay.title": "Zugriff auf Ihr Mikrofon erlauben", - "app.audio.permissionsOverlay.hint": "Sie müssen Zugriff auf Ihre Mediengeräte erlauben, um an einer Audiokonferenz teilnehmen zu können.", - "app.error.removed": "Sie wurden aus der Konferenz entfernt", - "app.error.meeting.ended": "Sie haben die Konferenz verlassen", - "app.meeting.logout.duplicateUserEjectReason": "Bereits anwesender Teilnehmer versucht erneut der Konferenz beizutreten", + "app.audio.permissionsOverlay.title": "Zugriff auf das Mikrofon erlauben", + "app.audio.permissionsOverlay.hint": "Zugriff auf die Mediengeräte muss im Browser erlaubt werden, um an einer Audiokonferenz teilnehmen zu können.", + "app.error.removed": "Die Konferenz musste verlassen werden.", + "app.error.meeting.ended": "Konferenz wurde verlassen", + "app.meeting.logout.duplicateUserEjectReason": "Bereits anwesende:r Teilnehmer:in versucht erneut der Konferenz beizutreten", "app.meeting.logout.permissionEjectReason": "Aufgrund einer Rechteverletzung aus der Konferenz entfernt worden", "app.meeting.logout.ejectedFromMeeting": "Sie wurden aus der Konferenz entfernt", "app.meeting.logout.validateTokenFailedEjectReason": "Verifikation des Autorisierungsmerkmals fehlgeschlagen", - "app.meeting.logout.userInactivityEjectReason": "Teilnehmer war zu lange inaktiv", + "app.meeting.logout.userInactivityEjectReason": "Teilnehmer:in war zu lange inaktiv", "app.meeting-ended.rating.legendLabel": "Feedbackbewertung", "app.meeting-ended.rating.starLabel": "Stern", "app.modal.close": "Schließen", @@ -582,13 +585,13 @@ "app.modal.confirm": "Fertig", "app.modal.newTab": "(Öffnet neuen Tab)", "app.modal.confirm.description": "Änderungen speichern und Dialog schließen", - "app.modal.randomUser.noViewers.description": "Keine Teilnehmer zur zufälligen Auswahl verfügbar", - "app.modal.randomUser.selected.description": "Sie wurden zufällig ausgewählt", - "app.modal.randomUser.title": "Zufällig ausgewählter Teilnehmer", + "app.modal.randomUser.noViewers.description": "Kein:e Teilnehmer:in zur zufälligen Auswahl verfügbar", + "app.modal.randomUser.selected.description": "zufällig ausgewählt", + "app.modal.randomUser.title": "Zufällig ausgewählte:r Teilnehmer:in", "app.modal.randomUser.who": "Wer wird ausgewählt...?", - "app.modal.randomUser.alone": "Es gibt nur einen Teilnehmer", + "app.modal.randomUser.alone": "Es gibt nur eine:n Teilnehmer:in", "app.modal.randomUser.reselect.label": "Erneut auswählen", - "app.modal.randomUser.ariaLabel.title": "Dialog für zufällig ausgewählten Teilnehmer", + "app.modal.randomUser.ariaLabel.title": "Dialog für zufällig ausgewählte:n Teilnehmer:in", "app.dropdown.close": "Schließen", "app.dropdown.list.item.activeLabel": "Aktiv", "app.error.400": "Ungültige Anfrage", @@ -598,41 +601,41 @@ "app.error.408": "Authentifizierung fehlgeschlagen", "app.error.410": "Die Konferenz ist zu Ende", "app.error.500": "Ups, irgendwas ist schiefgelaufen", - "app.error.userLoggedOut": "Teilnehmer hat einen ungültigen Konferenz-Token, weil er sich ausgeloggt hat", - "app.error.ejectedUser": "Teilnehmer hat einen ungültigen Konferenz-Token, weil er gesperrt wurde", - "app.error.userBanned": "Teilnehmer wurde gesperrt", + "app.error.userLoggedOut": "Teilnehmer:in hat einen ungültigen Konferenz-Token, weil er:sie sich ausgeloggt hat", + "app.error.ejectedUser": "Teilnehmer:in hat einen ungültigen Konferenz-Token, weil er:sie gesperrt wurde", + "app.error.userBanned": "Teilnehmer:in wurde gesperrt", "app.error.leaveLabel": "Erneut einloggen", "app.error.fallback.presentation.title": "Es ist ein Fehler aufgetreten", - "app.error.fallback.presentation.description": "Er wurde protokolliert. Bitte versuchen Sie die Seite neu zu laden.", + "app.error.fallback.presentation.description": "Er wurde protokolliert. Bitte versuchen, die Seite neu zu laden.", "app.error.fallback.presentation.reloadButton": "Neu laden", - "app.guest.waiting": "Warte auf Erlaubnis zur Konferenzteilnahme", + "app.guest.waiting": "Auf Erlaubnis zur Konferenzteilnahme wird gewartet", "app.guest.errorSeeConsole": "Fehler: Weitere Details in der Konsole.", "app.guest.noModeratorResponse": "Keine Antwort vom Moderator.", "app.guest.noSessionToken": "Kein Konferenz-Token erhalten.", - "app.guest.windowTitle": "BigBlueButton - Wartebereich für Gäste", + "app.guest.windowTitle": "Wartebereich für Gäste", "app.guest.missingToken": "Gast fehlt Konferenz-Token.", "app.guest.missingSession": "Gast fehlt in der Konferenz.", "app.guest.missingMeeting": "Konferenz existiert nicht.", "app.guest.meetingEnded": "Konferenz beendet.", "app.guest.guestWait": "Bitte warten Sie, bis ein Moderator Ihre Teilnahme an der Konferenz freigibt.", - "app.guest.guestDeny": "Der Moderator hat die Teilnahme an der Konferenz abgelehnt.", + "app.guest.guestDeny": "Moderator:in hat die Teilnahme an der Konferenz abgelehnt.", "app.guest.seatWait": "Gast wartet auf die Teilnahme an der Konferenz.", "app.guest.allow": "Gast zugelassen und zur Konferenz weitergeleitet.", - "app.guest.firstPositionInWaitingQueue": "Sie sind der Erste in der Warteschlange!", - "app.guest.positionInWaitingQueue": "Ihre aktuelle Position in der Warteschlange: ", + "app.guest.firstPositionInWaitingQueue": "Nun Erste:r in der Warteschlange!", + "app.guest.positionInWaitingQueue": "Aktuelle Position in der Warteschlange: ", "app.guest.guestInvalid": "Gastteilnehmer ist ungültig", - "app.guest.meetingForciblyEnded": "Sie können nicht an einer Konferenz teilnehmen, die bereits beendet wurde", - "app.userList.guest.waitingUsers": "Wartende Teilnehmer", + "app.guest.meetingForciblyEnded": "An einer Konferenz, die bereits beendet wurde, kann nicht teilgenommen werden", + "app.userList.guest.waitingUsers": "Wartende Teilnehmer:innen", "app.userList.guest.waitingUsersTitle": "Teilnehmerverwaltung", - "app.userList.guest.optionTitle": "Unbearbeitete Teilnehmer überprüfen", + "app.userList.guest.optionTitle": "Unbearbeitete Teilnehmer:innen überprüfen", "app.userList.guest.allowAllAuthenticated": "Alle Autorisierten erlauben", "app.userList.guest.allowAllGuests": "Alle Gäste erlauben", "app.userList.guest.allowEveryone": "Alle erlauben", "app.userList.guest.denyEveryone": "Alle verweigern", - "app.userList.guest.pendingUsers": "{0} unbearbeitete Teilnehmer", - "app.userList.guest.noPendingUsers": "Derzeit keine ausstehenden Teilnehmer...", + "app.userList.guest.pendingUsers": "{0} unbearbeitete Teilnehmer:innen", + "app.userList.guest.noPendingUsers": "Derzeit keine ausstehenden Teilnehmer:innen ...", "app.userList.guest.pendingGuestUsers": "{0} wartende Gäste", - "app.userList.guest.pendingGuestAlert": "Ist der Konferenz beigetreten und wartet auf Ihre Teilnahmeerlaubnis", + "app.userList.guest.pendingGuestAlert": "Ist der Konferenz beigetreten und wartet auf Teilnahmeerlaubnis", "app.userList.guest.rememberChoice": "Auswahl für die Zukunft speichern", "app.userList.guest.emptyMessage": "Momentan keine Nachricht vorhanden", "app.userList.guest.inputPlaceholder": "Nachricht für den Wartebereich", @@ -641,18 +644,18 @@ "app.userList.guest.acceptLabel": "Akzeptieren", "app.userList.guest.denyLabel": "Ablehnen", "app.user-info.title": "Verzeichnissuche", - "app.toast.breakoutRoomEnded": "Gruppenraum wurde geschlossen. Bitte treten Sie der Audiokonferenz erneut bei.", + "app.toast.breakoutRoomEnded": "Gruppenraum wurde geschlossen. Bitte treten der Audiokonferenz erneut beitreten.", "app.toast.chat.public": "Neue öffentliche Chatnachricht", "app.toast.chat.private": "Neue private Chatnachricht", "app.toast.chat.system": "System", "app.toast.clearedEmoji.label": "Emojistatus zurückgesetzt", "app.toast.setEmoji.label": "Emojistatus auf {0} gesetzt", - "app.toast.meetingMuteOn.label": "Alle Teilnehmer wurden stummgeschaltet", + "app.toast.meetingMuteOn.label": "Alle Teilnehmer:innen wurden stummgeschaltet", "app.toast.meetingMuteOff.label": "Konferenz-Stummschaltung ausgeschaltet", "app.toast.setEmoji.raiseHand": "Sie haben Ihre Hand gehoben", - "app.toast.setEmoji.lowerHand": "Ihre Hand wurde gesenkt", - "app.toast.promotedLabel": "Sie sind zum Moderator ernannt worden", - "app.toast.demotedLabel": "Sie wurden zum Teilnehmer zurückgestuft", + "app.toast.setEmoji.lowerHand": "Habe meine Hand gesenkt", + "app.toast.promotedLabel": "Zum Moderator ernannt worden", + "app.toast.demotedLabel": "Nun wieder in der Rolle eine:r Teilnehmer:in", "app.notification.recordingStart": "Diese Konferenz wird jetzt aufgezeichnet", "app.notification.recordingStop": "Diese Konferenz wird nicht aufgezeichnet", "app.notification.recordingPaused": "Diese Konferenz wird nicht mehr aufgezeichnet", @@ -680,7 +683,11 @@ "app.shortcut-help.toggleFullscreen": "Vollbild umschalten (Präsentator)", "app.shortcut-help.nextSlideDesc": "Nächste Folie (Präsentator)", "app.shortcut-help.previousSlideDesc": "Vorherige Folie (Präsentator)", - "app.lock-viewers.title": "Teilnehmerrechte einschränken", + "app.shortcut-help.togglePanKey": "Leertaste", + "app.shortcut-help.toggleFullscreenKey": "Enter", + "app.shortcut-help.nextSlideKey": "Pfeil rechts", + "app.shortcut-help.previousSlideKey": "Pfeil links", + "app.lock-viewers.title": "Rechte der Teilnehmer:innen einschränken", "app.lock-viewers.description": "Diese Optionen ermöglichen es, bestimmte Funktionen für Teilnehmer einzuschränken.", "app.lock-viewers.featuresLable": "Funktion", "app.lock-viewers.lockStatusLabel": "Status", @@ -691,11 +698,11 @@ "app.lock-viewers.PrivateChatLable": "Private Chatnachrichten senden", "app.lock-viewers.notesLabel": "Geteilte Notizen bearbeiten", "app.lock-viewers.userListLabel": "Teilnehmerliste für andere Teilnehmer anzeigen", - "app.lock-viewers.ariaTitle": "Teilnehmereinstellungsdialog", + "app.lock-viewers.ariaTitle": "Einstellungen für Teilnehmer:innen", "app.lock-viewers.button.apply": "Anwenden", "app.lock-viewers.button.cancel": "Abbrechen", "app.lock-viewers.locked": "Gesperrt", - "app.lock-viewers.unlocked": "Freigegeben", + "app.lock-viewers.hideViewersCursor": "Cursor anderer Teilnehmer anzeigen", "app.guest-policy.ariaTitle": "Einstellungsdialog für Gastzugangsregelung", "app.guest-policy.title": "Gastzugang regeln", "app.guest-policy.description": "Grundregel für den Gastzugang ändern", @@ -712,16 +719,16 @@ "app.connection-status.copied": "Kopiert!", "app.connection-status.jitter": "Jitter", "app.connection-status.label": "Verbindungsstatus", - "app.connection-status.settings": "Anpassen Ihrer Einstellungen", + "app.connection-status.settings": "Anpassen der Einstellungen", "app.connection-status.no": "Nein", - "app.connection-status.notification": "Verbindungsabbruch bei Ihrer Verbindung wurde erkannt", + "app.connection-status.notification": "Abbruch der Verbindung wurde erkannt", "app.connection-status.offline": "Offline", "app.connection-status.audioUploadRate": "Audio-Uploadrate", "app.connection-status.audioDownloadRate": "Audio-Downloadrate", "app.connection-status.videoUploadRate": "Video-Uploadrate", "app.connection-status.videoDownloadRate": "Video-Downloadrate", "app.connection-status.lostPackets": "Verlorene Pakete", - "app.connection-status.usingTurn": "TURN wird genutzt", + "app.connection-status.usingTurn": "TURN wird genutzt um Firewall zu umgehen", "app.connection-status.yes": "Ja", "app.connection-status.connectionStats": "Verbindungsstatistiken", "app.connection-status.myLogs": "Meine Protokolle", @@ -734,8 +741,8 @@ "app.recording.startTitle": "Aufzeichnung starten", "app.recording.stopTitle": "Aufzeichnung pausieren", "app.recording.resumeTitle": "Aufzeichnung fortsetzen", - "app.recording.startDescription": "Durch erneutes Drücken des Aufnahmeknopfs können Sie die Aufnahme pausieren.", - "app.recording.stopDescription": "Sind Sie sicher, dass Sie die Aufnahme pausieren wollen? Sie können Sie durch erneutes Drücken des Aufnahmeknopfs jederzeit fortsetzen.", + "app.recording.startDescription": "Durch erneutes Drücken des Aufnahmeknopfs Aufnahme pausieren.", + "app.recording.stopDescription": "Aufnahme pausieren? Diese kann durch erneutes Drücken des Aufnahmeknopfs jederzeit fortgesetzt werden.", "app.videoPreview.cameraLabel": "Kamera", "app.videoPreview.profileLabel": "Qualität", "app.videoPreview.quality.low": "Niedrige", @@ -768,13 +775,13 @@ "app.video.overconstrainedError": "Keine Gerätetypen, die die geforderten Kriterien erfüllen", "app.video.securityError": "Medienunterstützung ist für das Dokument deaktiviert", "app.video.typeError": "Liste der angegebenen Bedingungen ist leer oder alle Bedingungen sind auf falsch gesetzt", - "app.video.notFoundError": "Konnte keine Webcam finden. Stellen Sie sicher, dass sie angeschlossen ist", - "app.video.notAllowed": "Fehlende Berechtigung für die Webcamfreigabe, prüfen Sie Ihre Browserberechtigungen", - "app.video.notSupportedError": "Webcam kann nur über sichere Verbindung freigegeben werden, stellen Sie sicher, dass das SSL-Zertifikat gültig ist", - "app.video.notReadableError": "Konnte nicht auf die Webcam zugreifen. Stellen Sie sicher, dass kein anderes Programm auf die Webcam zugreift", + "app.video.notFoundError": "Konnte keine Webcam finden. Bitte prüfen, dass eine Kamera angeschlossen ist und nicht von einem anderen Programm blockiert wird.", + "app.video.notAllowed": "Fehlende Berechtigung für die Webcamfreigabe. Bitte die Berechtigungen iim Browser prüfen", + "app.video.notSupportedError": "Webcam kann nur über eine sichere Verbindung freigegeben werden, bitte prüfen ob das SSL-Zertifikat gültig ist", + "app.video.notReadableError": "Konnte nicht auf die Webcam zugreifen. Bitte prüfen, dass kein anderes Programm auf die Webcam zugreift", "app.video.timeoutError": "Der Browser hat nicht rechtzeitig reagiert.", - "app.video.genericError": "Ein unbekannter Fehler ist mit dem Gerät aufgetreten (Fehler {0})", - "app.video.mediaTimedOutError": "Ihre Webcam-Freigabe wurde unterbrochen. Bitte erneut starten.", + "app.video.genericError": "Ein unbekannter Fehler ist mit der Kamera aufgetreten (Fehler {0})", + "app.video.mediaTimedOutError": "Die Webcam-Freigabe wurde unterbrochen. Bitte erneut starten.", "app.video.mediaFlowTimeout1020": "Verbindung zum Server konnte nicht hergestellt werden (Fehler 1020)", "app.video.suggestWebcamLock": "Sperrung der Teilnehmerwebcams aktivieren?", "app.video.suggestWebcamLockReason": "(dies wird die Stabilität der Konferenz erhöhen)", @@ -798,7 +805,7 @@ "app.video.virtualBackground.background": "Hintergrund", "app.video.virtualBackground.genericError": "Virtueller Hintergrund konnte nicht angewendet werden. Bitte erneut versuchen.", "app.video.virtualBackground.camBgAriaDesc": "Setzt den virtuellen Hintergrund der Webcam auf {0}", - "app.video.camCapReached": "Sie können keine weiteren Kameras freigeben", + "app.video.camCapReached": "Es kann keine weitere Kamera freigegeben werden", "app.video.meetingCamCapReached": "Konferenz hat die maximale Anzahl gleichzeitiger Kameras erreicht", "app.video.dropZoneLabel": "Hier loslassen", "app.fullscreenButton.label": "{0} als Vollbild darstellen", @@ -851,7 +858,7 @@ "app.whiteboard.toolbar.fontSize": "Schriftgrößenliste", "app.whiteboard.toolbarAriaLabel": "Präsentationswerkzeuge", "app.feedback.title": "Sie haben sich aus der Konferenz ausgeloggt", - "app.feedback.subtitle": "Wir würden gerne erfahren, wie Sie BigBlueButton finden (optional)", + "app.feedback.subtitle": "Wir würden gerne erfahren ob die Technik geklappt hat (optional)", "app.feedback.textarea": "Wie können wir BigBlueButton verbessern?", "app.feedback.sendFeedback": "Feedback senden", "app.feedback.sendFeedbackDesc": "Feedback abschicken und Konferenz verlassen", @@ -861,12 +868,12 @@ "app.videoDock.webcamFocusDesc": "Ausgewählte Webcam vergrößern", "app.videoDock.webcamUnfocusLabel": "Normalgröße", "app.videoDock.webcamUnfocusDesc": "Ausgewählte Webcam auf Normalgröße verkleinern", - "app.videoDock.webcamPinLabel": "Anheften", - "app.videoDock.webcamPinDesc": "Ausgewählte Webcam anheften", - "app.videoDock.webcamUnpinLabel": "Lösen", - "app.videoDock.webcamUnpinLabelDisabled": "Nur Moderatoren können Teilnehmer lösen", + "app.videoDock.webcamPinLabel": "Kamera anheften", + "app.videoDock.webcamPinDesc": "Ausgewählte Webcam fixieren", + "app.videoDock.webcamUnpinLabel": "Kamera lösen", + "app.videoDock.webcamUnpinLabelDisabled": "Nur Moderator:innen können Teilnehmer:innen lösen", "app.videoDock.webcamUnpinDesc": "Ausgewählte Webcam lösen", - "app.videoDock.autoplayBlockedDesc": "Wir benötigen Ihre Zustimmung, um Ihnen die Webcams anderer Teilnehmer zu zeigen.", + "app.videoDock.autoplayBlockedDesc": "Wir benötigen Ihre/deine Zustimmung, um die Webcams anderer Teilnehmer:innen zu zeigen.", "app.videoDock.autoplayAllowLabel": "Webcams zeigen", "app.invitation.title": "Gruppenraumeinladung", "app.invitation.confirm": "Einladen", @@ -875,7 +882,7 @@ "app.createBreakoutRoom.breakoutRoomLabel": "Gruppenräume {0}", "app.createBreakoutRoom.askToJoin": "Raum beitreten", "app.createBreakoutRoom.generatingURL": "Erzeuge URL", - "app.createBreakoutRoom.generatingURLMessage": "Wir generieren eine Teilnahme-URL für den ausgewählten Gruppenraum. Das kann ein paar Sekunden dauern...", + "app.createBreakoutRoom.generatingURLMessage": "Wir generieren eine Teilnahme-URL für den ausgewählten Gruppenraum. Das kann ein paar Sekunden dauern ...", "app.createBreakoutRoom.duration": "Dauer {0}", "app.createBreakoutRoom.room": "Raum {0}", "app.createBreakoutRoom.notAssigned": "Nicht zugewiesen ({0})", @@ -890,7 +897,7 @@ "app.createBreakoutRoom.randomlyAssign": "Zufällig zuordnen", "app.createBreakoutRoom.randomlyAssignDesc": "Teilnehmer zufällig in Gruppenräume zuordnen", "app.createBreakoutRoom.resetAssignments": "Zuordnungen zurücksetzen", - "app.createBreakoutRoom.resetAssignmentsDesc": "Alle Raumzuordnungen der Teilnehmer zurücksetzen", + "app.createBreakoutRoom.resetAssignmentsDesc": "Alle Raumzuordnungen der Teilnehmer:innen zurücksetzen", "app.createBreakoutRoom.endAllBreakouts": "Alle Gruppenräume beenden", "app.createBreakoutRoom.chatTitleMsgAllRooms": "alle Räume", "app.createBreakoutRoom.msgToBreakoutsSent": "Nachricht wurde an {0} Gruppenräume gesendet", @@ -900,10 +907,10 @@ "app.createBreakoutRoom.minusRoomTime": "Gruppenraumzeit verringern auf", "app.createBreakoutRoom.addRoomTime": "Gruppenraumzeit erhöhen auf", "app.createBreakoutRoom.addParticipantLabel": "+ Teilnehmer hinzufügen", - "app.createBreakoutRoom.freeJoin": "Den Teilnehmern erlauben, sich selbst einen Gruppenraum auszusuchen.", - "app.createBreakoutRoom.leastOneWarnBreakout": "Jedem Gruppenraum muss wenigstens ein Teilnehmer zugeordnet sein.", + "app.createBreakoutRoom.freeJoin": "Erlauben, sich selbst einen Gruppenraum auszusuchen.", + "app.createBreakoutRoom.leastOneWarnBreakout": "Jedem Gruppenraum muss wenigstens ein:e Teilnehmer:in zugeordnet sein.", "app.createBreakoutRoom.minimumDurationWarnBreakout": "Die Mindestdauer für einen Gruppenraum beträgt {0} Minuten.", - "app.createBreakoutRoom.modalDesc": "Tipp: Sie können die Teilnehmer per Drag-and-Drop einem bestimmten Gruppenraum zuweisen.", + "app.createBreakoutRoom.modalDesc": "Tipp: Teilnehmer:in per Drag-and-Drop einem bestimmten Gruppenraum zuweisen.", "app.createBreakoutRoom.roomTime": "{0} Minuten", "app.createBreakoutRoom.numberOfRoomsError": "Die Raumanzahl ist ungültig.", "app.createBreakoutRoom.duplicatedRoomNameError": "Raumname kann nicht doppelt vergeben werden.", @@ -922,18 +929,20 @@ "app.externalVideo.autoPlayWarning": "Video abspielen, um Mediensynchronisation zu aktivieren", "app.externalVideo.refreshLabel": "Videoplayer aktualisieren", "app.externalVideo.fullscreenLabel": "Videoplayer", - "app.externalVideo.noteLabel": "Hinweis: Freigegebene externe Videos werden in der Aufzeichnung nicht angezeigt. YouTube, Vimeo, Instructure Media, Twitch, Dailymotion und Mediendatei-URLs (z.B. https://beispiel.de/xy.mp4) werden unterstützt.", + "app.externalVideo.noteLabel": "Hinweis: Freigegebene externe Videos werden in der Aufzeichnung nicht angezeigt. Unterstützt werden YouTube, Vimeo, Instructure Media, Twitch, Dailymotion und Mediendatei-URLs (z.B. https://beispiel.net/video.mp4) auf einem beliebigen Server oder einer Peertube Instanz.", + "app.externalVideo.subtitlesOn": "Ausschalten", + "app.externalVideo.subtitlesOff": "Einschalten (falls verfügbar)", "app.actionsBar.actionsDropdown.shareExternalVideo": "Externes Video teilen", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "Teilen von externem Video beenden", - "app.iOSWarning.label": "Bitte aktualisieren Sie auf iOS 12.2 oder höher", - "app.legacy.unsupportedBrowser": "Es scheint, dass Ihr verwendeter Browser nicht unterstützt wird. Bitte verwenden Sie {0} oder {1} für volle Unterstützung.", - "app.legacy.upgradeBrowser": "Es sieht so aus, als ob Sie eine veraltete Version eines unterstützten Browsers verwenden. Bitte aktualisieren Sie den Browser für volle Unterstützung.", + "app.iOSWarning.label": "Bitte auf iOS 12.2 oder höher aktualisieren", + "app.legacy.unsupportedBrowser": "Es scheint, dass der verwendete Browser nicht unterstützt wird. Bitte {0} oder {1} verwenden.", + "app.legacy.upgradeBrowser": "Es sieht so aus, als ob eine veraltete Version eines unterstützten Browsers verwendet wird. Bitte den Browser aktualisieren für den vollen Funktionsumfang.", "app.legacy.criosBrowser": "Unter iOS verwenden Sie für optimale Unterstützung bitte Safari.", "app.debugWindow.windowTitle": "Fehlersuche", "app.debugWindow.form.userAgentLabel": "User Agent", "app.debugWindow.form.button.copy": "Kopieren", "app.debugWindow.form.enableAutoarrangeLayoutLabel": "Automatisches Anordnungslayout aktivieren", - "app.debugWindow.form.enableAutoarrangeLayoutDescription": "(es wird deaktiviert, wenn Sie den Webcambereich ziehen oder in der Größe verändern)", + "app.debugWindow.form.enableAutoarrangeLayoutDescription": "(es wird deaktiviert, wenn der Webcambereich gezogen oder in der Größe verändert wird)", "app.debugWindow.form.chatLoggerLabel": "Test der Chatprotokollierungsstufen", "app.debugWindow.form.button.apply": "Anwenden", "app.layout.style.custom": "Benutzerdefiniertes Layout", @@ -952,6 +961,7 @@ "playback.button.search.aria": "Suche", "playback.button.section.aria": "Randabschnitt", "playback.button.swap.aria": "Inhalt umschalten", + "playback.button.theme.aria": "Design wechseln", "playback.error.wrapper.aria": "Fehlerbereich", "playback.loader.wrapper.aria": "Loaderbereich", "playback.player.wrapper.aria": "Playerbereich", @@ -1021,7 +1031,7 @@ "app.learningDashboard.usersTable.userStatusOffline": "Offline", "app.learningDashboard.usersTable.noUsers": "Bisher keine Teilnehmer", "app.learningDashboard.usersTable.name": "Name", - "app.learningDashboard.usersTable.moderator": "Moderator", + "app.learningDashboard.usersTable.moderator": "Moderator:in", "app.learningDashboard.usersTable.pollVotes": "Abstimmungen", "app.learningDashboard.usersTable.join": "Teilnahme", "app.learningDashboard.usersTable.left": "Verlassen", @@ -1035,15 +1045,17 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Vorschaubild der Präsentation", "app.learningDashboard.errors.invalidToken": "Ungültiger Konferenz-Token", "app.learningDashboard.errors.dataUnavailable": "Die Daten sind nicht mehr verfügbar", - "mobileApp.portals.list.empty.label": "Bitte Portale hinzufügen.", + "mobileApp.portals.list.empty.addFirstPortal.label": "Fügen Sie Ihr erstes Portal über die Schaltfläche oben hinzu,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "oder nutzen Sie unseren Demo-Server.", "mobileApp.portals.list.add.button.label": "Neues Portal", "mobileApp.portals.fields.name.label": "Portalname", "mobileApp.portals.fields.name.placeholder": "BigBlueButton Demo", "mobileApp.portals.fields.url.label": "Server-URL", "mobileApp.portals.addPortalPopup.confirm.button.label": "Portal hinzufügen", "mobileApp.portals.drawerNavigation.button.label": "Portale", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Leere Felder", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Name existiert bereits" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Benötigte Felder", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Name existiert bereits", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Fehler beim Laden der Seite - URL und Netzwerkverbindung prüfen" } diff --git a/bigbluebutton-html5/public/locales/dv.json b/bigbluebutton-html5/public/locales/dv.json index 475a076727..5aa1424dbf 100644 --- a/bigbluebutton-html5/public/locales/dv.json +++ b/bigbluebutton-html5/public/locales/dv.json @@ -207,7 +207,7 @@ "app.poll.quickPollTitle": "އަވަސް ވޯޓު", "app.poll.hidePollDesc": "ވޯޓު މެނޫ ޕޭން ފޮރުވާނެ", "app.poll.quickPollInstruction": "ވޯޓު ފެށުމަށްޓަކައި ތިރިން އޮޕްޝަންއެއް ހިޔާރުކުރައްވާ.", - "app.poll.activePollInstruction": "ލައިވްކޮށް ވޯޓުގެ ނަތީއްޖާ ބެއްލެވުމަށް މި ޕޭން ހުޅުވާފައި ބަހައްޓާ. ތައްޔާރުވުމުން، ނަތީއްޖާ ޝާއިއުކޮށް ވޯޓު ބަންދުކުރުމަށް 'ވޯޓުގެ ނަތީއްޖާ ޝާއިއުކުރ' ހިޔާރުކުރައްވާ. ", + "app.poll.activePollInstruction": "ލައިވްކޮށް ވޯޓުގެ ނަތީއްޖާ ބެއްލެވުމަށް މި ޕޭން ހުޅުވާފައި ބަހައްޓާ. ތައްޔާރުވުމުން، ނަތީއްޖާ ޝާއިއުކޮށް ވޯޓު ބަންދުކުރުމަށް 'ވޯޓުގެ ނަތީއްޖާ ޝާއިއުކުރޭ' ހިޔާރުކުރައްވާ. ", "app.poll.dragDropPollInstruction": "ވޯޓުގެ ވެލިއުތައް ފުރުމަށް، ވޯޓުގެ ވެލިއުތައް ހިމެނޭ ޓެކްސްޓް ފައިލެއް ފާހަގަކޮށްފައިވާ ފިލްޑަށް ޑްރޭގްކޮށްލާ", "app.poll.customPollTextArea": "ވޯޓުގެ ވެލިއުތައް ފުރާލާ", "app.poll.backLabel": "ވޯޓެއް ފަށާ", @@ -601,7 +601,6 @@ "app.lock-viewers.button.apply": "ބަދަލު ގެނޭ", "app.lock-viewers.button.cancel": "ކެންސަލްކޮށްލާ", "app.lock-viewers.locked": "ތަޅުލާފައި", - "app.lock-viewers.unlocked": "ތަޅުހުޅުވާފައި", "app.guest-policy.ariaTitle": "މެހެމާނުންގެ ޕޮލިސީ ސެޓިންގސް މޯޑަލް", "app.guest-policy.title": "މެހެމާނުންގެ ޕޮލިސީ", "app.guest-policy.description": "ބައްދަލުވުމުގެ މެހެމާނުންގެ ޕޮލިސީ ޚިޔާރުތައް ބަދަލުކުރޭ", diff --git a/bigbluebutton-html5/public/locales/el_GR.json b/bigbluebutton-html5/public/locales/el_GR.json index d037fe1cbe..41210fb6ac 100644 --- a/bigbluebutton-html5/public/locales/el_GR.json +++ b/bigbluebutton-html5/public/locales/el_GR.json @@ -662,7 +662,6 @@ "app.lock-viewers.button.apply": "Εφαρμογή", "app.lock-viewers.button.cancel": "Ακύρωση", "app.lock-viewers.locked": "Κλειδωμένο", - "app.lock-viewers.unlocked": "Μη Κλειδωμένο", "app.guest-policy.ariaTitle": "Τυπικές ρυθμίσεις πολιτικής για επισκέπτη", "app.guest-policy.title": "Πολιτική επισκεπτών", "app.guest-policy.description": "Αλλαγή ρυθμίσεων πολιτικής συνεδρίας για επισκέπτη", @@ -959,13 +958,9 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Μικρογραφία παρουσίασης", "app.learningDashboard.errors.invalidToken": "Μη έγκυρο αναγνωριστικό σύνδεσης", "app.learningDashboard.errors.dataUnavailable": "Τα δεδομένα δεν είναι πλέον διαθέσιμα", - "mobileApp.portals.list.add.button.label": "Νέα πύλη", "mobileApp.portals.fields.name.label": "Όνομα πύλης", "mobileApp.portals.fields.name.placeholder": "Δοκιμή BigBlueButton", - "mobileApp.portals.fields.url.label": "URL διακομιστή", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Προσθήκη πύλης", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Κενά πεδία", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Το όνομα υπάρχει ήδη" + "mobileApp.portals.fields.url.label": "URL διακομιστή" } diff --git a/bigbluebutton-html5/public/locales/en.json b/bigbluebutton-html5/public/locales/en.json index 036e6a2f80..f0608a2a56 100755 --- a/bigbluebutton-html5/public/locales/en.json +++ b/bigbluebutton-html5/public/locales/en.json @@ -683,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "Toggle Full-screen (Presenter)", "app.shortcut-help.nextSlideDesc": "Next slide (Presenter)", "app.shortcut-help.previousSlideDesc": "Previous slide (Presenter)", + "app.shortcut-help.togglePanKey": "Spacebar", + "app.shortcut-help.toggleFullscreenKey": "Enter", + "app.shortcut-help.nextSlideKey": "Right Arrow", + "app.shortcut-help.previousSlideKey": "Left Arrow", "app.lock-viewers.title": "Lock viewers", "app.lock-viewers.description": "These options enable you to restrict viewers from using specific features.", "app.lock-viewers.featuresLable": "Feature", @@ -926,6 +930,8 @@ "app.externalVideo.refreshLabel": "Refresh Video Player", "app.externalVideo.fullscreenLabel": "Video Player", "app.externalVideo.noteLabel": "Note: Shared external videos will not appear in the recording. YouTube, Vimeo, Instructure Media, Twitch, Dailymotion and media file URLs (e.g. https://example.com/xy.mp4) are supported.", + "app.externalVideo.subtitlesOn": "Turn off", + "app.externalVideo.subtitlesOff": "Turn on (if available)", "app.actionsBar.actionsDropdown.shareExternalVideo": "Share an external video", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "Stop sharing external video", "app.iOSWarning.label": "Please upgrade to iOS 12.2 or higher", @@ -1039,13 +1045,15 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Presentation thumbnail", "app.learningDashboard.errors.invalidToken": "Invalid session token", "app.learningDashboard.errors.dataUnavailable": "Data is no longer available", - "mobileApp.portals.list.empty.label": "Please add portals.", - "mobileApp.portals.list.add.button.label": "New Portal", + "mobileApp.portals.list.empty.addFirstPortal.label": "Add your first portal using the button above,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "or use our demo server.", + "mobileApp.portals.list.add.button.label": "Add portal", "mobileApp.portals.fields.name.label": "Portal Name", "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", "mobileApp.portals.fields.url.label": "Server URL", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Add Portal", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Save", "mobileApp.portals.drawerNavigation.button.label": "Portals", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Empty Fields", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Name Already Exists" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Required Fields", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Name already in use", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Error trying to load the page - check URL and network connection" } diff --git a/bigbluebutton-html5/public/locales/eo.json b/bigbluebutton-html5/public/locales/eo.json index 1f18ec212c..ef04d0b091 100644 --- a/bigbluebutton-html5/public/locales/eo.json +++ b/bigbluebutton-html5/public/locales/eo.json @@ -528,7 +528,6 @@ "app.lock-viewers.button.apply": "Apliki", "app.lock-viewers.button.cancel": "Nuligi", "app.lock-viewers.locked": "Malebligite", - "app.lock-viewers.unlocked": "Ebligite", "app.connection-status.ariaTitle": "Dialogo pri konektostato", "app.connection-status.title": "Konektostato", "app.connection-status.description": "Vidi la konektostaton de uzantoj", diff --git a/bigbluebutton-html5/public/locales/es.json b/bigbluebutton-html5/public/locales/es.json index 1f8ad1fbed..0b72c5fb78 100644 --- a/bigbluebutton-html5/public/locales/es.json +++ b/bigbluebutton-html5/public/locales/es.json @@ -602,7 +602,6 @@ "app.lock-viewers.button.apply": "Aplicar", "app.lock-viewers.button.cancel": "Cancelar", "app.lock-viewers.locked": "Bloqueado", - "app.lock-viewers.unlocked": "Desbloqueado", "app.guest-policy.ariaTitle": "Modo de configuración de la política de invitados", "app.guest-policy.title": "Política de invitados", "app.guest-policy.description": "Cambiar la configuración de la política de invitados a la reunión", diff --git a/bigbluebutton-html5/public/locales/es_ES.json b/bigbluebutton-html5/public/locales/es_ES.json index 7e3021d8af..7426fdc721 100644 --- a/bigbluebutton-html5/public/locales/es_ES.json +++ b/bigbluebutton-html5/public/locales/es_ES.json @@ -600,7 +600,6 @@ "app.lock-viewers.button.apply": "Aplicar", "app.lock-viewers.button.cancel": "Cancelar", "app.lock-viewers.locked": "Bloqueado", - "app.lock-viewers.unlocked": "Desbloqueado", "app.guest-policy.ariaTitle": "Modo de configuración de la política de invitados", "app.guest-policy.title": "Política de invitados", "app.guest-policy.description": "Cambiar la configuración de la política de invitados a la reunión", diff --git a/bigbluebutton-html5/public/locales/et.json b/bigbluebutton-html5/public/locales/et.json index 58d01cbd70..14ae2fbc0c 100644 --- a/bigbluebutton-html5/public/locales/et.json +++ b/bigbluebutton-html5/public/locales/et.json @@ -132,6 +132,8 @@ "app.userList.userOptions.savedNames.title": "Kasutajate nimekiri koosolekul {0} kell {1}", "app.userList.userOptions.sortedFirstName.heading": "Sorteeritult eesnime järgi:", "app.userList.userOptions.sortedLastName.heading": "Sorteeritult perekonnanime järgi:", + "app.userList.userOptions.hideViewersCursor": "Vaatajate kursorid on lukustatud", + "app.userList.userOptions.showViewersCursor": "Vaatajate kursorid on vabastatud", "app.media.label": "Meedia", "app.media.autoplayAlertDesc": "Luba juurdepääs", "app.media.screenshare.start": "Ekraanijagamine algas", @@ -323,7 +325,7 @@ "app.connectingMessage": "Ühendumine...", "app.waitingMessage": "Ühendus katkes. Uus ühendumiskatse {0} sekundi pärast ...", "app.retryNow": "Proovi uuesti kohe", - "app.muteWarning.label": "Klõpsa {0}, et oma vaigistus eemaldada", + "app.muteWarning.label": "Klõpsa {0}, et vaigistus eemaldada", "app.muteWarning.disableMessage": "Vaigistuse alarmid keelatud kuni vaigistuse eemaldamiseni", "app.muteWarning.tooltip": "Klõpsa, et sulgeda ja keelata hoiatus kuni vaigistuse eemaldamiseni", "app.navBar.settingsDropdown.optionsLabel": "Valikud", @@ -562,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "Pane tähele, et veebilehitsejas avaneb dialoogiaken, kus palutakse luba sinu mikrofoni jagamiseks.", "app.audio.audioSettings.microphoneSourceLabel": "Mikrofoni sisend", "app.audio.audioSettings.speakerSourceLabel": "Kõlarite sisend", + "app.audio.audioSettings.testSpeakerLabel": "Testi kõlarit", "app.audio.audioSettings.microphoneStreamLabel": "Audiovoo helitugevus", "app.audio.audioSettings.retryLabel": "Uuesti", "app.audio.listenOnly.backLabel": "Tagasi", @@ -680,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "Lülita täisekraani (Esitleja)", "app.shortcut-help.nextSlideDesc": "Järgmine slaid (Esitleja)", "app.shortcut-help.previousSlideDesc": "Eelmine slaid (Esitleja)", + "app.shortcut-help.togglePanKey": "Tühik", + "app.shortcut-help.toggleFullscreenKey": "Sisesta", + "app.shortcut-help.nextSlideKey": "Nool paremale", + "app.shortcut-help.previousSlideKey": "Nool vasakule", "app.lock-viewers.title": "Lukusta vaatajad", "app.lock-viewers.description": "Need valikud võimaldavad keelata vaatajatel teatud võimalusi kasutada.", "app.lock-viewers.featuresLable": "Võimalus", @@ -695,7 +702,7 @@ "app.lock-viewers.button.apply": "Kinnita", "app.lock-viewers.button.cancel": "Tühista", "app.lock-viewers.locked": "Lukustatud", - "app.lock-viewers.unlocked": "Avatud", + "app.lock-viewers.hideViewersCursor": "Näita teiste vaatajate kursoreid", "app.guest-policy.ariaTitle": "Külaliste reeglite seadistamise aken", "app.guest-policy.title": "Külaliste reeglid", "app.guest-policy.description": "Muuda koosoleku külaliste reegleid", @@ -952,6 +959,7 @@ "playback.button.search.aria": "Otsi", "playback.button.section.aria": "Külgsektsioon", "playback.button.swap.aria": "Vaheta sisu", + "playback.button.theme.aria": "Lülita teemat", "playback.error.wrapper.aria": "Vigade ala", "playback.loader.wrapper.aria": "Laadija ala", "playback.player.wrapper.aria": "Mängija ala", @@ -1035,15 +1043,17 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Esitluse pisipilt", "app.learningDashboard.errors.invalidToken": "Kehtetu sessioonitõend", "app.learningDashboard.errors.dataUnavailable": "Andmed ei ole enam kättesaadavad", - "mobileApp.portals.list.empty.label": "Palun lisa portaal.", - "mobileApp.portals.list.add.button.label": "Uus portaal", + "mobileApp.portals.list.empty.addFirstPortal.label": "Lisa esimene portaal ülaloleva nupuga", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "või kasuta meie demoserverit.", + "mobileApp.portals.list.add.button.label": "Lisa portaal", "mobileApp.portals.fields.name.label": "Portaali nimi", "mobileApp.portals.fields.name.placeholder": "BigBlueButtoni demo", "mobileApp.portals.fields.url.label": "Serveri URL", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Lisa portaal", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Salvesta", "mobileApp.portals.drawerNavigation.button.label": "Portaalid", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Tühjad väljad", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Nimi on juba olemas" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Nõutavad väljad", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Nimi on juba kasutusel", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Viga lehekülje laadimisel - kontrolli aadressi ja võrguühendust" } diff --git a/bigbluebutton-html5/public/locales/eu.json b/bigbluebutton-html5/public/locales/eu.json index f6474b771f..4b3ef8e762 100644 --- a/bigbluebutton-html5/public/locales/eu.json +++ b/bigbluebutton-html5/public/locales/eu.json @@ -6,9 +6,10 @@ "app.chat.disconnected": "Deskonektatuta zaude, mezuak ezin dira bidali", "app.chat.locked": "Txata blokeatuta dago, mezuak ezin dira bidali", "app.chat.inputLabel": "Txatean {0} mezu sartu dira", + "app.chat.inputPlaceholder": "Mezuak {0}", "app.chat.titlePublic": "Txat publikoa", - "app.chat.titlePrivate": "Txat pribatua {0}-(r)ekin", - "app.chat.partnerDisconnected": "{0}-(e)k bilera utzi du", + "app.chat.titlePrivate": "Txat pribatua {0}-ekin", + "app.chat.partnerDisconnected": "{0}-k bilera utzi du", "app.chat.closeChatLabel": "Itxi {0}", "app.chat.hideChatLabel": "Ezkutatu {0}", "app.chat.moreMessages": "Mezu gehiago behean", @@ -43,6 +44,8 @@ "app.captions.menu.previewLabel": "Aurreikusi", "app.captions.menu.cancelLabel": "Utzi", "app.captions.hide": "Ezkutatu azpitituluak", + "app.captions.ownership": "Hartu kontrola", + "app.captions.ownershipTooltip": "{0} azpitituluen jabe gisa hartuko zaituzte", "app.captions.dictationStart": "Hasi diktaketa", "app.captions.dictationStop": "Gelditu diktaketa", "app.captions.dictationOnDesc": "Aktibatu hizketa-ezagutzea", @@ -129,6 +132,8 @@ "app.userList.userOptions.savedNames.title": "Bileraren erabiltzaile zerrenda {0}/{1}", "app.userList.userOptions.sortedFirstName.heading": "Izenaren arabera ordenatuta:", "app.userList.userOptions.sortedLastName.heading": "Abizenaren arabera ordenatuta:", + "app.userList.userOptions.hideViewersCursor": "Ikusleen kurtsoreak blokeatuta daude", + "app.userList.userOptions.showViewersCursor": "Ikusleen kurtsoreak desblokeatuta daude", "app.media.label": "Multimedia", "app.media.autoplayAlertDesc": "Baimendu sartzea", "app.media.screenshare.start": "Pantaila partekatzea hasi da", @@ -196,6 +201,7 @@ "app.presentation.presentationToolbar.fitToWidth": "Doitu zabalera", "app.presentation.presentationToolbar.fitToPage": "Doitu orrira", "app.presentation.presentationToolbar.goToSlide": "{0} diapositiba", + "app.presentation.placeholder": "Une honetan ez dago aurkezpen aktiborik", "app.presentationUploder.title": "Aurkezpena", "app.presentationUploder.message": "Aurkezle gisa edozein bulegoko dokumentu edo PDF fitxategi igotzeko gaitasuna duzu. Emaitzarik onena lortzeko PDF fitxategia gomendatzen dugu. Ziurtatu ezazu aurkezpena hautatuta dagoela eskuinean dagoen kontrol-zirkulua erabiliz.", "app.presentationUploder.extraHint": "GARRANTZITSUA: fitxategi bakoitzak ezin ditu {0} MB eta {1} orrialde baino gehiago izan.", @@ -357,6 +363,7 @@ "app.endMeeting.noLabel": "Ez", "app.about.title": "Honi buruz", "app.about.version": "Bezeroaren bertsioa:", + "app.about.version_label": "BigBlueButton-en bertsioa:", "app.about.copyright": "Copyright:", "app.about.confirmLabel": "Ados", "app.about.confirmDesc": "Ados", @@ -417,6 +424,7 @@ "app.settings.dataSavingTab.description": "Zure banda zabalera aurrezteko, doitu ezazu une honetan erakusten dena.", "app.settings.save-notification.label": "Ezarpenak gorde dira", "app.statusNotifier.lowerHands": "Jaitsi eskuak", + "app.statusNotifier.lowerHandDescOneUser": "Jaitsi {0}-ren eskua", "app.statusNotifier.raisedHandsTitle": "Altxatutako eskuak", "app.statusNotifier.raisedHandDesc": "{0}-k altxatu dute eskua", "app.statusNotifier.raisedHandDescOneUser": "{0} esku altxatuta", @@ -427,7 +435,7 @@ "app.talkingIndicator.isTalking" : "{0} hitz egiten ari da", "app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ hitz egiten ari dira", "app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ hitz egiten ari ziren", - "app.talkingIndicator.wasTalking" : "{0}-(e)k hitz egiteari utzi dio", + "app.talkingIndicator.wasTalking" : "{0}-k hitz egiteari utzi dio", "app.actionsBar.actionsDropdown.actionsLabel": "Ekintzak", "app.actionsBar.actionsDropdown.presentationLabel": "Kudeatu aurkezpenak", "app.actionsBar.actionsDropdown.initPollLabel": "Hasi inkesta bat", @@ -453,7 +461,7 @@ "app.actionsBar.emojiMenu.awayLabel": "Kanpoan", "app.actionsBar.emojiMenu.awayDesc": "Aldatu zure egoera: kanpoan", "app.actionsBar.emojiMenu.raiseHandLabel": "Altxa eskua", - "app.actionsBar.emojiMenu.lowerHandLabel": "Jaitsi eskuka", + "app.actionsBar.emojiMenu.lowerHandLabel": "Jaitsi eskua", "app.actionsBar.emojiMenu.raiseHandDesc": "Altxatu eskua hitza eskatzeko", "app.actionsBar.emojiMenu.neutralLabel": "Zalantzan", "app.actionsBar.emojiMenu.neutralDesc": "Aldatu zure egoera: zalantzan", @@ -498,6 +506,9 @@ "app.breakoutJoinConfirmation.freeJoinMessage": "Aukeratu azpitalde baten gela bertara sartzeko", "app.breakoutTimeRemainingMessage": "Azpitaldearen gelari geratzen zaion denbora: {0}", "app.breakoutWillCloseMessage": "Denbora agortu da. Azpitaldearen gela laster itxiko da", + "app.breakout.dropdown.manageDuration": "Kudeatu iraupena", + "app.breakout.dropdown.destroyAll": "Bukatu azpitaldeak", + "app.breakout.dropdown.options": "Azpitaldeen aukerak", "app.calculatingBreakoutTimeRemaining": "Geratzen den denbora kalkulatzen...", "app.audioModal.ariaTitle": "Erabili audio modala", "app.audioModal.microphoneLabel": "Mikrofonoa", @@ -553,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "Kontuan izan zure nabigatzailean mikrofonoa partekatzeko eskatuko dizun mezu bat agertuko dela.", "app.audio.audioSettings.microphoneSourceLabel": "Mikrofonoaren jatorria", "app.audio.audioSettings.speakerSourceLabel": "Bozgorailuen jatorria", + "app.audio.audioSettings.testSpeakerLabel": "Probatu zure bozgorailua", "app.audio.audioSettings.microphoneStreamLabel": "Zure audioaren bolumena", "app.audio.audioSettings.retryLabel": "Saiatu berriro", "app.audio.listenOnly.backLabel": "Atzera", @@ -609,6 +621,10 @@ "app.guest.guestDeny": "Gonbidatuak uko egin dio bileran sartzeari.", "app.guest.seatWait": "Gonbidatua bilerako aulki baten zain dago.", "app.guest.allow": "Gonbidatua onartu da eta bilerara sartu da", + "app.guest.firstPositionInWaitingQueue": "Ilaran lehena zara!", + "app.guest.positionInWaitingQueue": "Zure uneko posizioa itxaron-ilaran:", + "app.guest.guestInvalid": "Erabiltzaile gonbidatua baliogabea da", + "app.guest.meetingForciblyEnded": "Ezin duzu sartu dagoeneko bukatu-arazi den bilera batean", "app.userList.guest.waitingUsers": "Itxaron zerrenda", "app.userList.guest.waitingUsersTitle": "Erabiltzaileen kudeaketa", "app.userList.guest.optionTitle": "Berrikusi zain dauden erabiltzaileak", @@ -617,11 +633,14 @@ "app.userList.guest.allowEveryone": "Onartu guztiak", "app.userList.guest.denyEveryone": "Ukatu guztiak", "app.userList.guest.pendingUsers": "{0} erabiltzaile zain", + "app.userList.guest.noPendingUsers": "Ez dago zain dagoen erabiltzailerik...", "app.userList.guest.pendingGuestUsers": "{0} gonbidatu zain", "app.userList.guest.pendingGuestAlert": "Saioan sartu da eta zure onarpenaren zain dago", "app.userList.guest.rememberChoice": "Gogoratu aukeratutakoa", "app.userList.guest.emptyMessage": "Une honetan ez dago mezurik", "app.userList.guest.inputPlaceholder": "Mezua gonbidatuen atondorako", + "app.userList.guest.privateInputPlaceholder": "Mezua {0}-rentzat", + "app.userList.guest.privateMessageLabel": "Mezua", "app.userList.guest.acceptLabel": "Onartu", "app.userList.guest.denyLabel": "Ukatu", "app.user-info.title": "Direktorio bilatzea", @@ -634,6 +653,9 @@ "app.toast.meetingMuteOn.label": "Erabiltzaile guztiak isilarazi dira", "app.toast.meetingMuteOff.label": "Bileraren isilaraztea itzali da", "app.toast.setEmoji.raiseHand": "Eskua altxatu duzu", + "app.toast.setEmoji.lowerHand": "Zure eskua jaitsi dute", + "app.toast.promotedLabel": "Moderatzaile rola eman dizute", + "app.toast.demotedLabel": "Ikusle rolera jaitsi zaituzte", "app.notification.recordingStart": "Saio hau grabatzen ari da", "app.notification.recordingStop": "Saioa ez da grabatzen ari", "app.notification.recordingPaused": "Saio hau ez da jada grabatzen ari", @@ -661,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "Aldatu pantaila osoa (aurkezlea)", "app.shortcut-help.nextSlideDesc": "Hurrengo diapositiba (aurkezlea)", "app.shortcut-help.previousSlideDesc": "Aurreko diapositiba (aurkezlea)", + "app.shortcut-help.togglePanKey": "Zuriune-barra", + "app.shortcut-help.toggleFullscreenKey": "Sartu", + "app.shortcut-help.nextSlideKey": "Eskuin gezia", + "app.shortcut-help.previousSlideKey": "Ezker gezia", "app.lock-viewers.title": "Blokeatu ikusleak", "app.lock-viewers.description": "Aukera hauen bidez ikusleen eginbide zehatzak murriztu ditzakezu.", "app.lock-viewers.featuresLable": "Eginbidea", @@ -676,7 +702,7 @@ "app.lock-viewers.button.apply": "Aplikatu", "app.lock-viewers.button.cancel": "Utzi", "app.lock-viewers.locked": "Blokeatua", - "app.lock-viewers.unlocked": "Desblokeatuta", + "app.lock-viewers.hideViewersCursor": "Ikusi beste ikusleen kurtsoreak", "app.guest-policy.ariaTitle": "Gonbidatuen gidalerroen ezarpen modala", "app.guest-policy.title": "Gonbidapen gidalerroak", "app.guest-policy.description": "Aldatu bileraren gonbidapen gidalerroen ezarpenak", @@ -689,15 +715,26 @@ "app.connection-status.description": "Ikusi erabiltzaileen konexio egoera", "app.connection-status.empty": "Une honetan ez dago konexio huts egiteen txostenik", "app.connection-status.more": "gehiago", + "app.connection-status.copy": "Kopiatu estatistikak", "app.connection-status.copied": "Kopiatu dira!", "app.connection-status.jitter": "Bibrazioa", "app.connection-status.label": "Konexioaren egoera", + "app.connection-status.settings": "Zure ezarpenak doitzen", "app.connection-status.no": "Ez", "app.connection-status.notification": "Zure konexioaren galera antzeman da", "app.connection-status.offline": "Lineaz kanpo", + "app.connection-status.audioUploadRate": "Audioaren igoera-tasa", + "app.connection-status.audioDownloadRate": "Audioaren jaitsiera-tasa", + "app.connection-status.videoUploadRate": "Bideoaren igoera-tasa", + "app.connection-status.videoDownloadRate": "Bideoaren jaitsiera-tasa", "app.connection-status.lostPackets": "Pakete galduak", "app.connection-status.usingTurn": "TXANDA erabiltzen", "app.connection-status.yes": "Bai", + "app.connection-status.connectionStats": "Konexioaren estatistikak", + "app.connection-status.myLogs": "Nire erregistroak", + "app.connection-status.sessionLogs": "Saioaren erregistroak", + "app.connection-status.next": "Hurrengo orria", + "app.connection-status.prev": "Aurreko orria", "app.learning-dashboard.label": "Ikaskuntzaren estatistiken panela", "app.learning-dashboard.description": "Ireki arbela erabiltzaileen aktibitateekin", "app.learning-dashboard.clickHereToOpen": "Ireki ikaskuntza estatistiken panela", @@ -768,6 +805,8 @@ "app.video.virtualBackground.background": "Atzeko planoa", "app.video.virtualBackground.genericError": "Kamera efektuaren aplikazioak huts egin du. Saiatu berriro", "app.video.virtualBackground.camBgAriaDesc": "{0} ezartzen du web-kameraren atzeko plano birtuala", + "app.video.camCapReached": "Ezin duzu kamera gehiago partekatu", + "app.video.meetingCamCapReached": "Bilera aldibereko kameren mugara iritsi da", "app.video.dropZoneLabel": "Jaregin hona", "app.fullscreenButton.label": "Jarri {0} pantaila osoan", "app.fullscreenUndoButton.label": "Desegin {0} pantaila osoa", @@ -857,7 +896,11 @@ "app.createBreakoutRoom.durationInMinutes": "Iraupena (minutuak)", "app.createBreakoutRoom.randomlyAssign": "Ausazko esleipena", "app.createBreakoutRoom.randomlyAssignDesc": "Azpitaldeetarako erabiltzaileak ausaz esleitzen ditu", + "app.createBreakoutRoom.resetAssignments": "Berrezarri esleipenak", + "app.createBreakoutRoom.resetAssignmentsDesc": "Berrezarri erabiltzaileen gelaren esleipen guztiak", "app.createBreakoutRoom.endAllBreakouts": "Itxi azpitaldeen gela guztiak", + "app.createBreakoutRoom.chatTitleMsgAllRooms": "gela guztiak", + "app.createBreakoutRoom.msgToBreakoutsSent": "Mezua {0} azpigeletara bidali da", "app.createBreakoutRoom.roomName": "{0} (Gela - {1})", "app.createBreakoutRoom.doneLabel": "Eginda", "app.createBreakoutRoom.nextLabel": "Hurrengoa", @@ -872,6 +915,10 @@ "app.createBreakoutRoom.numberOfRoomsError": "Gela kopurua ez da baliozkoa", "app.createBreakoutRoom.duplicatedRoomNameError": "Gelaren izena ezin da bikoiztu.", "app.createBreakoutRoom.emptyRoomNameError": "Gelaren izena ezin da hutsik utzi.", + "app.createBreakoutRoom.setTimeInMinutes": "Ezarri iraupena (minututan)", + "app.createBreakoutRoom.setTimeLabel": "Aplikatu", + "app.createBreakoutRoom.setTimeCancel": "Utzi", + "app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "Azpitaldeen gelen iraupenak ezin du bilerari geratzen zaion denbora gainditu.", "app.createBreakoutRoom.roomNameInputDesc": "Eguneratzen du azpitaldearen gelaren izena", "app.externalVideo.start": "Partekatu bideo berri bat", "app.externalVideo.title": "Partekatu kanpoko bideo bat", @@ -883,6 +930,8 @@ "app.externalVideo.refreshLabel": "Eguneratu bideo erreproduzigailua", "app.externalVideo.fullscreenLabel": "Bideo erreproduzigailua", "app.externalVideo.noteLabel": "Oharra: kanpoko bideo partekatuak ez dira grabazioan agertuko. YouTube, Vimeo, Instructure Media, Twitch eta Daily Motion eta media fitxategien URLak onartzen dira (adib.. https://example.com/xy.mp4).", + "app.externalVideo.subtitlesOn": "Itzali", + "app.externalVideo.subtitlesOff": "Piztu (ahal bada)", "app.actionsBar.actionsDropdown.shareExternalVideo": "Partekatu kanpoko bideo bat", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "Gelditu kanpoko bideoaren partekatzea", "app.iOSWarning.label": "Eguneratu iOS 12.2 edo berriagora", @@ -912,9 +961,21 @@ "playback.button.search.aria": "Bilatu", "playback.button.section.aria": "Alboko atala", "playback.button.swap.aria": "Aldatu edukia", + "playback.button.theme.aria": "Aldatu itxura", "playback.error.wrapper.aria": "Erroreen eremua", "playback.loader.wrapper.aria": "Kargatzailearen eremua", "playback.player.wrapper.aria": "Erreproduzigailuaren eremua", + "playback.player.about.modal.shortcuts.title": "Laster-teklak", + "playback.player.about.modal.shortcuts.alt": "Alt", + "playback.player.about.modal.shortcuts.shift": "Mayus", + "playback.player.about.modal.shortcuts.fullscreen": "Pantaila osora", + "playback.player.about.modal.shortcuts.play": "Erreproduzitu/Pausatu", + "playback.player.about.modal.shortcuts.section": "Aldatu alboko atala", + "playback.player.about.modal.shortcuts.seek.backward": "Bilatu atzerantz", + "playback.player.about.modal.shortcuts.seek.forward": "Bilatu aurrerantz", + "playback.player.about.modal.shortcuts.skip.next": "Hurrengo diapositiba", + "playback.player.about.modal.shortcuts.skip.previous": "Aurreko diapositiba", + "playback.player.about.modal.shortcuts.swap": "Trukatu edukia", "playback.player.chat.message.poll.name": "Inkestaren emaitza", "playback.player.chat.message.poll.question": "Galdera", "playback.player.chat.message.poll.options": "Aukerak", @@ -923,6 +984,7 @@ "playback.player.chat.message.poll.option.abstention": "Abstentzioa", "playback.player.chat.message.poll.option.true": "Egia", "playback.player.chat.message.poll.option.false": "Gezurra", + "playback.player.chat.message.video.name": "Kanpoko bideoa", "playback.player.chat.wrapper.aria": "Txat eremua", "playback.player.notes.wrapper.aria": "Oharren eremua", "playback.player.presentation.wrapper.aria": "Aurkezpenaren eremua", @@ -930,15 +992,32 @@ "playback.player.search.modal.title": "Bilatu", "playback.player.search.modal.subtitle": "Aurkitu aurkezpenaren diapositiben edukia", "playback.player.thumbnails.wrapper.aria": "Koadro txikien eremua", + "playback.player.webcams.wrapper.aria": "Web-kameren eremua", "app.learningDashboard.dashboardTitle": "Ikaskuntzaren estatistiken panela", + "app.learningDashboard.downloadSessionDataLabel": "Deskargatu saioaren datuak", + "app.learningDashboard.lastUpdatedLabel": "Azken eguneratzea:", + "app.learningDashboard.sessionDataDownloadedLabel": "Deskarga osatu da!", + "app.learningDashboard.shareButton": "Partekatu besterekin", + "app.learningDashboard.shareLinkCopied": "Esteka behar bezala kopiatu da!", "app.learningDashboard.user": "Erabiltzailea", "app.learningDashboard.indicators.meetingStatusEnded": "Bukatua", "app.learningDashboard.indicators.meetingStatusActive": "Aktiboa", "app.learningDashboard.indicators.usersOnline": "Erabiltzaile aktiboak", "app.learningDashboard.indicators.usersTotal": "Erabiltzaileak denetara", "app.learningDashboard.indicators.polls": "Inkestak", + "app.learningDashboard.indicators.timeline": "Denbora-lerroa", "app.learningDashboard.indicators.activityScore": "Jardueraren puntuazioa", "app.learningDashboard.indicators.duration": "Iraupena", + "app.learningDashboard.userDetails.startTime": "Hasiera ordua", + "app.learningDashboard.userDetails.endTime": "Bukaera ordua", + "app.learningDashboard.userDetails.joined": "Barruan", + "app.learningDashboard.userDetails.category": "Kategoria", + "app.learningDashboard.userDetails.average": "Batez beste", + "app.learningDashboard.userDetails.activityPoints": "Aktibitate puntuak", + "app.learningDashboard.userDetails.poll": "Inkesta", + "app.learningDashboard.userDetails.response": "Erantzuna", + "app.learningDashboard.userDetails.mostCommonAnswer": "Erantzun ohikoena", + "app.learningDashboard.userDetails.anonymousAnswer": "Inkesta anonimoa", "app.learningDashboard.usersTable.title": "Ikuspegi orokorra", "app.learningDashboard.usersTable.colOnline": "Lineako denbora", "app.learningDashboard.usersTable.colTalk": "Hizketako denbora", @@ -951,10 +1030,32 @@ "app.learningDashboard.usersTable.userStatusOnline": "Linean", "app.learningDashboard.usersTable.userStatusOffline": "Lineatik kanpo", "app.learningDashboard.usersTable.noUsers": "Oraindik ez dago erabiltzailerik", + "app.learningDashboard.usersTable.name": "Izena", + "app.learningDashboard.usersTable.moderator": "Moderatzailea", + "app.learningDashboard.usersTable.pollVotes": "Botoak", + "app.learningDashboard.usersTable.join": "Sartu", + "app.learningDashboard.usersTable.left": "Irten", + "app.learningDashboard.usersTable.notAvailable": "Erantzunik ez", + "app.learningDashboard.pollsTable.title": "Inkestak", "app.learningDashboard.pollsTable.anonymousAnswer": "Inkesta anonimoa (erantzun azken errenkadan)", "app.learningDashboard.pollsTable.anonymousRowName": "Anonimoa", + "app.learningDashboard.pollsTable.noPollsCreatedHeading": "Ez da inkestarik sortu", + "app.learningDashboard.pollsTable.noPollsCreatedMessage": "Erabiltzaileei inkesta bat bidalitakoan, haien emaitzak zerrenda honetan agertuko dira.", + "app.learningDashboard.statusTimelineTable.title": "Denbora-lerroa", + "app.learningDashboard.statusTimelineTable.thumbnail": "Aurkezpenaren miniaturak", "app.learningDashboard.errors.invalidToken": "Saioaren token baliogabea", - "app.learningDashboard.errors.dataUnavailable": "Datuak ez daude eskuragarri" + "app.learningDashboard.errors.dataUnavailable": "Datuak ez daude eskuragarri", + "mobileApp.portals.list.empty.addFirstPortal.label": "Gehitu zure lehen ataria goiko botoia erabiliz,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "edo erabili gure demo zerbitzaria.", + "mobileApp.portals.list.add.button.label": "Gehitu ataria", + "mobileApp.portals.fields.name.label": "Atariaren izena", + "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", + "mobileApp.portals.fields.url.label": "Zerbitzariaren URLa", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Gorde", + "mobileApp.portals.drawerNavigation.button.label": "Atariak", + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Beharrezko eremuak", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Dagoeneko erabiltzen ari den izena", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Errore bat gertatu da orria kargatzen saiatzean. Egiaztatu URLa eta sareko konexioa" } diff --git a/bigbluebutton-html5/public/locales/fa_IR.json b/bigbluebutton-html5/public/locales/fa_IR.json index 01976c9830..0836f8b4a8 100644 --- a/bigbluebutton-html5/public/locales/fa_IR.json +++ b/bigbluebutton-html5/public/locales/fa_IR.json @@ -653,7 +653,6 @@ "app.lock-viewers.button.apply": "اعمال", "app.lock-viewers.button.cancel": "لغو", "app.lock-viewers.locked": "قفل شده", - "app.lock-viewers.unlocked": "مجاز", "app.guest-policy.ariaTitle": "فرم تنظیمات سیاست پذیرش درخواست ورود کاربران", "app.guest-policy.title": "سیاست پذیرش درخواست ورود کاربران", "app.guest-policy.description": "سیاست پذیرش درخواست ورود کاربران در جلسه را مشخصی کنید", @@ -675,9 +674,9 @@ "app.connection-status.lostPackets": "Lost packets", "app.connection-status.usingTurn": "Using TURN", "app.connection-status.yes": "Yes", - "app.learning-dashboard.label": "داشبورد تحلیل یادگیری", - "app.learning-dashboard.description": "بازکردن پیشخوان اطلاعات و فعالیت های کاربران", - "app.learning-dashboard.clickHereToOpen": "باز کردن داشبورد تحلیل یادگیری", + "app.learning-dashboard.label": "پیشخوان تحلیل یادگیری", + "app.learning-dashboard.description": "باز کردن پیشخوان به همراه فعالیت‌های کاربران", + "app.learning-dashboard.clickHereToOpen": "باز کردن پیشخوان تحلیل یادگیری", "app.recording.startTitle": "شروع ضبط", "app.recording.stopTitle": "مکث ضبط", "app.recording.resumeTitle": "از سر گرفتن ضبط", @@ -920,7 +919,7 @@ "playback.player.search.modal.subtitle": "یافتن محتوای صفحات ارائه شده", "playback.player.thumbnails.wrapper.aria": "محدوده تصاویر بندانگشتی", "playback.player.webcams.wrapper.aria": "ناحیه وب‌کم", - "app.learningDashboard.dashboardTitle": "داشبورد تحلیل یادگیری", + "app.learningDashboard.dashboardTitle": "پیشخوان تحلیل یادگیری", "app.learningDashboard.user": "کاربر", "app.learningDashboard.indicators.meetingStatusEnded": "پایان یافته", "app.learningDashboard.indicators.meetingStatusActive": "فعال", diff --git a/bigbluebutton-html5/public/locales/fr.json b/bigbluebutton-html5/public/locales/fr.json index 22d78382db..71e3d38fad 100644 --- a/bigbluebutton-html5/public/locales/fr.json +++ b/bigbluebutton-html5/public/locales/fr.json @@ -695,7 +695,6 @@ "app.lock-viewers.button.apply": "Appliquer", "app.lock-viewers.button.cancel": "Annuler", "app.lock-viewers.locked": "Verrouillé", - "app.lock-viewers.unlocked": "Déverrouillé", "app.guest-policy.ariaTitle": "Fenêtre des paramètres de gestion des accès", "app.guest-policy.title": "Gestion des accès", "app.guest-policy.description": "Modifier le paramétrage de la gestion des accès à la réunion ", @@ -1035,15 +1034,10 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Vignette de présentation", "app.learningDashboard.errors.invalidToken": "Jeton de session invalide", "app.learningDashboard.errors.dataUnavailable": "Les données ne sont plus disponibles", - "mobileApp.portals.list.empty.label": "Veuillez ajouter des portails.", - "mobileApp.portals.list.add.button.label": "Nouveau portail", "mobileApp.portals.fields.name.label": "Nom du portail", "mobileApp.portals.fields.name.placeholder": "Démo BigBlueButton", "mobileApp.portals.fields.url.label": "URL du serveur", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Ajouter le portail", - "mobileApp.portals.drawerNavigation.button.label": "Portails", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Champs vides", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Nom déjà existant" + "mobileApp.portals.drawerNavigation.button.label": "Portails" } diff --git a/bigbluebutton-html5/public/locales/gl.json b/bigbluebutton-html5/public/locales/gl.json index 7d94022b2f..a5a9578b65 100644 --- a/bigbluebutton-html5/public/locales/gl.json +++ b/bigbluebutton-html5/public/locales/gl.json @@ -132,6 +132,8 @@ "app.userList.userOptions.savedNames.title": "Lista de usuarios en xuntanza {0} en {1}", "app.userList.userOptions.sortedFirstName.heading": "Ordenado por nome:", "app.userList.userOptions.sortedLastName.heading": "Ordenado por apelido:", + "app.userList.userOptions.hideViewersCursor": "Os cursores do espectador están bloqueados", + "app.userList.userOptions.showViewersCursor": "Os cursores do espectador están desbloqueados", "app.media.label": "Multimedia", "app.media.autoplayAlertDesc": "Permitir acceso", "app.media.screenshare.start": "Comezou a pantalla compartida", @@ -562,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "Teña en conta que aparecerá un diálogo no navegador que lle requerira que acepte compartir o seu micrófono", "app.audio.audioSettings.microphoneSourceLabel": "Fonte de micrófono", "app.audio.audioSettings.speakerSourceLabel": "Fonte de altofalante", + "app.audio.audioSettings.testSpeakerLabel": "Probar o seu altofalante", "app.audio.audioSettings.microphoneStreamLabel": "O seu volume do fluxo de son", "app.audio.audioSettings.retryLabel": "Tentar de novo", "app.audio.listenOnly.backLabel": "Atrás", @@ -680,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "Alternar a pantalla completa (presentador)", "app.shortcut-help.nextSlideDesc": "Diapositiva seguinte (Presentador)", "app.shortcut-help.previousSlideDesc": "Diapositiva anterior (Presentador)", + "app.shortcut-help.togglePanKey": "Barra espazadora", + "app.shortcut-help.toggleFullscreenKey": "Intro", + "app.shortcut-help.nextSlideKey": "Frecha dereita", + "app.shortcut-help.previousSlideKey": "Frecha esquerda", "app.lock-viewers.title": "Bloquear aos espectadores", "app.lock-viewers.description": "Estas opcións permítenlle restrinxir aos espectadores o uso de funcións específicas.", "app.lock-viewers.featuresLable": "Función", @@ -695,7 +702,7 @@ "app.lock-viewers.button.apply": "Aplicar", "app.lock-viewers.button.cancel": "Cancelar", "app.lock-viewers.locked": "Bloqueado", - "app.lock-viewers.unlocked": "Desbloqueado", + "app.lock-viewers.hideViewersCursor": "Ver os cursores doutros espectadores", "app.guest-policy.ariaTitle": "Axustes das normas de convidados modais", "app.guest-policy.title": "Normas para os convidados", "app.guest-policy.description": "Cambiar os axustes das normas de convidados á xuntanza", @@ -923,6 +930,8 @@ "app.externalVideo.refreshLabel": "Actualizar o reprodutor de vídeo", "app.externalVideo.fullscreenLabel": "Reprodutor de vídeo", "app.externalVideo.noteLabel": "Nota: os vídeos externos compartidos non aparecerán na gravación. Admítense os URL de YouTube, Vimeo, Instructure Media, Twitch, Daily Motion e ficheiros multimedia (p. ex. https://exemplo.com/xy.mp4).", + "app.externalVideo.subtitlesOn": "Apagar", + "app.externalVideo.subtitlesOff": "Acender (se está dispoñíbel)", "app.actionsBar.actionsDropdown.shareExternalVideo": "Compartir un vídeo externo", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "Deixar de compartir o vídeo externo", "app.iOSWarning.label": "Actualice a iOS 12.2 ou superior", @@ -952,6 +961,7 @@ "playback.button.search.aria": "Buscar", "playback.button.section.aria": "Sección lateral", "playback.button.swap.aria": "Intercambiar o contido", + "playback.button.theme.aria": "Alternar o tema", "playback.error.wrapper.aria": "Área de erro", "playback.loader.wrapper.aria": "Área do cargador", "playback.player.wrapper.aria": "Área do reprodutor", @@ -1035,15 +1045,17 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Miniatura da presentación", "app.learningDashboard.errors.invalidToken": "O testemuño de sesión non é válido", "app.learningDashboard.errors.dataUnavailable": "Os datos xa non están dispoñíbeis", - "mobileApp.portals.list.empty.label": "Engada portais.", - "mobileApp.portals.list.add.button.label": "Novo portal", + "mobileApp.portals.list.empty.addFirstPortal.label": "Engada o seu primeiro portal usando o botón anterior,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "ou use o noso servidor de demostración.", + "mobileApp.portals.list.add.button.label": "Engadir portal", "mobileApp.portals.fields.name.label": "Nome do portal", "mobileApp.portals.fields.name.placeholder": "Demostración de BigBlueButton", "mobileApp.portals.fields.url.label": "URL do servidor", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Engadir portal", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Gardar", "mobileApp.portals.drawerNavigation.button.label": "Portais", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Campos baleiros", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Ese nome xa existe" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Campos obrigatorios", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Ese nome xa está a ser usado", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Produciuse un erro ao tentar cargar a páxina. Comprobe o URL e a conexión de rede" } diff --git a/bigbluebutton-html5/public/locales/he.json b/bigbluebutton-html5/public/locales/he.json index 8a71b02a68..5745c09a5b 100644 --- a/bigbluebutton-html5/public/locales/he.json +++ b/bigbluebutton-html5/public/locales/he.json @@ -428,7 +428,6 @@ "app.lock-viewers.button.apply": "אישור", "app.lock-viewers.button.cancel": "ביטול", "app.lock-viewers.locked": "לא מאופשר", - "app.lock-viewers.unlocked": "מאופשר", "app.recording.startTitle": "התחלת הקלטה", "app.recording.stopTitle": "השהית הקלטה", "app.recording.resumeTitle": "הפעלת הקלטה מחדש", diff --git a/bigbluebutton-html5/public/locales/hr.json b/bigbluebutton-html5/public/locales/hr.json index 0f87d6cb51..5faf202cdc 100644 --- a/bigbluebutton-html5/public/locales/hr.json +++ b/bigbluebutton-html5/public/locales/hr.json @@ -389,7 +389,6 @@ "app.lock-viewers.button.apply": "Primjeni", "app.lock-viewers.button.cancel": "Odustani", "app.lock-viewers.locked": "Zaključano", - "app.lock-viewers.unlocked": "Otključano", "app.guest-policy.button.askModerator": "Pitaj moderatora", "app.guest-policy.button.alwaysAccept": "Uvijek prihvati", "app.guest-policy.button.alwaysDeny": "Uvijek odbij", diff --git a/bigbluebutton-html5/public/locales/hu_HU.json b/bigbluebutton-html5/public/locales/hu_HU.json index 96b9ac784f..092f0d18ac 100644 --- a/bigbluebutton-html5/public/locales/hu_HU.json +++ b/bigbluebutton-html5/public/locales/hu_HU.json @@ -1,29 +1,33 @@ { - "app.home.greeting": "A prezentáció hamarosan elindul ...", + "app.home.greeting": "A prezentáció hamarosan elindul…", "app.chat.submitLabel": "Üzenet küldése", - "app.chat.loading": "Üzenet töltődik: {0}%", - "app.chat.errorMaxMessageLength": "Az üzenet {0} karakterrel hosszabb", - "app.chat.disconnected": "Nem küldhetsz üzenete, mert nem kapcsolódtál", - "app.chat.locked": "Nem küldhetsz üzenetet, mert a beszélgetés zárolt", + "app.chat.loading": "Csevegőüzenetek betöltve: {0}%", + "app.chat.errorMaxMessageLength": "Az üzenet {0} karakterrel hosszabb", + "app.chat.disconnected": "Nincs kapcsolódva, nem küldhetők üzenetek", + "app.chat.locked": "A csevegés zárolt, nem küldhetők üzenetek", "app.chat.inputLabel": "{0}: üzenet érkezett", + "app.chat.inputPlaceholder": "{0} üzenet", "app.chat.titlePublic": "Nyilvános üzenetek", "app.chat.titlePrivate": "Privát üzenetek {0} résztvevővel", "app.chat.partnerDisconnected": "{0} kilépett", "app.chat.closeChatLabel": "{0} bezárása", "app.chat.hideChatLabel": "{0} elrejtése", "app.chat.moreMessages": "További üzenetek lejjebb", - "app.chat.dropdown.options": "Üzenetek beállításai", + "app.chat.dropdown.options": "Üzenetbeállítások", "app.chat.dropdown.clear": "Törlés", "app.chat.dropdown.copy": "Másolás", "app.chat.dropdown.save": "Mentés", "app.chat.label": "Üzenetek", "app.chat.offline": "Offline", "app.chat.pollResult": "Szavazás eredménye", + "app.chat.breakoutDurationUpdated": "A csoportmegbeszélés ideje {0} perc", "app.chat.emptyLogLabel": "Az üzenetek naplója üres", - "app.chat.clearPublicChatMessage": "A nyilvános beszélgetés előzményeit csak Szervező törölheti", + "app.chat.clearPublicChatMessage": "A nyilvános beszélgetés előzményeit csak a szervező törölheti", "app.chat.multi.typing": "Több résztvevő gépel", "app.chat.one.typing": "{0} gépel", "app.chat.two.typing": "{0} és {1} gépel", + "app.chat.copySuccess": "Másolt üzenetátirat", + "app.chat.copyErr": "Üzenetátirat másolása sikertelen", "app.captions.label": "Feliratok", "app.captions.menu.close": "Bezárás", "app.captions.menu.start": "Indítás", @@ -39,10 +43,27 @@ "app.captions.menu.backgroundColor": "Háttérszín", "app.captions.menu.previewLabel": "Előnézet", "app.captions.menu.cancelLabel": "Mégsem", + "app.captions.hide": "Felirat elrejtése", + "app.captions.ownership": "Átvétel", + "app.captions.ownershipTooltip": "{0} feliratok tulajdonosa leszel", + "app.captions.dictationStart": "Diktálás indítása", + "app.captions.dictationStop": "Diktálás befejezése", + "app.captions.dictationOnDesc": "Beszédfelismerés bekapcsolása", + "app.captions.dictationOffDesc": "Beszédfelismerés kikapcsolása", + "app.captions.speech.start": "A beszédfelismerés elindult", + "app.captions.speech.stop": "A beszédfelismerés leállt", + "app.captions.speech.error": "A beszédfelismerő leállt a böngésző inkompatibilitása vagy a csöndes időszak miatt", + "app.textInput.sendLabel": "Küldés", + "app.title.defaultViewLabel": "Alapértelmezett prezentációs nézet", + "app.notes.title": "Megosztott jegyzetek", + "app.notes.label": "Jegyetek", + "app.notes.hide": "Jegyzet elrejtése", + "app.notes.locked": "Zárolt", + "app.pads.hint": "Nyomj Esc-et a szerkesztő eszköztárra fókuszálásához", "app.user.activityCheck": "Felhasználói aktivitás ellenőrzése", "app.user.activityCheck.label": "Ellenőrzi, hogy a felhasználó még az előadás résztvevője-e ({0})", "app.user.activityCheck.check": "Ellenőrzés", - "app.userList.usersTitle": "Résztvevők", + "app.userList.usersTitle": "Felhasználók", "app.userList.participantsTitle": "Résztvevők", "app.userList.messagesTitle": "Üzenetek", "app.userList.notesTitle": "Jegyetek", @@ -52,14 +73,17 @@ "app.userList.you": "Én", "app.userList.locked": "Zárolt", "app.userList.byModerator": "(Szervező)", - "app.userList.label": "Résztvevők", + "app.userList.label": "Résztvevők listája", "app.userList.toggleCompactView.label": "Kompakt nézet be-, kikapcsolása", - "app.userList.moderator": "Szervező", + "app.userList.moderator": "Moderátor", "app.userList.mobile": "Mobil", "app.userList.guest": "Vendég", + "app.userList.sharingWebcam": "Webkamera", "app.userList.menuTitleContext": "Elérhető beállítások", + "app.userList.chatListItem.unreadSingular": "Egy új üzenet", + "app.userList.chatListItem.unreadPlural": "{0} új üzenet", "app.userList.menu.chat.label": "Privát üzenetek indítása", - "app.userList.menu.clearStatus.label": "Hangulatjeled törlése", + "app.userList.menu.clearStatus.label": "Állapot törlése", "app.userList.menu.removeUser.label": "Résztvevő eltávolítása", "app.userList.menu.removeConfirmation.label": "({0}) résztvevő eltávolítása", "app.userlist.menu.removeConfirmation.desc": "A résztvevő újracsatlakozásának megakadályozása.", @@ -69,6 +93,7 @@ "app.userList.menu.webcamUnpin.label": "Résztvevő webkamera feloldás", "app.userList.menu.giveWhiteboardAccess.label" : "Hozzáférést biztosít a táblához", "app.userList.menu.removeWhiteboardAccess.label": "Hozzáférés megvonás a táblától", + "app.userList.menu.ejectUserCameras.label": "Feliratok", "app.userList.userAriaLabel": "{0} {1} {2} állapot {3}", "app.userList.menu.promoteUser.label": "Előléptetés Szervezővé", "app.userList.menu.demoteUser.label": "Lefokozás résztvevővé", @@ -93,6 +118,7 @@ "app.userList.userOptions.disableMic": "A résztvevők mikrofonja le van tiltva", "app.userList.userOptions.disablePrivChat": "A privát üzenetek le van tiltva", "app.userList.userOptions.disablePubChat": "A nyilvános üzenetek le van tiltva", + "app.userList.userOptions.disableNotes": "A megosztott jegyzetek zárolva vannak", "app.userList.userOptions.hideUserList": "A résztvevők nem látják a résztvevői névsort", "app.userList.userOptions.webcamsOnlyForModerator": "Csak Szervezők láthatják a résztvevők webkaméráját (zárolási beállítások miatt)", "app.userList.content.participants.options.clearedStatus": "Az összes résztvevő állapotát sikeresen törölted", @@ -100,15 +126,19 @@ "app.userList.userOptions.enableMic": "A résztvevők mikrofonja engedélyezve van", "app.userList.userOptions.enablePrivChat": "A privát üzenetek engedélyezve van", "app.userList.userOptions.enablePubChat": "A nyilvános üzenetek engedélyezve van", + "app.userList.userOptions.enableNotes": "A megosztott jegyzet engedélyezve van", "app.userList.userOptions.showUserList": "A résztvevők látják a résztvevői névsort", "app.userList.userOptions.enableOnlyModeratorWebcam": "A webkamerád engedélyezve van, így a többiek láthatnak", - "app.userList.userOptions.savedNames.title": "A(z) {0} konferencia résztvevőinek listája, {1}", + "app.userList.userOptions.savedNames.title": "{0} előadás résztvevőinek listája, {1}", "app.userList.userOptions.sortedFirstName.heading": "Keresztnév szerint rendezve:", "app.userList.userOptions.sortedLastName.heading": "Vezetéknév szerint rendezve:", + "app.userList.userOptions.hideViewersCursor": "Résztvevők kurzora zárolva", + "app.userList.userOptions.showViewersCursor": "Résztvevők kurzora nincs zárolva", "app.media.label": "Média", "app.media.autoplayAlertDesc": "Hozzáférés engedélyezése", "app.media.screenshare.start": "A képernyőmegosztás elindult", "app.media.screenshare.end": "A képernyőmegosztás befejeződött", + "app.media.screenshare.endDueToDataSaving": "A képernyőmegosztás leállt adatcsökkentés miatt", "app.media.screenshare.unavailable": "A képernyőmegosztás nem érhető el", "app.media.screenshare.notSupported": "Ez a böngésző nem támogatja a képernyőmegosztást.", "app.media.screenshare.autoplayBlockedDesc": "Az előadó képernyőjének megjelenítéséhez az engedélyedre van szükségünk.", @@ -138,7 +168,15 @@ "app.presentation.slideContent": "Diatartalom", "app.presentation.startSlideContent": "Diatartalom indítása", "app.presentation.endSlideContent": "Diatartalom befejezése", + "app.presentation.changedSlideContent": "A prezentáció váltott a diára: {0}", "app.presentation.emptySlideContent": "A jelenlegi diának nincs tartalma", + "app.presentation.options.fullscreen": "Teljes képernyő", + "app.presentation.options.exitFullscreen": "Teljes képernyő bezárása", + "app.presentation.options.minimize": "Kis méret", + "app.presentation.options.snapshot": "Pillanatkép az aktuális előadásról ", + "app.presentation.options.downloading": "Letöltés...", + "app.presentation.options.downloaded": "Az aktuális előadás letöltve", + "app.presentation.options.downloadFailed": "Az aktuális előadás nem tölthető le", "app.presentation.presentationToolbar.noNextSlideDesc": "Prezentáció vége", "app.presentation.presentationToolbar.noPrevSlideDesc": "Prezentáció eleje", "app.presentation.presentationToolbar.selectLabel": "Dia választása", @@ -163,8 +201,10 @@ "app.presentation.presentationToolbar.fitToWidth": "A szélességhez illeszkedjen", "app.presentation.presentationToolbar.fitToPage": "Az oldalhoz illeszkedjen", "app.presentation.presentationToolbar.goToSlide": "{0}. dia", + "app.presentation.placeholder": "Jelenleg nincs aktív előadás", "app.presentationUploder.title": "Prezentáció", "app.presentationUploder.message": "Előadóként tetszőleges office dokumentumot, illetve PDF fájlt fel tudsz tölteni. A legjobb eredmény érdekében javasoljuk PDF fájl használatát. Kérjük, ellenőrizd, hogy egy prezentációt kiválasztottál a jobb oldalon lévő jelölővel. ", + "app.presentationUploder.extraHint": "FONTOS: egyik fájl sem érheti el {0} MB-ot és {1} oldalt.", "app.presentationUploder.uploadLabel": "Feltöltés", "app.presentationUploder.confirmLabel": "Jóváhagyás", "app.presentationUploder.confirmDesc": "Mentsd a módosításaidat és indítsd a prezentációt", @@ -177,6 +217,7 @@ "app.presentationUploder.fileToUpload": "Feltöltendő ...", "app.presentationUploder.currentBadge": "Jelenlegi", "app.presentationUploder.rejectedError": "A kiválasztott fájl(oka)t visszautasítottuk. Kérjük, ellenőrizd a fájl(ok) típusát.", + "app.presentationUploder.connectionClosedError": "Megszakadt a lassú kapcsolat miatt. Kérem, próbáld újra.", "app.presentationUploder.upload.progress": "({0}%) feltöltve", "app.presentationUploder.upload.413": "A fájl túl nagy, túllépte a maximális {0} MB-ot", "app.presentationUploder.genericError": "Hoppá, valami hiba történt ...", @@ -211,6 +252,7 @@ "app.presentationUploder.clearErrorsDesc": "Hibás feltöltések törlése", "app.presentationUploder.uploadViewTitle": "Bemutató feltöltése", "app.poll.pollPaneTitle": "Szavazás", + "app.poll.enableMultipleResponseLabel": "Több válasz is lehetséges válaszadónként?", "app.poll.quickPollTitle": "Gyorsszavazás", "app.poll.hidePollDesc": "Szavazásmenü-panel elrejtése", "app.poll.quickPollInstruction": "Válassz egy beállítást a szavazás indításához", @@ -238,7 +280,11 @@ "app.poll.secretPoll.label" : "Névtelen szavazás", "app.poll.secretPoll.isSecretLabel": "A szavazás anonim – az egyéni válaszokat nem láthatja.", "app.poll.questionErr": "Kérdés megadása kötelező.", + "app.poll.optionErr": "Szavazási lehetőség beírása", "app.poll.startPollDesc": "Szavazás kezdése", + "app.poll.showRespDesc": "Válaszok beállításainak megjelenítése", + "app.poll.addRespDesc": "Szavazási válaszbemenet hozzáadása", + "app.poll.deleteRespDesc": "{0} lehetőség eltávolítása", "app.poll.t": "Igaz", "app.poll.f": "Hamis", "app.poll.tf": "Igaz / Hamis", @@ -263,6 +309,8 @@ "app.poll.liveResult.usersTitle": "Résztvevők", "app.poll.liveResult.responsesTitle": "Válasz", "app.poll.liveResult.secretLabel": "Ez egy névtelen szavazás. Az egyéni válaszok nem jelennek meg.", + "app.poll.removePollOpt": "{0} szavazási lehetőség eltávolítva", + "app.poll.emptyPollOpt": "Üres", "app.polling.pollingTitle": "Válaszlehetőségek", "app.polling.pollQuestionTitle": "Szavazás kérdése", "app.polling.submitLabel": "Beküldés", @@ -278,6 +326,8 @@ "app.waitingMessage": "Szétkapcsolódtunk. {0} másodperc múlva próbálunk újra csatlakozni ...", "app.retryNow": "Most próbáld újra", "app.muteWarning.label": "{0} kattints, hogy hallható légy!", + "app.muteWarning.disableMessage": "A néma figyelmeztetések tiltva a visszavonásig", + "app.muteWarning.tooltip": "Kattints a figyelmeztetés bezárásához és letiltásához a következő némítás feloldásáig", "app.navBar.settingsDropdown.optionsLabel": "Beállítások", "app.navBar.settingsDropdown.fullscreenLabel": "Teljes képernyő", "app.navBar.settingsDropdown.settingsLabel": "Beállítások", @@ -298,6 +348,7 @@ "app.navBar.userListToggleBtnLabel": "Résztvevői ablak be-, kikapcsolása", "app.navBar.toggleUserList.ariaLabel": "Résztvevők és Üzentek felcserélése", "app.navBar.toggleUserList.newMessages": "új üzenetértesítéssel", + "app.navBar.toggleUserList.newMsgAria": "Új üzenet tőle: {0}", "app.navBar.recording": "Ezt a munkamenetet rögzítjük", "app.navBar.recording.on": "Felvétel", "app.navBar.recording.off": "Nem készül felvétel", @@ -312,6 +363,7 @@ "app.endMeeting.noLabel": "Nem", "app.about.title": "Névjegy", "app.about.version": "Kliens buildszáma:", + "app.about.version_label": "BigBlueButton verzió:", "app.about.copyright": "Copyright:", "app.about.confirmLabel": "OK", "app.about.confirmDesc": "OK", @@ -372,6 +424,7 @@ "app.settings.dataSavingTab.description": "Igazítsd a sávszélességedhez, hogy mi jelenhessen meg a képernyődön.", "app.settings.save-notification.label": "A beállításokat mentettük", "app.statusNotifier.lowerHands": "Kezek leengedése", + "app.statusNotifier.lowerHandDescOneUser": "{0} kezének letétele", "app.statusNotifier.raisedHandsTitle": "Kézfeltartások", "app.statusNotifier.raisedHandDesc": "{0} jelentkeznek", "app.statusNotifier.raisedHandDescOneUser": "{0} jelentkezik", @@ -380,7 +433,7 @@ "app.switch.offLabel": "KI", "app.talkingIndicator.ariaMuteDesc" : "Válasszd ki a némítani kívánt résztvevőt", "app.talkingIndicator.isTalking" : "{0} beszél", - "app.talkingIndicator.moreThanMaxIndicatorsTalking" : "0}+ beszél", + "app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ beszél", "app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ beszélgettek", "app.talkingIndicator.wasTalking" : "{0} befejezte beszédét", "app.actionsBar.actionsDropdown.actionsLabel": "Műveletek", @@ -453,6 +506,9 @@ "app.breakoutJoinConfirmation.freeJoinMessage": "Csoportterem választása", "app.breakoutTimeRemainingMessage": "Csoport hátralévő ideje: {0}", "app.breakoutWillCloseMessage": "Az idő lejárt. A csoportterem hamarosan bezárul", + "app.breakout.dropdown.manageDuration": "Időtartam kezelése", + "app.breakout.dropdown.destroyAll": "Csoporttermek megszüntetése", + "app.breakout.dropdown.options": "Csoporttermek beállításai", "app.calculatingBreakoutTimeRemaining": "Hátralévő idő számítása ...", "app.audioModal.ariaTitle": "Csatlakozás hangablak", "app.audioModal.microphoneLabel": "Mikrofon", @@ -508,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "Kérjük, figyelj, hogy egy ablak fog megjelenni a böngésződben, benne kérés, hogy fogadd el a mikrofonod megosztását.", "app.audio.audioSettings.microphoneSourceLabel": "Mikrofon forrása", "app.audio.audioSettings.speakerSourceLabel": "Hangszóró forrása", + "app.audio.audioSettings.testSpeakerLabel": "Hang tesztelése", "app.audio.audioSettings.microphoneStreamLabel": "A hangstream hangerőd", "app.audio.audioSettings.retryLabel": "Újra", "app.audio.listenOnly.backLabel": "Vissza", @@ -544,6 +601,8 @@ "app.error.408": "Hitelesítés nem sikerült", "app.error.410": "A találkozó véget ért", "app.error.500": "Sajnáljuk, hiba történt", + "app.error.userLoggedOut": "A felhasználónak érvénytelen munkamenet-tokenje van kijelentkezés miatt", + "app.error.ejectedUser": "A felhasználónak érvénytelen munkamenet-tokenje van kizárás miatt", "app.error.userBanned": "A résztvevőt kitiltották", "app.error.leaveLabel": "Bejelentkezés újra", "app.error.fallback.presentation.title": "Hiba lépett fel", @@ -562,6 +621,10 @@ "app.guest.guestDeny": "Sajnálom, a Szervező elutasította a csatlakozásod. Amennyiben úgy gondolod, hogy ez tévedésből történt, kérlek vedd fel a kapcsolatot a szervezővel, hogy tisztázni tudd a helyzetet!", "app.guest.seatWait": "Vendég várakozik csatlakozáshoz", "app.guest.allow": "Vendég csatlakozása jóváhagyva", + "app.guest.firstPositionInWaitingQueue": "Te vagy az első a sorban!", + "app.guest.positionInWaitingQueue": "Jelenlegi helyed a várakozási sorban:", + "app.guest.guestInvalid": "A vendég felhasználó érvénytelen", + "app.guest.meetingForciblyEnded": "Befejezett előadáshoz nem csatlakozhatsz", "app.userList.guest.waitingUsers": "Várakozók", "app.userList.guest.waitingUsersTitle": "Résztvevő kezelés", "app.userList.guest.optionTitle": "Várakozók", @@ -570,11 +633,14 @@ "app.userList.guest.allowEveryone": "Mindenki engedélyezése", "app.userList.guest.denyEveryone": "Mindenki tiltása", "app.userList.guest.pendingUsers": "{0} várakozó szervező", + "app.userList.guest.noPendingUsers": "Egy várakozó vendég sincs...", "app.userList.guest.pendingGuestUsers": "{0} várakozó ", "app.userList.guest.pendingGuestAlert": "csatlakozott a munkamenethez és várakozik a jóváhagyásodra.", "app.userList.guest.rememberChoice": "Választás megjegyzése", "app.userList.guest.emptyMessage": "Jelenleg nincs üzenet", "app.userList.guest.inputPlaceholder": "Üzenet a belépésre várakozóknak", + "app.userList.guest.privateInputPlaceholder": "Üzenet neki: {0}", + "app.userList.guest.privateMessageLabel": "Üzenet", "app.userList.guest.acceptLabel": "Engedélyezés", "app.userList.guest.denyLabel": "Tiltás", "app.user-info.title": "Címtárkeresés", @@ -582,11 +648,14 @@ "app.toast.chat.public": "Új nyilvános üzenet", "app.toast.chat.private": "Új privát üzenet", "app.toast.chat.system": "Rendszer", - "app.toast.clearedEmoji.label": "Hangulatjel(ek) törölve", + "app.toast.clearedEmoji.label": "Hangulatjel-állapot törölve", "app.toast.setEmoji.label": "Hangulatod új állapota {0}", "app.toast.meetingMuteOn.label": "Az összes résztvevőt elnémítottad", "app.toast.meetingMuteOff.label": "A megbeszélés némaságát kikapcsoltad", "app.toast.setEmoji.raiseHand": "Felemelted a kezed", + "app.toast.setEmoji.lowerHand": "Kezedet letették", + "app.toast.promotedLabel": "Moderátorrá léptettek elő", + "app.toast.demotedLabel": "Résztvevővé fokoztak le", "app.notification.recordingStart": "Ezt a munkamenetet rögzítjük", "app.notification.recordingStop": "Ezt a munkamenetet nem rögzítjük", "app.notification.recordingPaused": "Ezt a munkamenetet nem rögzítjük tovább", @@ -614,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "Teljes képernyő váltás (előadó)", "app.shortcut-help.nextSlideDesc": "Következő dia (előadó)", "app.shortcut-help.previousSlideDesc": "Előző dia (előadó)", + "app.shortcut-help.togglePanKey": "Szóköz", + "app.shortcut-help.toggleFullscreenKey": "Enter", + "app.shortcut-help.nextSlideKey": "Jobb nyíl", + "app.shortcut-help.previousSlideKey": "Bal nyíl", "app.lock-viewers.title": "Résztvevők zárolása", "app.lock-viewers.description": "Ezek az opciókkal letilthatod, hogy a résztvevők meghatározott funkciókat használhassanak.", "app.lock-viewers.featuresLable": "Tulajdonság", @@ -624,12 +697,12 @@ "app.lock-viewers.PublicChatLabel": "Nyilvános üzenetek küldése", "app.lock-viewers.PrivateChatLable": "Privát üzenetek küldése", "app.lock-viewers.notesLabel": "Nyilvános megjegyzések módosítása", - "app.lock-viewers.userListLabel": "A Résztvevői lista nyílt", + "app.lock-viewers.userListLabel": "A többi résztvevő megjelenítése a Résztvevői listában", "app.lock-viewers.ariaTitle": "Résztvevők beállításablakának zárolása", "app.lock-viewers.button.apply": "Alkalmaz", "app.lock-viewers.button.cancel": "Mégsem", "app.lock-viewers.locked": "Zárolt", - "app.lock-viewers.unlocked": "Zárolás feloldva", + "app.lock-viewers.hideViewersCursor": "A többi felhasználó kurzorának megtekintése", "app.guest-policy.ariaTitle": "Vendégek fogadása", "app.guest-policy.title": "Vendégek fogadása", "app.guest-policy.description": "Teendő új vendég fogadásakor", @@ -642,14 +715,26 @@ "app.connection-status.description": "Az állapotjel saját interneted minőségéről mutat képet.", "app.connection-status.empty": "Jelenleg nincs kapcsolódási probléma.", "app.connection-status.more": "több", + "app.connection-status.copy": "Statisztikák másolása", "app.connection-status.copied": "Másolva!", "app.connection-status.jitter": "Jitter", "app.connection-status.label": "Kapcsolódás állapota", + "app.connection-status.settings": "Beállításaim alkalmazása", "app.connection-status.no": "Nem", "app.connection-status.notification": "Kapcsolatod szakadozik.", + "app.connection-status.offline": "offline", + "app.connection-status.audioUploadRate": "Hang feltöltési arány", + "app.connection-status.audioDownloadRate": "Hang letöltési arány", + "app.connection-status.videoUploadRate": "Videó feltöltési arány", + "app.connection-status.videoDownloadRate": "Videó letöltési arány", "app.connection-status.lostPackets": "Elvesztett csomag", "app.connection-status.usingTurn": "TURN használat", "app.connection-status.yes": "Igen", + "app.connection-status.connectionStats": "Csatlakozási statisztikák", + "app.connection-status.myLogs": "Naplózásaim", + "app.connection-status.sessionLogs": "Munkamenet-naplók", + "app.connection-status.next": "Következő oldal", + "app.connection-status.prev": "Előző oldal", "app.learning-dashboard.label": "Aktivitáselemzés irányítópult", "app.learning-dashboard.description": "Irányítópult megnyitása a résztvevők tevékenységeivel", "app.learning-dashboard.clickHereToOpen": "Aktivitáselemzés irányítópult megnyitása", @@ -695,6 +780,7 @@ "app.video.notSupportedError": "Csak biztonságok forrásból oszthatsz meg webkamerát, ezért kérjük, ellenőrizd, hogy SSL tanúsítványod érvényes-e", "app.video.notReadableError": "Nem vesszük a webkamera képét. Kérjük, ellenőrizd, hogy másik program ne használja a webkamerát", "app.video.timeoutError": "A böngésző nem válaszolt időben.", + "app.video.genericError": "({0}) eszköz ismeretlen hibát okozott", "app.video.mediaTimedOutError": "A webkamera adatfolyama megszakadt. Próbáld meg újra megosztani", "app.video.mediaFlowTimeout1020": "A média nem éri el a szervert (hiba 1020)", "app.video.suggestWebcamLock": "Érvényesíted a zárolási beállítást a nézők webkameráján?", @@ -713,12 +799,19 @@ "app.video.clientDisconnected": "A webkamerát nem lehet megosztani kapcsolódási problémák miatt", "app.video.virtualBackground.none": "Egyik sem", "app.video.virtualBackground.blur": "Elhomályosít", + "app.video.virtualBackground.home": "Kezdőpont", "app.video.virtualBackground.board": "Tábla", "app.video.virtualBackground.coffeeshop": "Kávézó", "app.video.virtualBackground.background": "Háttér", "app.video.virtualBackground.genericError": "Nem sikerült alkalmazni a kameraeffektust. Próbáld újra.", "app.video.virtualBackground.camBgAriaDesc": "A webkamera virtuális hátterét a következőre állítottad: {0}", + "app.video.camCapReached": "Több webkamerát nem oszthatsz meg", + "app.video.meetingCamCapReached": "Az előadás elérte az egyidőben maximálisan megosztható webkamerák számát.", + "app.video.dropZoneLabel": "Dobja ide", "app.fullscreenButton.label": "{0} teljes képernyős módra állítása", + "app.fullscreenUndoButton.label": "{0} teljes képernyőjének visszaállítása", + "app.switchButton.expandLabel": "Képernyőmegosztási videó kiterjesztése", + "app.switchButton.shrinkLabel": "Képernyőmegosztási videó zsugorítása", "app.sfu.mediaServerConnectionError2000": "Nem sikerült csatlakozni a médiaszerverhez (hiba 2000)", "app.sfu.mediaServerOffline2001": "A médiaszerver ki van kapcsolva. Kérjük, próbálja később. (hiba 2001)", "app.sfu.mediaServerNoResources2002": "A médiaszervernek nincs elérhető erőforrása (hiba 2002)", @@ -731,6 +824,7 @@ "app.meeting.endNotification.ok.label": "OK", "app.whiteboard.annotations.poll": "A szavazás eredményeit sikeresen közzétetted", "app.whiteboard.annotations.pollResult": "Szavazás eredménye", + "app.whiteboard.annotations.noResponses": "Egy válasz sincs", "app.whiteboard.toolbar.tools": "Eszközök", "app.whiteboard.toolbar.tools.hand": "Mozgatás", "app.whiteboard.toolbar.tools.pencil": "Ceruza", @@ -762,6 +856,7 @@ "app.whiteboard.toolbar.palmRejectionOn": "Érintőképernyőn rajzolás elutasítása", "app.whiteboard.toolbar.palmRejectionOff": "Érintőképernyőn rajzolás engedélyezése", "app.whiteboard.toolbar.fontSize": "Betűméretek", + "app.whiteboard.toolbarAriaLabel": "Prezentációs eszköz", "app.feedback.title": "Kiléptél a beszélgetésből", "app.feedback.subtitle": "Örömmel vesszük, ha írsz néhány szót a BigBlueButton használatának tapasztalatairól (nem kötelező)", "app.feedback.textarea": "Hogyan tennéd jobbá a BigBlueButton-t?", @@ -773,7 +868,9 @@ "app.videoDock.webcamFocusDesc": "Fókusz a kiválasztott webkamerára", "app.videoDock.webcamUnfocusLabel": "Fókusz elvétele", "app.videoDock.webcamUnfocusDesc": "Fókusz elvétele a kiválasztott webkameráról", + "app.videoDock.webcamPinLabel": "Kitűzés", "app.videoDock.webcamPinDesc": "Rögzítsd a kiválasztott webkamerát", + "app.videoDock.webcamUnpinLabel": "Kitűzés eltávolítása", "app.videoDock.webcamUnpinLabelDisabled": "Csak Szervezők oldhatják fel a résztvevők rögzítését", "app.videoDock.webcamUnpinDesc": "Oldd fel a kiválasztott webkamerát", "app.videoDock.autoplayBlockedDesc": "Mások webkamerájának a megjelenítéséhez az engedélyedre van szükségünk.", @@ -783,7 +880,9 @@ "app.createBreakoutRoom.title": "Csoporttermek", "app.createBreakoutRoom.ariaTitle": "Csoporttermek elrejtése", "app.createBreakoutRoom.breakoutRoomLabel": "{0} csoportterem", + "app.createBreakoutRoom.askToJoin": "Csatlakozás kérése", "app.createBreakoutRoom.generatingURL": "URL létrehozása", + "app.createBreakoutRoom.generatingURLMessage": "Rövid időn belül legyártjuk a csoportszobához a csatlakozásai linket...", "app.createBreakoutRoom.duration": "{0} időtartam", "app.createBreakoutRoom.room": "{0}. Terem", "app.createBreakoutRoom.notAssigned": "({0}) nincs hozzárendelve", @@ -797,7 +896,11 @@ "app.createBreakoutRoom.durationInMinutes": "Időtartam (percben)", "app.createBreakoutRoom.randomlyAssign": "Véletlenszerű hozzárendelés", "app.createBreakoutRoom.randomlyAssignDesc": "Véletlenszerűen rendeli a résztvevőket a csoportterembe", + "app.createBreakoutRoom.resetAssignments": "Hozzárendelések resztelése", + "app.createBreakoutRoom.resetAssignmentsDesc": "Összes felhasználó szoba összerendelés reszetelése", "app.createBreakoutRoom.endAllBreakouts": "Összes csoportterem bezárása", + "app.createBreakoutRoom.chatTitleMsgAllRooms": "összes szoba", + "app.createBreakoutRoom.msgToBreakoutsSent": "{0} csoportteremnek küldendő üzenet", "app.createBreakoutRoom.roomName": "{0} (Terem - {1})", "app.createBreakoutRoom.doneLabel": "Kész", "app.createBreakoutRoom.nextLabel": "Következő", @@ -810,6 +913,13 @@ "app.createBreakoutRoom.modalDesc": "Tipp: Fogd-és-vidd a résztvevő nevét a kívánt csoportterembe.", "app.createBreakoutRoom.roomTime": "{0} perc", "app.createBreakoutRoom.numberOfRoomsError": "A termek száma érvénytelen.", + "app.createBreakoutRoom.duplicatedRoomNameError": "A szoba neve nem duplikálható.", + "app.createBreakoutRoom.emptyRoomNameError": "A szoba neve nem lehet üres.", + "app.createBreakoutRoom.setTimeInMinutes": "Időtartam beállítása (percben)", + "app.createBreakoutRoom.setTimeLabel": "Alkalmaz", + "app.createBreakoutRoom.setTimeCancel": "Mégsem", + "app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "A csoporttermek nyitvatartási időtartama nem haladhatja meg a megbeszélésből hátralévő időt.", + "app.createBreakoutRoom.roomNameInputDesc": "Csoportterem nevének módosítása", "app.externalVideo.start": "Egy új videó megosztása", "app.externalVideo.title": "Egy külső videó megosztása", "app.externalVideo.input": "Külső videó URL", @@ -817,16 +927,24 @@ "app.externalVideo.urlError": "Ez a videó URL nem támogatott", "app.externalVideo.close": "Bezárás", "app.externalVideo.autoPlayWarning": "Játszd le a videót a médiaszinkronizáció engedélyezéséhez", + "app.externalVideo.refreshLabel": "Videólejátszó frissítése", + "app.externalVideo.fullscreenLabel": "Videólejátszó", "app.externalVideo.noteLabel": "Megjegyzés: A megosztott külső videó nem jelenik meg a felvételen. A YouTube, Vimeo, Instructure Media, Twitch, Daily Motion és média URL-ek (például https://example.com/xy.mp4) támogatottak.", + "app.externalVideo.subtitlesOn": "Kikapcsolás", + "app.externalVideo.subtitlesOff": "Bekapcsolás (ha elérhető)", "app.actionsBar.actionsDropdown.shareExternalVideo": "Egy külső videó megosztása", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "Külső videó megosztásának befejezése", "app.iOSWarning.label": "Frissíts iOS 12.2-re vagy újabbra", "app.legacy.unsupportedBrowser": "Úgy néz ki, hogy a böngésződ nem támogatott. Kérjük, használj {0} vagy {1} böngészőt a teljes támogatás érdekében.", "app.legacy.upgradeBrowser": "Úgy néz ki, hogy a böngésződ egy régi verzióját használod. Kérjük, frissítsd a böngésződet a teljes támogatás érdekében.", "app.legacy.criosBrowser": "iOS-en a teljes támogatáshoz használj Safari böngészőt .", + "app.debugWindow.windowTitle": "Debug", + "app.debugWindow.form.userAgentLabel": "User Agent", "app.debugWindow.form.button.copy": "Másolás", "app.debugWindow.form.enableAutoarrangeLayoutLabel": "Automatikus elrendezés engedélyezése", "app.debugWindow.form.enableAutoarrangeLayoutDescription": "(le van tiltva, hogy húzd vagy átméretezd a webkamerák területét)", + "app.debugWindow.form.chatLoggerLabel": "Tesztüzenet naplózási szintjei", + "app.debugWindow.form.button.apply": "Alkalmaz", "app.layout.style.custom": "Egyéni", "app.layout.style.smart": "Intelligens elrendezés", "app.layout.style.presentationFocus": "Prezentáció a fókuszban", @@ -835,25 +953,109 @@ "app.layout.style.smartPush": "Intelligens elrendezés (mindenkinél kikényszerítve)", "app.layout.style.presentationFocusPush": "Prezentáció a fókuszban (mindenkinél kikényszerítve)", "app.layout.style.videoFocusPush": "Video a fókuszban (mindenkinél kikényszerítve)", + "playback.button.about.aria": "Névjegy", + "playback.button.clear.aria": "Keresés törlése", + "playback.button.close.aria": "Ablak bezárása", + "playback.button.fullscreen.aria": "Teljes képernyős tartalom", + "playback.button.restore.aria": "Tartalom visszaállítása", + "playback.button.search.aria": "Keresés", + "playback.button.section.aria": "Oldalsó rész", + "playback.button.swap.aria": "Tartalom cseréje", + "playback.button.theme.aria": "Téma felcserélése", + "playback.error.wrapper.aria": "Hiba területe", + "playback.loader.wrapper.aria": "Betöltő területe", + "playback.player.wrapper.aria": "Lejátszó területe", + "playback.player.about.modal.shortcuts.title": "Gyorsbillentyűk", + "playback.player.about.modal.shortcuts.alt": "Alt", + "playback.player.about.modal.shortcuts.shift": "Shift", + "playback.player.about.modal.shortcuts.fullscreen": "Teljes képernyő be-ki", + "playback.player.about.modal.shortcuts.play": "Lejátszás/Megállítás", + "playback.player.about.modal.shortcuts.section": "Oldalterület felcserélése", + "playback.player.about.modal.shortcuts.seek.backward": "Visszafelé keresés", + "playback.player.about.modal.shortcuts.seek.forward": "Előre keresés", + "playback.player.about.modal.shortcuts.skip.next": "Következő dia", + "playback.player.about.modal.shortcuts.skip.previous": "Előző dia", + "playback.player.about.modal.shortcuts.swap": "Tartalom cseréje", + "playback.player.chat.message.poll.name": "Szavazás eredménye", + "playback.player.chat.message.poll.question": "Kérdés", + "playback.player.chat.message.poll.options": "Lehetőségek", + "playback.player.chat.message.poll.option.yes": "Igen", + "playback.player.chat.message.poll.option.no": "Nem", + "playback.player.chat.message.poll.option.abstention": "Tartózkodás", + "playback.player.chat.message.poll.option.true": "Igaz", + "playback.player.chat.message.poll.option.false": "Hamis", + "playback.player.chat.message.video.name": "Külső videó", + "playback.player.chat.wrapper.aria": "Csevegés területe", + "playback.player.notes.wrapper.aria": "Jegyzetek területe", + "playback.player.presentation.wrapper.aria": "Prezentáció területe", + "playback.player.screenshare.wrapper.aria": "Képernyőmegosztás területe", + "playback.player.search.modal.title": "Keresés", + "playback.player.search.modal.subtitle": "Prezentációs diák tartalmának keresése ", + "playback.player.thumbnails.wrapper.aria": "Bélyegképek területe", + "playback.player.webcams.wrapper.aria": "Webkamerák területe", "app.learningDashboard.dashboardTitle": "Aktivitáselemzés irányítópult", + "app.learningDashboard.downloadSessionDataLabel": "Munkamenet-adat letöltése", + "app.learningDashboard.lastUpdatedLabel": "Utolsó módosítás időpontja:", + "app.learningDashboard.sessionDataDownloadedLabel": "Letöltve!", + "app.learningDashboard.shareButton": "Megosztás másokkal", + "app.learningDashboard.shareLinkCopied": "A linket sikeresen másolta!", "app.learningDashboard.user": "Résztvevő", + "app.learningDashboard.indicators.meetingStatusEnded": "Lezárult", "app.learningDashboard.indicators.meetingStatusActive": "Aktív", "app.learningDashboard.indicators.usersOnline": "Aktív résztvevők", "app.learningDashboard.indicators.usersTotal": "Résztvevők száma", "app.learningDashboard.indicators.polls": "Szavazások", + "app.learningDashboard.indicators.timeline": "Idővonal", "app.learningDashboard.indicators.activityScore": "Aktivitás pontszám", "app.learningDashboard.indicators.duration": "Időtartam", + "app.learningDashboard.userDetails.startTime": "Kezdő időpont", + "app.learningDashboard.userDetails.endTime": "Záró időpont", + "app.learningDashboard.userDetails.joined": "Csatlakozott", + "app.learningDashboard.userDetails.category": "Kategória", + "app.learningDashboard.userDetails.average": "Átlag", + "app.learningDashboard.userDetails.activityPoints": "Aktivitás pontszámok", + "app.learningDashboard.userDetails.poll": "Szavazás", + "app.learningDashboard.userDetails.response": "Válasz", + "app.learningDashboard.userDetails.mostCommonAnswer": "Leggyakoribb válasz", + "app.learningDashboard.userDetails.anonymousAnswer": "Névtelen szavazás", "app.learningDashboard.usersTable.title": "Áttekintés", "app.learningDashboard.usersTable.colOnline": "Kapcsolódás ideje", "app.learningDashboard.usersTable.colTalk": "Beszélgetés ideje", "app.learningDashboard.usersTable.colWebcam": "Webkamera ideje", "app.learningDashboard.usersTable.colMessages": "Üzenetek", + "app.learningDashboard.usersTable.colEmojis": "Hangulatjelek", "app.learningDashboard.usersTable.colRaiseHands": "Jelentkezések", "app.learningDashboard.usersTable.colActivityScore": "Aktivitás pontszám", "app.learningDashboard.usersTable.colStatus": "Állapot", - "app.learningDashboard.usersTable.userStatusOnline": "Kapcsolódva", + "app.learningDashboard.usersTable.userStatusOnline": "Online", + "app.learningDashboard.usersTable.userStatusOffline": "Offline", "app.learningDashboard.usersTable.noUsers": "Még nincsenek résztvevők", - "app.learningDashboard.pollsTable.anonymousAnswer": "Névtelen szavazás (válaszok az utolsó sorban)" + "app.learningDashboard.usersTable.name": "Név", + "app.learningDashboard.usersTable.moderator": "Moderátor", + "app.learningDashboard.usersTable.pollVotes": "Szavaztok", + "app.learningDashboard.usersTable.join": "Csatlakozás", + "app.learningDashboard.usersTable.left": "Bal", + "app.learningDashboard.usersTable.notAvailable": "N/A", + "app.learningDashboard.pollsTable.title": "Szavazások", + "app.learningDashboard.pollsTable.anonymousAnswer": "Névtelen szavazás (válaszok az utolsó sorban)", + "app.learningDashboard.pollsTable.anonymousRowName": "Névtelen", + "app.learningDashboard.pollsTable.noPollsCreatedHeading": "Egy szavazás sem jött létre", + "app.learningDashboard.pollsTable.noPollsCreatedMessage": "Miután elküldték a szavazást a felhasználóknak, eredményeik megjelennek ebben a listában.", + "app.learningDashboard.statusTimelineTable.title": "Idővonal", + "app.learningDashboard.statusTimelineTable.thumbnail": "Bemutató bélyegképe", + "app.learningDashboard.errors.invalidToken": "Érvénytelen munkamenet-token", + "app.learningDashboard.errors.dataUnavailable": "Az adat többé nem érhető el", + "mobileApp.portals.list.empty.addFirstPortal.label": "Hozd létre az első portálodat az alábbi gombbal,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "vagy használja a demó szerverünket.", + "mobileApp.portals.list.add.button.label": "Portál hozzáadása", + "mobileApp.portals.fields.name.label": "Portál neve", + "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", + "mobileApp.portals.fields.url.label": "Szerver URL-je", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Mentés", + "mobileApp.portals.drawerNavigation.button.label": "Portálok", + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Kötelező mezők", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "A név már használatban van", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Hiba az oldal betöltésekor - ellenőrizd az URL-t és a hálózati kapcsolatot" } diff --git a/bigbluebutton-html5/public/locales/hy.json b/bigbluebutton-html5/public/locales/hy.json index 738c3d8e22..57a34f3b01 100644 --- a/bigbluebutton-html5/public/locales/hy.json +++ b/bigbluebutton-html5/public/locales/hy.json @@ -695,7 +695,6 @@ "app.lock-viewers.button.apply": "Ընդունել", "app.lock-viewers.button.cancel": "Չեղարկել", "app.lock-viewers.locked": "Արգելափակված է", - "app.lock-viewers.unlocked": "Արգելափակված չէ", "app.guest-policy.ariaTitle": "Հյուրերի միանալու կանոնների պատուհան", "app.guest-policy.title": "Հյուրերի միանալու կանոններ", "app.guest-policy.description": "Փոխել հյուրերի միանալու կանոնները", @@ -1035,15 +1034,10 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Ներկայացման պատկեր", "app.learningDashboard.errors.invalidToken": "Սեանսի սխալ թոքեն", "app.learningDashboard.errors.dataUnavailable": "Տվյալներն այլևս հասանելի չեն", - "mobileApp.portals.list.empty.label": "Խնդրում ենք ավելացրեք պորտալներ։", - "mobileApp.portals.list.add.button.label": "Նոր պորտալ", "mobileApp.portals.fields.name.label": "Պորտալի անվանում", "mobileApp.portals.fields.name.placeholder": "Փորձնական", "mobileApp.portals.fields.url.label": "Սերվերի հասցեն", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Ավելացնել պորտալ", - "mobileApp.portals.drawerNavigation.button.label": "Պորտալներ", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Դատարկ դաշտեր", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Անունն արդեն կա" + "mobileApp.portals.drawerNavigation.button.label": "Պորտալներ" } diff --git a/bigbluebutton-html5/public/locales/id.json b/bigbluebutton-html5/public/locales/id.json index ce89967877..07380cf29f 100644 --- a/bigbluebutton-html5/public/locales/id.json +++ b/bigbluebutton-html5/public/locales/id.json @@ -648,7 +648,6 @@ "app.lock-viewers.button.apply": "Terapkan", "app.lock-viewers.button.cancel": "Batalkan", "app.lock-viewers.locked": "Terkunci", - "app.lock-viewers.unlocked": "Tak Terkunci", "app.guest-policy.title": "Kebijakan tamu", "app.guest-policy.description": "Ubah pengaturan kebijakan tamu pertemuan", "app.guest-policy.button.askModerator": "Tanya moderator", diff --git a/bigbluebutton-html5/public/locales/it_IT.json b/bigbluebutton-html5/public/locales/it_IT.json index 0fd27655c9..45947a8ae4 100644 --- a/bigbluebutton-html5/public/locales/it_IT.json +++ b/bigbluebutton-html5/public/locales/it_IT.json @@ -6,6 +6,7 @@ "app.chat.disconnected": "Sei disconnesso, la chat è disattivata.", "app.chat.locked": "La chat è disabilitata, non puoi inviare messaggi.", "app.chat.inputLabel": "Messaggio di input per la chat {0}", + "app.chat.inputPlaceholder": "Messaggio {0}", "app.chat.titlePublic": "Chat pubblica", "app.chat.titlePrivate": "Chat privata con {0}", "app.chat.partnerDisconnected": "{0} ha lasciato il meeting", @@ -162,6 +163,7 @@ "app.presentation.changedSlideContent": "La presentazione ha cambiato diapositiva: {0}", "app.presentation.emptySlideContent": "Nessun contenuto per la slide corrente", "app.presentation.options.fullscreen": "Schermo intero", + "app.presentation.options.exitFullscreen": "Esci da schermo intero", "app.presentation.presentationToolbar.noNextSlideDesc": "Fine della presentazione", "app.presentation.presentationToolbar.noPrevSlideDesc": "Avvia presentazione", "app.presentation.presentationToolbar.selectLabel": "Seleziona slide", @@ -543,6 +545,7 @@ "app.audio.audioSettings.descriptionLabel": "Apparirà una finestra con una richiesta di accedere al tuo microfono.", "app.audio.audioSettings.microphoneSourceLabel": "Sorgente microfono", "app.audio.audioSettings.speakerSourceLabel": "Sorgente uscita audio", + "app.audio.audioSettings.testSpeakerLabel": "Prova gli altoparlanti", "app.audio.audioSettings.microphoneStreamLabel": "Volume del tuo streaming audio", "app.audio.audioSettings.retryLabel": "Riprova", "app.audio.listenOnly.backLabel": "Indietro", @@ -654,6 +657,9 @@ "app.shortcut-help.toggleFullscreen": "Commuta tutto schermo (Presentatore)", "app.shortcut-help.nextSlideDesc": "Slide seguente (Presentatore)", "app.shortcut-help.previousSlideDesc": "Slide precedente (Presentatore)", + "app.shortcut-help.togglePanKey": "Barra spaziatrice", + "app.shortcut-help.nextSlideKey": "Freccia destra", + "app.shortcut-help.previousSlideKey": "Freccia sinistra", "app.lock-viewers.title": "Blocca spettatori", "app.lock-viewers.description": "Queste opzioni ti danno la possibilità di disattivare specifiche funzioni agli utenti", "app.lock-viewers.featuresLable": "Caratteristica", @@ -669,7 +675,6 @@ "app.lock-viewers.button.apply": "Applica", "app.lock-viewers.button.cancel": "Annulla", "app.lock-viewers.locked": "Bloccato", - "app.lock-viewers.unlocked": "Sbloccato", "app.guest-policy.ariaTitle": "Finestra impostazioni regolamento degli ospiti", "app.guest-policy.title": "Regolamento degli ospiti", "app.guest-policy.description": "Modifica impostazioni sulle norme degli ospiti al meeting", @@ -763,6 +768,7 @@ "app.video.virtualBackground.background": "Sfondo", "app.video.virtualBackground.genericError": "Applicazione dell’effetto alla telecamera fallito. Prova di nuovo.", "app.video.virtualBackground.camBgAriaDesc": "Imposta lo sfondo virtuale della webcam su {0}", + "app.video.camCapReached": "Non puoi condividere ulteriori videocamere", "app.video.dropZoneLabel": "Rilascia qui", "app.fullscreenButton.label": "Metti {0} a schermo intero", "app.fullscreenUndoButton.label": "Annulla {0} a schermo intero", @@ -850,6 +856,7 @@ "app.createBreakoutRoom.randomlyAssign": "Assegna casualmente", "app.createBreakoutRoom.randomlyAssignDesc": "Assegna gli utenti in modo casuale alle Stanze Separate", "app.createBreakoutRoom.endAllBreakouts": "Termina tutte le Stanze Separate", + "app.createBreakoutRoom.chatTitleMsgAllRooms": "tutte le stanze", "app.createBreakoutRoom.roomName": "{0} (Stanza - {1})", "app.createBreakoutRoom.doneLabel": "Fatto", "app.createBreakoutRoom.nextLabel": "Prossimo", @@ -864,7 +871,9 @@ "app.createBreakoutRoom.numberOfRoomsError": "Il numero di stanze non è valido.", "app.createBreakoutRoom.duplicatedRoomNameError": "Il nome della stanza non può essere ripetuto.", "app.createBreakoutRoom.emptyRoomNameError": "Il nome della stanza non può essere vuoto.", + "app.createBreakoutRoom.setTimeInMinutes": "Imposta la durata a (minuti)", "app.createBreakoutRoom.setTimeLabel": "Applica", + "app.createBreakoutRoom.setTimeCancel": "Annulla", "app.createBreakoutRoom.roomNameInputDesc": "Aggiorna il nome della Stanza Separata", "app.externalVideo.start": "Condividi un nuovo video", "app.externalVideo.title": "Condividi un video esterno", @@ -908,6 +917,7 @@ "playback.error.wrapper.aria": "Area errori", "playback.loader.wrapper.aria": "Area caricatore", "playback.player.wrapper.aria": "Area riproduttore", + "playback.player.about.modal.shortcuts.title": "Scorciatoie", "playback.player.about.modal.shortcuts.skip.next": "Prossima slide", "playback.player.about.modal.shortcuts.skip.previous": "Slide precedente", "playback.player.chat.message.poll.name": "Risultati sondaggio", @@ -928,6 +938,8 @@ "playback.player.thumbnails.wrapper.aria": "Area miniature", "playback.player.webcams.wrapper.aria": "Area delle webcam", "app.learningDashboard.dashboardTitle": "Pannello di analisi dell'apprendimento", + "app.learningDashboard.sessionDataDownloadedLabel": "Scaricato!", + "app.learningDashboard.shareButton": "Condividi con altri", "app.learningDashboard.user": "Utente", "app.learningDashboard.indicators.meetingStatusEnded": "Terminato", "app.learningDashboard.indicators.meetingStatusActive": "Attivo", diff --git a/bigbluebutton-html5/public/locales/ja.json b/bigbluebutton-html5/public/locales/ja.json index a1049a5b26..7351ca5f60 100644 --- a/bigbluebutton-html5/public/locales/ja.json +++ b/bigbluebutton-html5/public/locales/ja.json @@ -132,6 +132,8 @@ "app.userList.userOptions.savedNames.title": "{0}の会議の{1}のユーザーリスト", "app.userList.userOptions.sortedFirstName.heading": "第一語でソート", "app.userList.userOptions.sortedLastName.heading": "第二語でソート", + "app.userList.userOptions.hideViewersCursor": "ビューアーのカーソルがロックされました", + "app.userList.userOptions.showViewersCursor": "ビューアーのカーソルロックが解除されました", "app.media.label": "メディア", "app.media.autoplayAlertDesc": "アクセス許可", "app.media.screenshare.start": "画面共有を開始しました", @@ -171,7 +173,7 @@ "app.presentation.options.fullscreen": "全画面表示", "app.presentation.options.exitFullscreen": "全画面表示解除", "app.presentation.options.minimize": "最小化", - "app.presentation.options.snapshot": "現在のプレゼンのスナップショット", + "app.presentation.options.snapshot": "スナップショットを撮る", "app.presentation.options.downloading": "ダウンロード中...", "app.presentation.options.downloaded": "プレゼンファイルをダウンロードしました", "app.presentation.options.downloadFailed": "プレゼンファイルがダウンロードできませんでした", @@ -388,7 +390,7 @@ "app.submenu.application.languageLabel": "使用言語", "app.submenu.application.languageOptionLabel": "言語を選択", "app.submenu.application.noLocaleOptionLabel": "アクティブなロケールがありません", - "app.submenu.application.paginationEnabledLabel": "ビデオのページ割", + "app.submenu.application.paginationEnabledLabel": "ビデオのページ付け", "app.submenu.application.layoutOptionLabel": "レイアウトのタイプ", "app.submenu.notification.SectionTitle": "通知", "app.submenu.notification.Desc": "何をどのように通知するかを設定できます。", @@ -437,7 +439,7 @@ "app.actionsBar.actionsDropdown.actionsLabel": "アクション", "app.actionsBar.actionsDropdown.presentationLabel": "プレゼン用ファイルの管理", "app.actionsBar.actionsDropdown.initPollLabel": "投票を初期化", - "app.actionsBar.actionsDropdown.desktopShareLabel": "画面を共有する", + "app.actionsBar.actionsDropdown.desktopShareLabel": "画面を共有", "app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "画面共有ロック", "app.actionsBar.actionsDropdown.stopDesktopShareLabel": "画面共有をやめる", "app.actionsBar.actionsDropdown.presentationDesc": "プレゼンテーションをアップロード", @@ -562,6 +564,7 @@ "app.audio.audioSettings.descriptionLabel": "マイク共有の許可を求めるダイアログがブラウザ内に現われますのでご了承ください。", "app.audio.audioSettings.microphoneSourceLabel": "マイクのソース", "app.audio.audioSettings.speakerSourceLabel": "スピーカーのソース", + "app.audio.audioSettings.testSpeakerLabel": "スピーカーをテストする", "app.audio.audioSettings.microphoneStreamLabel": "音声ストリームの音量", "app.audio.audioSettings.retryLabel": "再試行", "app.audio.listenOnly.backLabel": "戻る", @@ -680,6 +683,10 @@ "app.shortcut-help.toggleFullscreen": "フルスクリーン切り替え(プレゼンターのみ)", "app.shortcut-help.nextSlideDesc": "次のスライド(プレゼンターのみ)", "app.shortcut-help.previousSlideDesc": "前のスライド(プレゼンターのみ)", + "app.shortcut-help.togglePanKey": "スペース", + "app.shortcut-help.toggleFullscreenKey": "エンター", + "app.shortcut-help.nextSlideKey": "右矢印", + "app.shortcut-help.previousSlideKey": "左矢印", "app.lock-viewers.title": "参加者の行動を制限", "app.lock-viewers.description": "こちらの設定で参加者が使える機能を制限できます", "app.lock-viewers.featuresLable": "機能", @@ -695,7 +702,7 @@ "app.lock-viewers.button.apply": "適用", "app.lock-viewers.button.cancel": "キャンセル", "app.lock-viewers.locked": "禁止", - "app.lock-viewers.unlocked": "許可", + "app.lock-viewers.hideViewersCursor": "他のビューアーのカーソルを表示する", "app.guest-policy.ariaTitle": "入室許可設定モーダル", "app.guest-policy.title": "入室許可設定", "app.guest-policy.description": "会議室の入室許可設定を変更する", @@ -708,7 +715,7 @@ "app.connection-status.description": "ユーザーの接続状況の閲覧", "app.connection-status.empty": "現在のところ接続の問題は報告されていません。", "app.connection-status.more": "更に見る", - "app.connection-status.copy": "統計をコピー", + "app.connection-status.copy": "値をコピー", "app.connection-status.copied": "コピーしました!", "app.connection-status.jitter": "ジッター", "app.connection-status.label": "接続状況", @@ -923,6 +930,8 @@ "app.externalVideo.refreshLabel": "ビデオプレイヤーをリフレッシュ", "app.externalVideo.fullscreenLabel": "ビデオプレイヤー", "app.externalVideo.noteLabel": "注意:インターネット上の動画は録画できません。YouTube, Vimeo, Instructure Media, Twitch, Daily Motion, およびメディアファイルのURL(例えばhttps://example.com/xy.mp4)がサポートされています", + "app.externalVideo.subtitlesOn": "消す", + "app.externalVideo.subtitlesOff": "(あれば)表示する", "app.actionsBar.actionsDropdown.shareExternalVideo": "インターネット上の動画を共有", "app.actionsBar.actionsDropdown.stopShareExternalVideo": "動画の共有停止", "app.iOSWarning.label": "iOS 12.2またはそれ以降のバージョンにアップグレードしてください", @@ -940,10 +949,10 @@ "app.layout.style.smart": "スマートレイアウト", "app.layout.style.presentationFocus": "プレゼンにフォーカス", "app.layout.style.videoFocus": "ビデオにフォーカス", - "app.layout.style.customPush": "カスタム(全員に強制)", - "app.layout.style.smartPush": "スマートレイアウト(全員に強制)", - "app.layout.style.presentationFocusPush": "プレゼンにフォーカス(全員に強制)", - "app.layout.style.videoFocusPush": "ビデオにフォーカス(全員に強制)", + "app.layout.style.customPush": "カスタム(全員に適用)", + "app.layout.style.smartPush": "スマートレイアウト(全員に適用)", + "app.layout.style.presentationFocusPush": "プレゼンにフォーカス(全員に適用)", + "app.layout.style.videoFocusPush": "ビデオにフォーカス(全員に適用)", "playback.button.about.aria": "このコンテンツについて", "playback.button.clear.aria": "検索をクリア", "playback.button.close.aria": "モーダルを閉じる", @@ -952,6 +961,7 @@ "playback.button.search.aria": "検索", "playback.button.section.aria": "サイドセクション", "playback.button.swap.aria": "コンテンツの入れ替え", + "playback.button.theme.aria": "テーマの切り替え", "playback.error.wrapper.aria": "エラーエリア", "playback.loader.wrapper.aria": "ローダーエリア", "playback.player.wrapper.aria": "プレイヤーエリア", @@ -1035,15 +1045,17 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "プレゼンのサムネール", "app.learningDashboard.errors.invalidToken": "セッショントークンが無効です", "app.learningDashboard.errors.dataUnavailable": "データはもう閲覧できません", - "mobileApp.portals.list.empty.label": "ポータルを追加してください。", - "mobileApp.portals.list.add.button.label": "新規ポータル", + "mobileApp.portals.list.empty.addFirstPortal.label": "上のボタンで自分のポータルサイトを追加するか、", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "公式のデモサーバーを使用してください。", + "mobileApp.portals.list.add.button.label": "ポータルサイトを追加", "mobileApp.portals.fields.name.label": "ポータルの名前", "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", "mobileApp.portals.fields.url.label": "サーバーのURL", - "mobileApp.portals.addPortalPopup.confirm.button.label": "ポータルを追加", + "mobileApp.portals.addPortalPopup.confirm.button.label": "保存", "mobileApp.portals.drawerNavigation.button.label": "ポータル", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "フィールドを空にする", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "既に同じ名前があります" + "mobileApp.portals.addPortalPopup.validation.emptyFields": "必須項目", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "名前が既に使用されています", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "ウェブページのアクセスに失敗しましたーURLとネットワーク接続を確認してください" } diff --git a/bigbluebutton-html5/public/locales/ka.json b/bigbluebutton-html5/public/locales/ka.json index b816957b5f..cd8121c061 100644 --- a/bigbluebutton-html5/public/locales/ka.json +++ b/bigbluebutton-html5/public/locales/ka.json @@ -539,7 +539,6 @@ "app.lock-viewers.button.apply": "გამოყენება", "app.lock-viewers.button.cancel": "გაუქმება", "app.lock-viewers.locked": "ჩაკეტილია", - "app.lock-viewers.unlocked": "გახსნილია", "app.connection-status.title": "კავშირის სტატუსი", "app.connection-status.more": "მეტი", "app.connection-status.copied": "დაკოპირებულია!", diff --git a/bigbluebutton-html5/public/locales/kn.json b/bigbluebutton-html5/public/locales/kn.json index 5d00413587..7d020b77fc 100644 --- a/bigbluebutton-html5/public/locales/kn.json +++ b/bigbluebutton-html5/public/locales/kn.json @@ -481,7 +481,6 @@ "app.lock-viewers.button.apply": "ಅನ್ವಯಿಸು", "app.lock-viewers.button.cancel": "ರದ್ದುಮಾಡಿ", "app.lock-viewers.locked": "ಲಾಕ್ ಮಾಡಲಾಗಿದೆ", - "app.lock-viewers.unlocked": "ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ", "app.recording.startTitle": "ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸಿ", "app.recording.stopTitle": "ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಿ", "app.recording.resumeTitle": "ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಪುನರಾರಂಭಿಸಿ", diff --git a/bigbluebutton-html5/public/locales/ko_KR.json b/bigbluebutton-html5/public/locales/ko_KR.json index 31aaae7505..fe20ced8d7 100644 --- a/bigbluebutton-html5/public/locales/ko_KR.json +++ b/bigbluebutton-html5/public/locales/ko_KR.json @@ -647,7 +647,6 @@ "app.lock-viewers.button.apply": "적용", "app.lock-viewers.button.cancel": "취소", "app.lock-viewers.locked": "잠김", - "app.lock-viewers.unlocked": "해제", "app.guest-policy.ariaTitle": "참여자 승인 정책 설정 모달", "app.guest-policy.title": "참여자 승인 정책", "app.guest-policy.description": "참여자 승인 정책 변경", diff --git a/bigbluebutton-html5/public/locales/lt_LT.json b/bigbluebutton-html5/public/locales/lt_LT.json index b30a5e770e..e81172758b 100644 --- a/bigbluebutton-html5/public/locales/lt_LT.json +++ b/bigbluebutton-html5/public/locales/lt_LT.json @@ -519,7 +519,6 @@ "app.lock-viewers.button.apply": "Taikyti", "app.lock-viewers.button.cancel": "Atšaukti", "app.lock-viewers.locked": "Užrakinta", - "app.lock-viewers.unlocked": "Atrakinta", "app.connection-status.title": "Ryšio būsena", "app.connection-status.description": "Peržiūrėti naudotojų ryšio būseną", "app.connection-status.more": "daugiau", diff --git a/bigbluebutton-html5/public/locales/lv.json b/bigbluebutton-html5/public/locales/lv.json index 1c6f27ded7..af99851bd0 100644 --- a/bigbluebutton-html5/public/locales/lv.json +++ b/bigbluebutton-html5/public/locales/lv.json @@ -479,7 +479,6 @@ "app.lock-viewers.button.apply": "Pielietot", "app.lock-viewers.button.cancel": "Atcelt", "app.lock-viewers.locked": "Slēgts/bloķēts", - "app.lock-viewers.unlocked": "Atslēgts/nebloķēts", "app.recording.startTitle": "Sākt ierakstu", "app.recording.stopTitle": "Pauzēt ierakstu", "app.recording.resumeTitle": "Turpināt ierakstu", diff --git a/bigbluebutton-html5/public/locales/ml.json b/bigbluebutton-html5/public/locales/ml.json index 53377e811c..2d2a69ece5 100644 --- a/bigbluebutton-html5/public/locales/ml.json +++ b/bigbluebutton-html5/public/locales/ml.json @@ -629,7 +629,6 @@ "app.lock-viewers.button.apply": "പ്രയോഗിക്കുക", "app.lock-viewers.button.cancel": "റദ്ദാക്കുക", "app.lock-viewers.locked": "ലോക്കുചെയ്‌തു", - "app.lock-viewers.unlocked": "അൺലോക്കുചെയ്‌തു", "app.guest-policy.ariaTitle": "അതിഥി നയ ക്രമീകരണ മോഡൽ", "app.guest-policy.title": "അതിഥി നയം", "app.guest-policy.description": "മീറ്റിംഗ് അതിഥി നയ ക്രമീകരണം മാറ്റുക", diff --git a/bigbluebutton-html5/public/locales/nb_NO.json b/bigbluebutton-html5/public/locales/nb_NO.json index ce84e04008..3e388f47de 100644 --- a/bigbluebutton-html5/public/locales/nb_NO.json +++ b/bigbluebutton-html5/public/locales/nb_NO.json @@ -486,7 +486,6 @@ "app.lock-viewers.button.apply": "Bruk", "app.lock-viewers.button.cancel": "Avbryt", "app.lock-viewers.locked": "Låst", - "app.lock-viewers.unlocked": "Opplåst", "app.recording.startTitle": "Start innspilling", "app.recording.stopTitle": "Pause innspilling", "app.recording.resumeTitle": "Gjenoppta innspilling", diff --git a/bigbluebutton-html5/public/locales/nl.json b/bigbluebutton-html5/public/locales/nl.json index d65ea48dec..063e8c6336 100644 --- a/bigbluebutton-html5/public/locales/nl.json +++ b/bigbluebutton-html5/public/locales/nl.json @@ -695,7 +695,6 @@ "app.lock-viewers.button.apply": "Toepassen", "app.lock-viewers.button.cancel": "Annuleren", "app.lock-viewers.locked": "Vergrendeld", - "app.lock-viewers.unlocked": "Ontgrendeld", "app.guest-policy.ariaTitle": "Modale instellingen voor het beleid voor gasten", "app.guest-policy.title": "Beleid voor gasten", "app.guest-policy.description": "Wijzig de instellingen van het beleid voor gasten", @@ -1035,15 +1034,10 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "Presentatie-icoontje", "app.learningDashboard.errors.invalidToken": "Ongeldig sessietoken", "app.learningDashboard.errors.dataUnavailable": "Gegevens niet meer beschikbaar", - "mobileApp.portals.list.empty.label": "Voeg portalen toe.", - "mobileApp.portals.list.add.button.label": "Nieuw portaal", "mobileApp.portals.fields.name.label": "Portaalnaam", "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", "mobileApp.portals.fields.url.label": "Server URL", - "mobileApp.portals.addPortalPopup.confirm.button.label": "Voeg portaal toe", - "mobileApp.portals.drawerNavigation.button.label": "Portalen", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "Lege velden", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Naam bestaat al" + "mobileApp.portals.drawerNavigation.button.label": "Portalen" } diff --git a/bigbluebutton-html5/public/locales/pl_PL.json b/bigbluebutton-html5/public/locales/pl_PL.json index e3a97e6172..3cd3094b40 100644 --- a/bigbluebutton-html5/public/locales/pl_PL.json +++ b/bigbluebutton-html5/public/locales/pl_PL.json @@ -625,7 +625,6 @@ "app.lock-viewers.button.apply": "Zastosuj", "app.lock-viewers.button.cancel": "Anuluj", "app.lock-viewers.locked": "Zablokowane", - "app.lock-viewers.unlocked": "Odblokowane", "app.guest-policy.ariaTitle": "Okno ustawień polityki gości", "app.guest-policy.title": "Polityka gości", "app.guest-policy.description": "Zmień ustawienia polityki gości spotkania", diff --git a/bigbluebutton-html5/public/locales/pt.json b/bigbluebutton-html5/public/locales/pt.json index 9a95c9124f..54f27b0ca1 100644 --- a/bigbluebutton-html5/public/locales/pt.json +++ b/bigbluebutton-html5/public/locales/pt.json @@ -648,7 +648,6 @@ "app.lock-viewers.button.apply": "Aplicar", "app.lock-viewers.button.cancel": "Cancelar", "app.lock-viewers.locked": "Bloqueado", - "app.lock-viewers.unlocked": "Desbloqueado", "app.guest-policy.ariaTitle": "Janela de configurações da política de convidado", "app.guest-policy.title": "Política de convidado", "app.guest-policy.description": "Alterar configuração da política de convidados da sessão", diff --git a/bigbluebutton-html5/public/locales/pt_BR.json b/bigbluebutton-html5/public/locales/pt_BR.json index 92e6d747a3..4f678d38c4 100644 --- a/bigbluebutton-html5/public/locales/pt_BR.json +++ b/bigbluebutton-html5/public/locales/pt_BR.json @@ -6,6 +6,7 @@ "app.chat.disconnected": "Você está desconectado, as mensagens não podem ser enviadas", "app.chat.locked": "O bate-papo está bloqueado, as mensagens não podem ser enviadas", "app.chat.inputLabel": "Entrada de mensagem para o bate-papo {0}", + "app.chat.inputPlaceholder": "Mensagem {0}", "app.chat.titlePublic": "Bate-papo público", "app.chat.titlePrivate": "Bate-papo privado com {0}", "app.chat.partnerDisconnected": "{0} saiu da sessão", @@ -19,6 +20,7 @@ "app.chat.label": "Bate-papo", "app.chat.offline": "Offline", "app.chat.pollResult": "Resultados da enquete", + "app.chat.breakoutDurationUpdated": "Tempo das salas de apoio agora é de {0} minutos", "app.chat.emptyLogLabel": "Registro do bate-papo vazio", "app.chat.clearPublicChatMessage": "O histórico do bate-papo público foi apagado por um moderador", "app.chat.multi.typing": "Múltiplos usuários estão digitando", @@ -41,8 +43,23 @@ "app.captions.menu.backgroundColor": "Cor de fundo", "app.captions.menu.previewLabel": "Visualizar", "app.captions.menu.cancelLabel": "Cancelar", + "app.captions.hide": "Ocultar legendas", + "app.captions.ownership": "Assumir o controle", + "app.captions.ownershipTooltip": "Você recebeu o controle das legendas {0}", + "app.captions.dictationStart": "Iniciar ditado", + "app.captions.dictationStop": "Encerrar ditado", + "app.captions.dictationOnDesc": "Ativar o reconhecimento de fala", + "app.captions.dictationOffDesc": "Desativar o reconhecimento de fala", + "app.captions.speech.start": "Reconhecimento de fala iniciado", + "app.captions.speech.stop": "Reconhecimento de fala encerrado", + "app.captions.speech.error": "O reconhecimento de fala parou devido à incompatibilidade do navegador ou algum tempo de silêncio", "app.textInput.sendLabel": "Enviar", "app.title.defaultViewLabel": "Visualização da apresentação padrão", + "app.notes.title": "Notas compartilhadas", + "app.notes.label": "Notas", + "app.notes.hide": "Ocultar notas", + "app.notes.locked": "Bloqueado", + "app.pads.hint": "Pressione Esc para focar na barra de ferramentas do editor", "app.user.activityCheck": "Verificação de atividade do usuário", "app.user.activityCheck.label": "Verifica se o usuário ainda está na sala ({0})", "app.user.activityCheck.check": "Verificar", @@ -101,6 +118,7 @@ "app.userList.userOptions.disableMic": "Microfones dos participantes estão desabilitados", "app.userList.userOptions.disablePrivChat": "Bate-papo privado está desabilitado", "app.userList.userOptions.disablePubChat": "Bate-papo público está desabilitado", + "app.userList.userOptions.disableNotes": "Notas compartilhadas agora estão bloqueadas", "app.userList.userOptions.hideUserList": "A lista de participantes agora está oculta para os espectadores", "app.userList.userOptions.webcamsOnlyForModerator": "Somente os moderadores podem ver as webcams dos participantes (devido às configurações de bloqueio)", "app.userList.content.participants.options.clearedStatus": "Status de todos os participantes redefinidos", @@ -108,15 +126,19 @@ "app.userList.userOptions.enableMic": "Os participantes podem usar seus microfones", "app.userList.userOptions.enablePrivChat": "Bate-papo privado está liberado", "app.userList.userOptions.enablePubChat": "Bate-papo público está liberado", + "app.userList.userOptions.enableNotes": "Notas compartilhadas estão liberadas", "app.userList.userOptions.showUserList": "A lista de participantes agora está visível aos espectadores", "app.userList.userOptions.enableOnlyModeratorWebcam": "Você pode habilitar sua webcam agora, todo mundo vai ver você", "app.userList.userOptions.savedNames.title": "Lista de usuários na sessão {0} em {1}", "app.userList.userOptions.sortedFirstName.heading": "Ordenado pelo primeiro nome:", "app.userList.userOptions.sortedLastName.heading": "Ordenado pelo último nome:", + "app.userList.userOptions.hideViewersCursor": "Cursores dos participantes estão bloqueados", + "app.userList.userOptions.showViewersCursor": "Cursores dos participantes estão liberados", "app.media.label": "Mídia", "app.media.autoplayAlertDesc": "Permitir acesso", "app.media.screenshare.start": "O compartilhamento de tela foi iniciado", "app.media.screenshare.end": "O compartilhamento de tela foi encerrado", + "app.media.screenshare.endDueToDataSaving": "Compartilhamento de tela parado por economia de dados", "app.media.screenshare.unavailable": "Compartilhamento de tela indisponível", "app.media.screenshare.notSupported": "Compartilhamento de tela não suportado neste navegador.", "app.media.screenshare.autoplayBlockedDesc": "Precisamos da sua permissão para mostrar a tela do apresentador.", @@ -146,7 +168,15 @@ "app.presentation.slideContent": "Conteúdo do slide", "app.presentation.startSlideContent": "Início do conteúdo do slide", "app.presentation.endSlideContent": "Fim do conteúdo do slide", + "app.presentation.changedSlideContent": "Apresentação alterada para o slide: {0}", "app.presentation.emptySlideContent": "Nenhum conteúdo no slide atual", + "app.presentation.options.fullscreen": "Tela cheia", + "app.presentation.options.exitFullscreen": "Sair de tela cheia", + "app.presentation.options.minimize": "Minimizar", + "app.presentation.options.snapshot": "Salvar imagem da apresentação", + "app.presentation.options.downloading": "Downloading...", + "app.presentation.options.downloaded": "Donwload da apresentação atual encerrado", + "app.presentation.options.downloadFailed": "Não foi possível fazer o download da apresentação atual", "app.presentation.presentationToolbar.noNextSlideDesc": "Fim da apresentação", "app.presentation.presentationToolbar.noPrevSlideDesc": "Início da apresentação", "app.presentation.presentationToolbar.selectLabel": "Selecione o slide", @@ -171,8 +201,10 @@ "app.presentation.presentationToolbar.fitToWidth": "Ajustar à largura", "app.presentation.presentationToolbar.fitToPage": "Ajustar à página", "app.presentation.presentationToolbar.goToSlide": "Slide {0}", + "app.presentation.placeholder": "No momento não há apresentação ativa", "app.presentationUploder.title": "Apresentação", "app.presentationUploder.message": "Como apresentador, você pode enviar qualquer documento do Office ou arquivo PDF. Para melhores resultados, recomendamos que se carregue arquivos em PDF. Por favor, certifique-se de que uma apresentação seja selecionada usando a caixa de seleção circular à direita.", + "app.presentationUploder.extraHint": "IMPORTANTE: cada arquivo não pode exceder {0} MB e {1} páginas.", "app.presentationUploder.uploadLabel": "Enviar", "app.presentationUploder.confirmLabel": "Confirmar", "app.presentationUploder.confirmDesc": "Salvar as alterações e inicie a apresentação", @@ -185,6 +217,7 @@ "app.presentationUploder.fileToUpload": "Carregar arquivo...", "app.presentationUploder.currentBadge": "Atual", "app.presentationUploder.rejectedError": "Os arquivos selecionados foram rejeitados. Por favor, verifique os tipos de arquivos permitidos.", + "app.presentationUploder.connectionClosedError": "Interrompido por problemas de conectividade. Por favor tente novamente.", "app.presentationUploder.upload.progress": "Carregando ({0}%)", "app.presentationUploder.upload.413": "O arquivo é muito grande, excedeu o limite de {0} MB", "app.presentationUploder.genericError": "Ops, algo deu errado ...", @@ -219,6 +252,7 @@ "app.presentationUploder.clearErrorsDesc": "Limpar envios de apresentações com falhas", "app.presentationUploder.uploadViewTitle": "Carregar apresentação", "app.poll.pollPaneTitle": "Enquete", + "app.poll.enableMultipleResponseLabel": "Permitir múltiplas respostas por participante?", "app.poll.quickPollTitle": "Enquete rápida", "app.poll.hidePollDesc": "Ocultar menu de enquetes", "app.poll.quickPollInstruction": "Selecione uma opção abaixo para iniciar uma enquete.", @@ -329,6 +363,7 @@ "app.endMeeting.noLabel": "Não", "app.about.title": "Sobre", "app.about.version": "Versão do cliente:", + "app.about.version_label": "Versão do BigBlueButton:", "app.about.copyright": "Copyright:", "app.about.confirmLabel": "OK", "app.about.confirmDesc": "OK", @@ -389,6 +424,7 @@ "app.settings.dataSavingTab.description": "Para economizar o volume de transferência de dados, ajuste o que está sendo exibido no momento.", "app.settings.save-notification.label": "As configurações foram salvas", "app.statusNotifier.lowerHands": "Mãos baixadas", + "app.statusNotifier.lowerHandDescOneUser": "Abaixar a mão de {0}", "app.statusNotifier.raisedHandsTitle": "Mãos levantadas", "app.statusNotifier.raisedHandDesc": "{0} levantaram as mãos", "app.statusNotifier.raisedHandDescOneUser": "{0} levantou a mão", @@ -470,6 +506,9 @@ "app.breakoutJoinConfirmation.freeJoinMessage": "Escolha uma sala de apoio para entrar", "app.breakoutTimeRemainingMessage": "Tempo restante na sala de apoio: {0}", "app.breakoutWillCloseMessage": "Tempo expirado. A sala de apoio será fechada em breve", + "app.breakout.dropdown.manageDuration": "Gerenciar duração", + "app.breakout.dropdown.destroyAll": "Encerrar salas de apoio", + "app.breakout.dropdown.options": "Opções das salas de apoio", "app.calculatingBreakoutTimeRemaining": "Calculando o tempo restante...", "app.audioModal.ariaTitle": "Janela de ativação de áudio", "app.audioModal.microphoneLabel": "Microfone", @@ -581,6 +620,10 @@ "app.guest.guestDeny": "Convidado teve sua entrada negada.", "app.guest.seatWait": "Convidado aguardando uma vaga na reunião.", "app.guest.allow": "Convidado aprovado e sendo redirecionado para a sessão.", + "app.guest.firstPositionInWaitingQueue": "Você é o primeiro da fila!", + "app.guest.positionInWaitingQueue": "Sua posição atual na fila de espera é:", + "app.guest.guestInvalid": "Convidado inválido", + "app.guest.meetingForciblyEnded": "Você não pode acessar uma sessão que já foi encerrada", "app.userList.guest.waitingUsers": "Aguardando", "app.userList.guest.waitingUsersTitle": "Convidados", "app.userList.guest.optionTitle": "Usuários aguardando aprovação", @@ -589,11 +632,14 @@ "app.userList.guest.allowEveryone": "Permitir todos", "app.userList.guest.denyEveryone": "Rejeitar todos", "app.userList.guest.pendingUsers": "{0} usuários aguardando", + "app.userList.guest.noPendingUsers": "Sem usuários aguardando...", "app.userList.guest.pendingGuestUsers": "{0} usuários convidados aguardando", "app.userList.guest.pendingGuestAlert": "entrou na sessão e está aguardando sua aprovação.", "app.userList.guest.rememberChoice": "Lembrar escolha", "app.userList.guest.emptyMessage": "Atualmente não há mensagem", "app.userList.guest.inputPlaceholder": "Mensagem para a sala de espera", + "app.userList.guest.privateInputPlaceholder": "Mensagem para {0}", + "app.userList.guest.privateMessageLabel": "Mensagem", "app.userList.guest.acceptLabel": "Aceitar", "app.userList.guest.denyLabel": "Recusar", "app.user-info.title": "Pesquisa de Diretório", @@ -606,6 +652,9 @@ "app.toast.meetingMuteOn.label": "Todos os participantes foram silenciados", "app.toast.meetingMuteOff.label": "Mudo da sessão desativado", "app.toast.setEmoji.raiseHand": "Você levantou sua mão", + "app.toast.setEmoji.lowerHand": "Sua mão foi abaixada", + "app.toast.promotedLabel": "Você foi promovido para moderador", + "app.toast.demotedLabel": "Você foi despromovido para participante", "app.notification.recordingStart": "Esta sessão está sendo gravada", "app.notification.recordingStop": "Esta sessão não está sendo gravada", "app.notification.recordingPaused": "Esta sessão não está mais sendo gravada", @@ -648,7 +697,7 @@ "app.lock-viewers.button.apply": "Aplicar", "app.lock-viewers.button.cancel": "Cancelar", "app.lock-viewers.locked": "Bloqueado", - "app.lock-viewers.unlocked": "Liberado", + "app.lock-viewers.hideViewersCursor": "Ver os cursores dos outros participantes", "app.guest-policy.ariaTitle": "Janela de configurações da política de convidado", "app.guest-policy.title": "Política de convidado", "app.guest-policy.description": "Alterar configuração da política de convidados da sessão", @@ -661,15 +710,26 @@ "app.connection-status.description": "Mostra o status da conexão dos participantes", "app.connection-status.empty": "Atualmente não há problemas de conexão relatados", "app.connection-status.more": "mais", + "app.connection-status.copy": "Copiar", "app.connection-status.copied": "Copiado!", "app.connection-status.jitter": "Jitter", "app.connection-status.label": "Status da conexão", + "app.connection-status.settings": "Ajustando suas configurações...", "app.connection-status.no": "Não", "app.connection-status.notification": "Sua conexão foi perdida", "app.connection-status.offline": "desconectado", + "app.connection-status.audioUploadRate": "Taxa de upload de áudio", + "app.connection-status.audioDownloadRate": "Taxa de download de áudio", + "app.connection-status.videoUploadRate": "Taxa de upload de vídeo", + "app.connection-status.videoDownloadRate": "Taxa de download de vídeo", "app.connection-status.lostPackets": "Pacotes perdidos", "app.connection-status.usingTurn": "Usando TURN", "app.connection-status.yes": "Sim", + "app.connection-status.connectionStats": "Status da conexão", + "app.connection-status.myLogs": "Meus registros", + "app.connection-status.sessionLogs": "Registros da sessão", + "app.connection-status.next": "Próxima página", + "app.connection-status.prev": "Página anterior", "app.learning-dashboard.label": "Painel Analítico de Aprendizagem", "app.learning-dashboard.description": "Abrir painel com a atividade dos usuários", "app.learning-dashboard.clickHereToOpen": "Abrir Painel Analítico de Aprendizagem", @@ -740,6 +800,8 @@ "app.video.virtualBackground.background": "Fundo", "app.video.virtualBackground.genericError": "Falha ao aplicar efeito de câmera. Tente novamente.", "app.video.virtualBackground.camBgAriaDesc": "Define fundo virtual de camera para {0}", + "app.video.camCapReached": "Você não pode compartilhar mais câmeras", + "app.video.meetingCamCapReached": "A sessão atingiu seu limite de câmeras simultâneas", "app.video.dropZoneLabel": "Largar aqui", "app.fullscreenButton.label": "Alternar {0} para tela cheia", "app.fullscreenUndoButton.label": "Desfazer {0} tela inteira", @@ -829,7 +891,11 @@ "app.createBreakoutRoom.durationInMinutes": "Duração (minutos)", "app.createBreakoutRoom.randomlyAssign": "Atribuir aleatoriamente", "app.createBreakoutRoom.randomlyAssignDesc": "Atribuir usuários em salas de apoio aleatóriamente", + "app.createBreakoutRoom.resetAssignments": "Redefinir atribuições", + "app.createBreakoutRoom.resetAssignmentsDesc": "Redefinir todas atribuições", "app.createBreakoutRoom.endAllBreakouts": "Encerrar todas as salas de apoio", + "app.createBreakoutRoom.chatTitleMsgAllRooms": "todas salas", + "app.createBreakoutRoom.msgToBreakoutsSent": "A mensagem foi enviada para {0} salas de apoio", "app.createBreakoutRoom.roomName": "{0} (Sala - {1})", "app.createBreakoutRoom.doneLabel": "Confirmar", "app.createBreakoutRoom.nextLabel": "Próximo", @@ -844,6 +910,10 @@ "app.createBreakoutRoom.numberOfRoomsError": "O número de salas é inválido.", "app.createBreakoutRoom.duplicatedRoomNameError": "O nome da sala não pode ser duplicado.", "app.createBreakoutRoom.emptyRoomNameError": "O nome da sala não pode estar vazio.", + "app.createBreakoutRoom.setTimeInMinutes": "Definir duração para (minutos)", + "app.createBreakoutRoom.setTimeLabel": "Aplicar", + "app.createBreakoutRoom.setTimeCancel": "Cancelar", + "app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "A duração das salas de apoio não pode exceder o tempo remanescente da sessão.", "app.createBreakoutRoom.roomNameInputDesc": "Atualiza o nome da sala de apoio", "app.externalVideo.start": "Compartilhar vídeo", "app.externalVideo.title": "Compartilhar um vídeo externo", @@ -887,6 +957,17 @@ "playback.error.wrapper.aria": "Área de erro", "playback.loader.wrapper.aria": "Área do carregador", "playback.player.wrapper.aria": "Área do player", + "playback.player.about.modal.shortcuts.title": "Atalhos", + "playback.player.about.modal.shortcuts.alt": "Alt", + "playback.player.about.modal.shortcuts.shift": "Shift", + "playback.player.about.modal.shortcuts.fullscreen": "Alternar tela cheia", + "playback.player.about.modal.shortcuts.play": "Play/Pause", + "playback.player.about.modal.shortcuts.section": "Alternar seção lateral", + "playback.player.about.modal.shortcuts.seek.backward": "Avançar", + "playback.player.about.modal.shortcuts.seek.forward": "Retroceder", + "playback.player.about.modal.shortcuts.skip.next": "Próximo slide", + "playback.player.about.modal.shortcuts.skip.previous": "Slide anterior", + "playback.player.about.modal.shortcuts.swap": "Trocar conteúdo", "playback.player.chat.message.poll.name": "Resultado da enquete", "playback.player.chat.message.poll.question": "Pergunta", "playback.player.chat.message.poll.options": "Opções", @@ -895,6 +976,7 @@ "playback.player.chat.message.poll.option.abstention": "Abstenção", "playback.player.chat.message.poll.option.true": "Verdadeiro", "playback.player.chat.message.poll.option.false": "Falso", + "playback.player.chat.message.video.name": "Vídeo externo", "playback.player.chat.wrapper.aria": "Área do bate-papo", "playback.player.notes.wrapper.aria": "Área das anotações", "playback.player.presentation.wrapper.aria": "Área da apresentação", @@ -902,6 +984,7 @@ "playback.player.search.modal.title": "Procurar", "playback.player.search.modal.subtitle": "Encontre o conteúdo dos slides da apresentação", "playback.player.thumbnails.wrapper.aria": "Área das miniaturas", + "playback.player.webcams.wrapper.aria": "Área das câmeras", "app.learningDashboard.dashboardTitle": "Painel Analítico de Aprendizagem", "app.learningDashboard.user": "Usuário", "app.learningDashboard.indicators.meetingStatusEnded": "Finalizado", @@ -926,7 +1009,18 @@ "app.learningDashboard.pollsTable.anonymousAnswer": "Enquete anônima (respostas na última linha)", "app.learningDashboard.pollsTable.anonymousRowName": "Anônimos", "app.learningDashboard.errors.invalidToken": "Token de sessão inválido", - "app.learningDashboard.errors.dataUnavailable": "Dado indisponível" + "app.learningDashboard.errors.dataUnavailable": "Dado indisponível", + "mobileApp.portals.list.empty.addFirstPortal.label": "Adicione seu primeiro portal utilizando o botão acima,", + "mobileApp.portals.list.empty.orUseOurDemoServer.label": "ou utilize nosso servidor demo.", + "mobileApp.portals.list.add.button.label": "Novo portal", + "mobileApp.portals.fields.name.label": "Nome do portal", + "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", + "mobileApp.portals.fields.url.label": "URL do servidor", + "mobileApp.portals.addPortalPopup.confirm.button.label": "Adicionar portal", + "mobileApp.portals.drawerNavigation.button.label": "Portais", + "mobileApp.portals.addPortalPopup.validation.emptyFields": "Campos obrigatórios", + "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Este nome já está sendo utilizado", + "mobileApp.portals.addPortalPopup.validation.urlInvalid": "Erro ao tentar carregar a página, verifique o endereço e sua conexão com a internet" } diff --git a/bigbluebutton-html5/public/locales/ro_RO.json b/bigbluebutton-html5/public/locales/ro_RO.json index 4d04f778c8..7a4f8c62ff 100644 --- a/bigbluebutton-html5/public/locales/ro_RO.json +++ b/bigbluebutton-html5/public/locales/ro_RO.json @@ -462,7 +462,6 @@ "app.lock-viewers.button.apply": "Aplica", "app.lock-viewers.button.cancel": "Anulare", "app.lock-viewers.locked": "Blocat", - "app.lock-viewers.unlocked": "Deblocat", "app.recording.startTitle": "Porneste inregistrare", "app.recording.stopTitle": "Pauza inregistrare", "app.recording.resumeTitle": "Reporneste inregistrare", diff --git a/bigbluebutton-html5/public/locales/ru.json b/bigbluebutton-html5/public/locales/ru.json index 3c8f66471e..061db7271b 100644 --- a/bigbluebutton-html5/public/locales/ru.json +++ b/bigbluebutton-html5/public/locales/ru.json @@ -560,6 +560,7 @@ "app.audio.audioSettings.descriptionLabel": "Вам будет показан запрос на разрешение использование вашего микрофона", "app.audio.audioSettings.microphoneSourceLabel": "Микрофон", "app.audio.audioSettings.speakerSourceLabel": "Динамики", + "app.audio.audioSettings.testSpeakerLabel": "Проверить динамики", "app.audio.audioSettings.microphoneStreamLabel": "Громкость вашего аудио-потока", "app.audio.audioSettings.retryLabel": "Повторить", "app.audio.listenOnly.backLabel": "Назад", @@ -693,7 +694,6 @@ "app.lock-viewers.button.apply": "Применить", "app.lock-viewers.button.cancel": "Отмена", "app.lock-viewers.locked": "Заблокировано", - "app.lock-viewers.unlocked": "Разблокирован", "app.guest-policy.ariaTitle": "Окно настроек для правил входа гостей в конференцию", "app.guest-policy.title": "Правила входа гостей в конференцию", "app.guest-policy.description": "Изменить правила входа гостей в конференцию", @@ -797,6 +797,7 @@ "app.video.virtualBackground.genericError": "Ошибка при применении эффекта для камеры. Попробуйте ещё раз.", "app.video.virtualBackground.camBgAriaDesc": "Установка виртуального фона веб-камеры на {0}", "app.video.camCapReached": "Вы не можете предоставить больше камер", + "app.video.meetingCamCapReached": "В этой конференции включено максимальное количество веб-камер", "app.video.dropZoneLabel": "Перенесите файл сюда", "app.fullscreenButton.label": "Включить {0} на полный экран", "app.fullscreenUndoButton.label": "Отменить {0} полноэкранный режим", diff --git a/bigbluebutton-html5/public/locales/sk_SK.json b/bigbluebutton-html5/public/locales/sk_SK.json index 70fc8c5c64..6b44b3ca01 100644 --- a/bigbluebutton-html5/public/locales/sk_SK.json +++ b/bigbluebutton-html5/public/locales/sk_SK.json @@ -590,7 +590,6 @@ "app.lock-viewers.button.apply": "Aplikovať", "app.lock-viewers.button.cancel": "Zrušiť", "app.lock-viewers.locked": "Uzamknuté", - "app.lock-viewers.unlocked": "Odomknuté", "app.guest-policy.ariaTitle": "Nastavenia pravidiel pre hostí sú modálne", "app.guest-policy.title": "Pravidlá pre hostí", "app.guest-policy.description": "Zmeniť nastavenia pravidiel pre hostí", diff --git a/bigbluebutton-html5/public/locales/sl.json b/bigbluebutton-html5/public/locales/sl.json index fb21a9b15e..9ac48f7cb2 100644 --- a/bigbluebutton-html5/public/locales/sl.json +++ b/bigbluebutton-html5/public/locales/sl.json @@ -519,7 +519,6 @@ "app.lock-viewers.button.apply": "Potrdi", "app.lock-viewers.button.cancel": "Prekliči", "app.lock-viewers.locked": "Zaklenjeno", - "app.lock-viewers.unlocked": "Odklenjeno", "app.connection-status.ariaTitle": "Okno stanja povezave", "app.connection-status.title": "Stanje povezave", "app.connection-status.description": "Pokaži stanje povezave uporabnika", diff --git a/bigbluebutton-html5/public/locales/sr.json b/bigbluebutton-html5/public/locales/sr.json index 92739e57a1..3f984ee2c1 100644 --- a/bigbluebutton-html5/public/locales/sr.json +++ b/bigbluebutton-html5/public/locales/sr.json @@ -492,7 +492,6 @@ "app.lock-viewers.button.apply": "Primenite", "app.lock-viewers.button.cancel": "Otkažite", "app.lock-viewers.locked": "Zaključano", - "app.lock-viewers.unlocked": "Otključano", "app.connection-status.description": "Pogledajte status povezivanja učesnika", "app.recording.startTitle": "Započnite snimanje", "app.recording.stopTitle": "Pauzirajte snimanje", diff --git a/bigbluebutton-html5/public/locales/sv_SE.json b/bigbluebutton-html5/public/locales/sv_SE.json index b8e34970dd..22ab53766c 100644 --- a/bigbluebutton-html5/public/locales/sv_SE.json +++ b/bigbluebutton-html5/public/locales/sv_SE.json @@ -648,7 +648,6 @@ "app.lock-viewers.button.apply": "Spara", "app.lock-viewers.button.cancel": "Avbryt", "app.lock-viewers.locked": "Låst", - "app.lock-viewers.unlocked": "Upplåst", "app.guest-policy.ariaTitle": "Gäst policy inställningar modal", "app.guest-policy.title": "Gäst policy", "app.guest-policy.description": "Ändra mötespolicy för gäster", diff --git a/bigbluebutton-html5/public/locales/ta.json b/bigbluebutton-html5/public/locales/ta.json index 0cf211216b..a126f0b2a9 100644 --- a/bigbluebutton-html5/public/locales/ta.json +++ b/bigbluebutton-html5/public/locales/ta.json @@ -609,7 +609,6 @@ "app.lock-viewers.button.apply": "விண்ணப்பிக்கவும்", "app.lock-viewers.button.cancel": "ரத்துசெய்", "app.lock-viewers.locked": "பூட்டப்பட்டுள்ளது", - "app.lock-viewers.unlocked": "திறக்கப்பட்டது", "app.guest-policy.ariaTitle": "விருந்தினர் கொள்கை அமைப்புகள் மாதிரி", "app.guest-policy.title": "விருந்தினர் கொள்கை", "app.guest-policy.description": "சந்திப்பு விருந்தினர் கொள்கை அமைப்பை மாற்றவும்", diff --git a/bigbluebutton-html5/public/locales/te.json b/bigbluebutton-html5/public/locales/te.json index 3e81802fc0..b781c3f36e 100644 --- a/bigbluebutton-html5/public/locales/te.json +++ b/bigbluebutton-html5/public/locales/te.json @@ -641,7 +641,6 @@ "app.lock-viewers.button.apply": "అమలు చేయి", "app.lock-viewers.button.cancel": "రద్దు చేయి", "app.lock-viewers.locked": "లాక్ చేయబడింది", - "app.lock-viewers.unlocked": "అన్ లాక్ చేయబడింది", "app.guest-policy.ariaTitle": "అతిథి విధాన సెట్టింగ్‌లు మోడల్", "app.guest-policy.title": "అతిథి విధానం", "app.guest-policy.description": "సమావేశ అతిథి విధాన సెట్టింగ్‌ని మార్చండి", diff --git a/bigbluebutton-html5/public/locales/th.json b/bigbluebutton-html5/public/locales/th.json index 5e92fb860d..fb1dbcbefb 100644 --- a/bigbluebutton-html5/public/locales/th.json +++ b/bigbluebutton-html5/public/locales/th.json @@ -465,7 +465,6 @@ "app.lock-viewers.button.apply": "ใช้งาน", "app.lock-viewers.button.cancel": "ยกเลิก", "app.lock-viewers.locked": "ล็อค", - "app.lock-viewers.unlocked": "ปลดล็อค", "app.recording.startTitle": "เริ่มการบันทึก", "app.recording.stopTitle": "หยุดการบันทึกชั่วคราว", "app.recording.resumeTitle": "ทำการบันทึกต่อ", diff --git a/bigbluebutton-html5/public/locales/tr.json b/bigbluebutton-html5/public/locales/tr.json index d0cdca7e5f..1262de92d1 100644 --- a/bigbluebutton-html5/public/locales/tr.json +++ b/bigbluebutton-html5/public/locales/tr.json @@ -577,6 +577,8 @@ "app.guest.guestDeny": "Misafir toplantıya katılmayı reddetti.", "app.guest.seatWait": "Toplantıda katılmayı bekleyen bir misafir var.", "app.guest.allow": "Misafir onaylandı ve toplantıya yönlendiriliyor.", + "app.guest.firstPositionInWaitingQueue": "İlk Sıradasınız!", + "app.guest.positionInWaitingQueue": "Bekleme kuyruğundaki mevcut konumunuz:", "app.userList.guest.waitingUsers": "Kullanıcılar Bekleniyor", "app.userList.guest.waitingUsersTitle": "Kullanıcı Yönetimi", "app.userList.guest.optionTitle": "Bekleyen Kullanıcılara Bakın", @@ -644,7 +646,6 @@ "app.lock-viewers.button.apply": "Uygula", "app.lock-viewers.button.cancel": "Vazgeç", "app.lock-viewers.locked": "Kilitli", - "app.lock-viewers.unlocked": "Kilidi açık", "app.guest-policy.ariaTitle": "Misafir politikası ayarları modeli", "app.guest-policy.title": "Misafir politikası", "app.guest-policy.description": "Toplantı misafir politika ayarını değiştirin", diff --git a/bigbluebutton-html5/public/locales/tr_TR.json b/bigbluebutton-html5/public/locales/tr_TR.json index 141e20b807..fd7bda2481 100644 --- a/bigbluebutton-html5/public/locales/tr_TR.json +++ b/bigbluebutton-html5/public/locales/tr_TR.json @@ -607,7 +607,7 @@ "app.guest.seatWait": "Toplantıda katılmayı bekleyen bir misafir var.", "app.guest.allow": "Misafir onaylandı ve toplantıya yönlendiriliyor.", "app.guest.firstPositionInWaitingQueue": "İlk Sıradasınız!", - "app.guest.positionInWaitingQueue": "Bekleme sırasındaki mevcut konumunuz:", + "app.guest.positionInWaitingQueue": "Bekleme kuyruğundaki mevcut konumunuz:", "app.guest.guestInvalid": "Konuk kullanıcı geçersiz", "app.guest.meetingForciblyEnded": "Zorla sonlandırılan bir toplantıya katılamazsınız", "app.userList.guest.waitingUsers": "Kullanıcılar bekleniyor", @@ -683,7 +683,6 @@ "app.lock-viewers.button.apply": "Uygula", "app.lock-viewers.button.cancel": "Vazgeç", "app.lock-viewers.locked": "Kilitli", - "app.lock-viewers.unlocked": "Açık", "app.guest-policy.ariaTitle": "Misafir politikası ayarları modeli", "app.guest-policy.title": "Misafir Politikası", "app.guest-policy.description": "Toplantı misafir politika ayarını değiştirin", diff --git a/bigbluebutton-html5/public/locales/uk_UA.json b/bigbluebutton-html5/public/locales/uk_UA.json index e9837f1f52..6ac47c7341 100644 --- a/bigbluebutton-html5/public/locales/uk_UA.json +++ b/bigbluebutton-html5/public/locales/uk_UA.json @@ -651,7 +651,6 @@ "app.lock-viewers.button.apply": "Застосувати", "app.lock-viewers.button.cancel": "Скасувати", "app.lock-viewers.locked": "Заблокований", - "app.lock-viewers.unlocked": "Розблокований", "app.guest-policy.ariaTitle": "Вікно налаштування політики для гостей", "app.guest-policy.title": "Гостьова політика", "app.guest-policy.description": "Змінити налаштування гостьової політики зустрічі", diff --git a/bigbluebutton-html5/public/locales/vi_VN.json b/bigbluebutton-html5/public/locales/vi_VN.json index 1524eb485b..d6276da369 100644 --- a/bigbluebutton-html5/public/locales/vi_VN.json +++ b/bigbluebutton-html5/public/locales/vi_VN.json @@ -646,7 +646,6 @@ "app.lock-viewers.button.apply": "ÁP dụng", "app.lock-viewers.button.cancel": "Hủy bỏ", "app.lock-viewers.locked": "Khóa", - "app.lock-viewers.unlocked": "Mở khóa", "app.guest-policy.ariaTitle": "Phương thức cài đặt chính sách khách", "app.guest-policy.title": "Chính sách cho khách", "app.guest-policy.description": "Thay đổi cài đặt chính sách khách họp", diff --git a/bigbluebutton-html5/public/locales/zh_CN.json b/bigbluebutton-html5/public/locales/zh_CN.json index ccde2f9be2..283ffc7b09 100644 --- a/bigbluebutton-html5/public/locales/zh_CN.json +++ b/bigbluebutton-html5/public/locales/zh_CN.json @@ -548,7 +548,6 @@ "app.lock-viewers.button.apply": "应用", "app.lock-viewers.button.cancel": "取消", "app.lock-viewers.locked": "已锁定", - "app.lock-viewers.unlocked": "未锁定", "app.connection-status.ariaTitle": "连接状态模式", "app.connection-status.title": "连接状态", "app.connection-status.description": "查看用户的连接状态", diff --git a/bigbluebutton-html5/public/locales/zh_TW.json b/bigbluebutton-html5/public/locales/zh_TW.json index ba832ba151..ae2174d816 100644 --- a/bigbluebutton-html5/public/locales/zh_TW.json +++ b/bigbluebutton-html5/public/locales/zh_TW.json @@ -110,28 +110,30 @@ "app.userList.userOptions.muteAllExceptPresenterDesc": "靜音會議中觀眾", "app.userList.userOptions.unmuteAllLabel": "關閉會議室靜音", "app.userList.userOptions.unmuteAllDesc": "解除會議室靜音", - "app.userList.userOptions.lockViewersLabel": "鎖定觀眾", + "app.userList.userOptions.lockViewersLabel": "鎖定與會者", "app.userList.userOptions.lockViewersDesc": "鎖定聽眾在此會議中的特定功能", "app.userList.userOptions.guestPolicyLabel": "訪客政策", "app.userList.userOptions.guestPolicyDesc": "更改訪客政策設定", - "app.userList.userOptions.disableCam": "觀眾的網路攝影機已禁用", - "app.userList.userOptions.disableMic": "已停用與會者的麥克風", + "app.userList.userOptions.disableCam": "與會者的網路攝影機已禁用", + "app.userList.userOptions.disableMic": "與會者的麥克風已禁用", "app.userList.userOptions.disablePrivChat": "已停用私人聊天", "app.userList.userOptions.disablePubChat": "已停用公開聊天", "app.userList.userOptions.disableNotes": "共享筆記目前鎖定", - "app.userList.userOptions.hideUserList": "用戶列表已對與會者隱藏", - "app.userList.userOptions.webcamsOnlyForModerator": "只有主持人才能看到觀眾的視訊(由於鎖定設置)", + "app.userList.userOptions.hideUserList": "對與會者隱藏參與者清單", + "app.userList.userOptions.webcamsOnlyForModerator": "只有主持人才能看到與會者的視訊(由於鎖定設置)", "app.userList.content.participants.options.clearedStatus": "已清除所有使用者狀態", "app.userList.userOptions.enableCam": "與會者的網路攝影機已啟用", "app.userList.userOptions.enableMic": "與會者的麥克風已啟用", "app.userList.userOptions.enablePrivChat": "私人聊天已啟用", "app.userList.userOptions.enablePubChat": "公開聊天已啟用", "app.userList.userOptions.enableNotes": "共享筆記已啟用", - "app.userList.userOptions.showUserList": "用戶列表己顯示於與會者", + "app.userList.userOptions.showUserList": "與會者可看見參與者清單", "app.userList.userOptions.enableOnlyModeratorWebcam": "您現在可以啟用網路攝影機,所有人都會看到您。", "app.userList.userOptions.savedNames.title": "列出與會用戶{0}人中的{1}", "app.userList.userOptions.sortedFirstName.heading": "依名稱排序", "app.userList.userOptions.sortedLastName.heading": "依姓氏排序", + "app.userList.userOptions.hideViewersCursor": "鎖定與會者游標", + "app.userList.userOptions.showViewersCursor": "解除鎖定與會者游標", "app.media.label": "媒體", "app.media.autoplayAlertDesc": "允許存取", "app.media.screenshare.start": "螢幕分享已開始", @@ -454,7 +456,7 @@ "app.actionsBar.actionsDropdown.takePresenter": "當簡報者", "app.actionsBar.actionsDropdown.takePresenterDesc": "設定自己為簡報者", "app.actionsBar.actionsDropdown.selectRandUserLabel": "選擇隨機使用者", - "app.actionsBar.actionsDropdown.selectRandUserDesc": "從可用的觀眾中隨機選擇一個使用者", + "app.actionsBar.actionsDropdown.selectRandUserDesc": "從與會者中隨機選擇一位", "app.actionsBar.emojiMenu.statusTriggerLabel": "設定狀態", "app.actionsBar.emojiMenu.awayLabel": "離開", "app.actionsBar.emojiMenu.awayDesc": "變更您的狀態為離開", @@ -495,7 +497,7 @@ "app.audioNotification.audioFailedMessage": "您的音訊連接失敗了", "app.audioNotification.mediaFailedMessage": "或取用戶麥克風失敗,需為安全來源才能被允許。", "app.audioNotification.closeLabel": "關閉", - "app.audioNotificaion.reconnectingAsListenOnly": "觀眾的麥克風被鎖定,您現在只能聆聽。", + "app.audioNotificaion.reconnectingAsListenOnly": "與會者的麥克風被鎖定,您現在只能聆聽。", "app.breakoutJoinConfirmation.title": "加入分組會議室", "app.breakoutJoinConfirmation.message": "您要加入嗎?", "app.breakoutJoinConfirmation.confirmDesc": "將您加入分組會議室", @@ -582,11 +584,11 @@ "app.modal.confirm": "完成", "app.modal.newTab": "(開啟新分頁)", "app.modal.confirm.description": "儲存變更並且關閉模組", - "app.modal.randomUser.noViewers.description": "沒有可供隨機選擇的觀看者", + "app.modal.randomUser.noViewers.description": "沒有與會者可供隨機選擇", "app.modal.randomUser.selected.description": "您已被隨機選中", "app.modal.randomUser.title": "隨機選擇的用戶", "app.modal.randomUser.who": "誰會被選到呢...?", - "app.modal.randomUser.alone": "只有一位觀眾", + "app.modal.randomUser.alone": "只有一位與會者", "app.modal.randomUser.reselect.label": "再次選擇", "app.modal.randomUser.ariaLabel.title": "隨機選擇的用戶模態", "app.dropdown.close": "關閉", @@ -652,7 +654,7 @@ "app.toast.setEmoji.raiseHand": "您已經舉手", "app.toast.setEmoji.lowerHand": "您的手已經放下", "app.toast.promotedLabel": "您被提升為主持人了", - "app.toast.demotedLabel": "您被調整回觀眾了", + "app.toast.demotedLabel": "您被調整回與會者", "app.notification.recordingStart": "正在錄製此會議", "app.notification.recordingStop": "已停止錄製此會議", "app.notification.recordingPaused": "此會談不再被側錄", @@ -680,8 +682,8 @@ "app.shortcut-help.toggleFullscreen": "切換全螢幕(簡報者)", "app.shortcut-help.nextSlideDesc": "下一張投影片(簡報者)", "app.shortcut-help.previousSlideDesc": "上一張投影片(簡報者)", - "app.lock-viewers.title": "鎖定觀眾", - "app.lock-viewers.description": "這些選項讓你禁止聽眾使用特定功能。", + "app.lock-viewers.title": "鎖定與會者", + "app.lock-viewers.description": "這些選項讓您禁止與會者使用特定功能。", "app.lock-viewers.featuresLable": "功能", "app.lock-viewers.lockStatusLabel": "狀態", "app.lock-viewers.webcamLabel": "分享網路攝影機", @@ -690,12 +692,12 @@ "app.lock-viewers.PublicChatLabel": "發送聊天訊息", "app.lock-viewers.PrivateChatLable": "傳送私人聊天訊息", "app.lock-viewers.notesLabel": "編輯共享筆記", - "app.lock-viewers.userListLabel": "在用戶列表查看其他與會者", - "app.lock-viewers.ariaTitle": "鎖定觀眾設置模式", + "app.lock-viewers.userListLabel": "在參與者清單查看其他與會者", + "app.lock-viewers.ariaTitle": "鎖定與會者設置模式", "app.lock-viewers.button.apply": "使用", "app.lock-viewers.button.cancel": "取消", "app.lock-viewers.locked": "已鎖定", - "app.lock-viewers.unlocked": "鎖定已解除", + "app.lock-viewers.hideViewersCursor": "觀看其他與會者游標", "app.guest-policy.ariaTitle": "訪客政策設置模式", "app.guest-policy.title": "訪客政策", "app.guest-policy.description": "更改會議訪客政策設定", @@ -776,7 +778,7 @@ "app.video.genericError": "設備 ({0}) 發生未知錯誤", "app.video.mediaTimedOutError": "您的網絡攝影機串流已中斷。請再次嘗試分享。", "app.video.mediaFlowTimeout1020": "媒體無法連接伺服器(錯誤 1020)", - "app.video.suggestWebcamLock": "是否對觀眾的攝影鏡頭強制鎖住設定?", + "app.video.suggestWebcamLock": "是否對與會者的攝影鏡頭強制鎖住設定?", "app.video.suggestWebcamLockReason": "(這將提升會議的穩定性)", "app.video.enable": "啟用", "app.video.cancel": "取消", @@ -952,6 +954,7 @@ "playback.button.search.aria": "搜尋", "playback.button.section.aria": "邊緣部分", "playback.button.swap.aria": "互換內容", + "playback.button.theme.aria": "切換佈景", "playback.error.wrapper.aria": "錯誤區", "playback.loader.wrapper.aria": "載入區", "playback.player.wrapper.aria": "播放區", @@ -1035,15 +1038,10 @@ "app.learningDashboard.statusTimelineTable.thumbnail": "簡報縮圖", "app.learningDashboard.errors.invalidToken": "無效的連線識別碼", "app.learningDashboard.errors.dataUnavailable": "資料不再能用", - "mobileApp.portals.list.empty.label": "請添加門戶", - "mobileApp.portals.list.add.button.label": "新門戶", "mobileApp.portals.fields.name.label": "門戶名稱", "mobileApp.portals.fields.name.placeholder": "BigBlueButton demo", "mobileApp.portals.fields.url.label": "伺服器URL", - "mobileApp.portals.addPortalPopup.confirm.button.label": "添加門戶", - "mobileApp.portals.drawerNavigation.button.label": "門戶", - "mobileApp.portals.addPortalPopup.validation.emptyFilds": "空字段", - "mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "名稱已經存在" + "mobileApp.portals.drawerNavigation.button.label": "門戶" } diff --git a/bigbluebutton-tests/playwright/README.md b/bigbluebutton-tests/playwright/README.md index 15649e4e7a..9dd97d8214 100644 --- a/bigbluebutton-tests/playwright/README.md +++ b/bigbluebutton-tests/playwright/README.md @@ -10,10 +10,15 @@ $ cd ../bigbluebutton-tests/playwright $ npm install $ npx playwright install ``` +You may also need to run the following command: +```bash +$ npx playwright install-deps +``` To run these tests with an existing BigBlueButton server, you need to find the server's URL and secret (can be done with `bbb-conf --secret` command). You need to put them into the `.env` file inside `bigbluebutton-tests/playwright` folder (variables `BBB_URL` and `BBB_SECRET`). Note: the value for `BBB_URL` follows the format of `https:///bigbluebutton/api`. ## Run tests +We recommend to use Node version 16 or higher to avoid errors in JavaScript. Tests can be executed using `npx` and `npm test`. You can run all tests in each of 3 supported environments (`chromium`, `firefox`, `webkit`) with one of the following commands: ```bash $ npx playwright test @@ -43,4 +48,4 @@ _(note that this filter needs to be passed in "double quotes")_ You can also use this also through the test tree, adding the test suite / group of tests before the test filter: ```bash $ npm run test:filter "notifications chat" -``` \ No newline at end of file +``` diff --git a/bigbluebutton-tests/playwright/audio/audio.js b/bigbluebutton-tests/playwright/audio/audio.js index abe75db175..e076195c49 100644 --- a/bigbluebutton-tests/playwright/audio/audio.js +++ b/bigbluebutton-tests/playwright/audio/audio.js @@ -1,6 +1,6 @@ const Page = require('../core/page'); const e = require('../core/elements'); -const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); +const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_TIME } = require('../core/constants'); class Audio extends Page { constructor(browser, page) { @@ -8,23 +8,32 @@ class Audio extends Page { } async joinAudio() { + const { autoJoinAudioModal, listenOnlyCallTimeout } = this.settings; + if (!autoJoinAudioModal) await this.waitAndClick(e.joinAudio); await this.waitAndClick(e.listenOnlyButton); await this.wasRemoved(e.connecting); - const parsedSettings = await this.getSettingsYaml(); - const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout); await this.waitForSelector(e.leaveAudio, listenOnlyCallTimeout); await this.waitForSelector(e.whiteboard); await this.hasElement(e.leaveAudio); } async joinMicrophone() { + const { + autoJoinAudioModal, + skipEchoTest, + skipEchoTestOnJoin, + listenOnlyCallTimeout, + } = this.settings; + + if (!autoJoinAudioModal) await this.waitAndClick(e.joinAudio); await this.waitAndClick(e.microphoneButton); - await this.waitForSelector(e.connectingToEchoTest); - await this.wasRemoved(e.connectingToEchoTest, ELEMENT_WAIT_LONGER_TIME); - const parsedSettings = await this.getSettingsYaml(); - const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout); - await this.waitAndClick(e.echoYesButton, listenOnlyCallTimeout); - await this.waitForSelector(e.whiteboard); + const shouldSkipEchoTest = skipEchoTest || skipEchoTestOnJoin; + if (!shouldSkipEchoTest) { + await this.waitForSelector(e.connectingToEchoTest); + await this.wasRemoved(e.connectingToEchoTest, ELEMENT_WAIT_LONGER_TIME); + await this.waitAndClick(e.echoYesButton, listenOnlyCallTimeout); + } + await this.waitForSelector(e.whiteboard, shouldSkipEchoTest ? listenOnlyCallTimeout : ELEMENT_WAIT_TIME); await this.hasElement(e.isTalking); } } diff --git a/bigbluebutton-tests/playwright/breakout/join.js b/bigbluebutton-tests/playwright/breakout/join.js index 6f0ce8d131..58ad5a9d35 100644 --- a/bigbluebutton-tests/playwright/breakout/join.js +++ b/bigbluebutton-tests/playwright/breakout/join.js @@ -23,17 +23,17 @@ class Join extends Create { await breakoutUserPage.bringToFront(); if (!shouldJoinAudio) await breakoutUserPage.closeAudioModal(); - await breakoutUserPage.hasElement(e.presentationPlaceholder); + await breakoutUserPage.waitForSelector(e.presentationTitle); return breakoutUserPage; } async joinAndShareWebcam() { const breakoutPage = await this.joinRoom(); - const parsedSettings = await this.userPage.getSettingsYaml(); - const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout); - await breakoutPage.shareWebcam(videoPreviewTimeout); + const { videoPreviewTimeout } = breakoutPage.settings; + await breakoutPage.shareWebcam(true, videoPreviewTimeout); await breakoutPage.hasElement(e.presentationPlaceholder); + await breakoutPage.waitForSelector(e.presentationTitle); } async joinAndShareScreen() { diff --git a/bigbluebutton-tests/playwright/chat/chat.js b/bigbluebutton-tests/playwright/chat/chat.js index 4fa9861643..62fd75f3e7 100644 --- a/bigbluebutton-tests/playwright/chat/chat.js +++ b/bigbluebutton-tests/playwright/chat/chat.js @@ -1,8 +1,10 @@ -const { expect } = require('@playwright/test'); +const { expect, default: test } = require('@playwright/test'); const Page = require('../core/page'); const { openChat } = require('./util'); const p = require('../core/parameters'); const e = require('../core/elements'); +const { checkTextContent } = require('../core/util'); +const { getSettings } = require('../core/settings'); class Chat extends Page { constructor(browser, page) { @@ -10,7 +12,7 @@ class Chat extends Page { } async sendPublicMessage() { - await openChat(this.page); + await openChat(this); const message = this.getLocator(e.chatUserMessageText); await expect(message).toHaveCount(0); @@ -21,7 +23,7 @@ class Chat extends Page { } async clearChat() { - await openChat(this.page); + await openChat(this); const message = this.getLocator(e.chatUserMessageText); await this.type(e.chatBox, e.message); @@ -39,8 +41,10 @@ class Chat extends Page { } async copyChat(context) { - await openChat(this); + const { publicChatOptionsEnabled } = getSettings(); + test.fail(!publicChatOptionsEnabled, 'Public chat options (save and copy) are disabled'); + await openChat(this); // sending a message await this.type(e.chatBox, e.message); await this.waitAndClick(e.sendButton); @@ -50,29 +54,42 @@ class Chat extends Page { await this.waitForSelector(e.chatUserMessageText); await this.waitAndClick(e.chatCopy); // enable access to browser context clipboard - await context.grantPermissions(['clipboard-write', 'clipboard-read'], { origin: process.env.BBB_SERVER_URL }); + await context.grantPermissions(['clipboard-write', 'clipboard-read'], { origin: process.env.BBB_URL }); const copiedText = await this.page.evaluate(async () => navigator.clipboard.readText()); const check = copiedText.includes(`${p.fullName}: ${e.message}`); expect(check).toBeTruthy(); } - async saveChat() { - await openChat(this.page); + async saveChat(testInfo) { + const { publicChatOptionsEnabled } = getSettings(); + test.fail(!publicChatOptionsEnabled, 'Public chat options (save and copy) are disabled'); + + await openChat(this); + await this.type(e.chatBox, e.message); + await this.waitAndClick(e.sendButton); + await this.waitForSelector(e.chatUserMessageText); await this.waitAndClick(e.chatOptions); - await this.waitAndClick(e.chatSave); - await this.page.waitForEvent('click'); + const { content } = await this.handleDownload(e.chatSave, testInfo); + + const dataToCheck = [ + this.meetingId, + this.username, + e.message, + ]; + await checkTextContent(content, dataToCheck); } async characterLimit() { - await openChat(this.page); + await openChat(this); const messageLocator = this.getLocator(e.chatUserMessageText); - await this.page.fill(e.chatBox, e.longMessage5000); + const { maxMessageLength } = getSettings(); + await this.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength)); await this.waitAndClick(e.sendButton); await this.waitForSelector(e.chatUserMessageText); await expect(messageLocator).toHaveCount(1); - await this.page.fill(e.chatBox, e.longMessage5001); + await this.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength + 1)); await this.waitForSelector(e.typingIndicator); await this.waitAndClick(e.sendButton); await this.waitForSelector(e.chatUserMessageText); @@ -80,7 +97,7 @@ class Chat extends Page { } async emptyMessage() { - await openChat(this.page); + await openChat(this); const messageLocator = this.getLocator(e.chatUserMessageText); await this.waitAndClick(e.sendButton); diff --git a/bigbluebutton-tests/playwright/chat/chat.spec.js b/bigbluebutton-tests/playwright/chat/chat.spec.js index 3f01d9aee5..a687955d78 100644 --- a/bigbluebutton-tests/playwright/chat/chat.spec.js +++ b/bigbluebutton-tests/playwright/chat/chat.spec.js @@ -22,20 +22,19 @@ test.describe.parallel('Chat', () => { }); test('Copy chat', async ({ browser, context, page }, testInfo) => { - test.fixme(testInfo.config.projects[0].use.headless, 'Only works in headed mode'); + test.fixme(testInfo.project.use.headless, 'Only works in headed mode'); const chat = new Chat(browser, page); await chat.init(true, true); await chat.copyChat(context); }); - test.skip('Save chat', async ({ browser, page }) => { - test.fixme(); + test('Save chat', async ({ browser, page }, testInfo) => { const chat = new Chat(browser, page); await chat.init(true, true); - await chat.saveChat(); + await chat.saveChat(testInfo); }); - test('Verify character limit (5000 characters)', async ({ browser, page }) => { + test('Verify character limit', async ({ browser, page }) => { const chat = new Chat(browser, page); await chat.init(true, true); await chat.characterLimit(); diff --git a/bigbluebutton-tests/playwright/chat/privateChat.js b/bigbluebutton-tests/playwright/chat/privateChat.js index 1fbbb20d9d..b624184cb9 100644 --- a/bigbluebutton-tests/playwright/chat/privateChat.js +++ b/bigbluebutton-tests/playwright/chat/privateChat.js @@ -2,6 +2,7 @@ const { MultiUsers } = require('../user/multiusers'); const e = require('../core/elements'); const { sleep } = require('../core/helpers'); const { expect } = require('@playwright/test'); +const { openPrivateChat } = require('./util'); class PrivateChat extends MultiUsers { constructor(browser, context) { @@ -9,8 +10,7 @@ class PrivateChat extends MultiUsers { } async sendPrivateMessage() { - await this.modPage.waitAndClick(e.userListItem); - await this.modPage.waitAndClick(e.startPrivateChat); + await openPrivateChat(this.modPage); await this.modPage.waitForSelector(e.hidePrivateChat); await sleep(500); // prevent a race condition when running on a deployed server // modPage send message @@ -31,8 +31,7 @@ class PrivateChat extends MultiUsers { } async closeChat() { - await this.modPage.waitAndClick(e.userListItem); - await this.modPage.waitAndClick(e.startPrivateChat); + await openPrivateChat(this.modPage); await this.modPage.waitUntilHaveCountSelector(e.chatButton, 2); const privateChatLocator = this.modPage.getLocatorByIndex(e.chatButton, -1); expect(privateChatLocator).toContainText(this.userPage.username); @@ -48,8 +47,7 @@ class PrivateChat extends MultiUsers { } async chatDisabledUserLeaves() { - await this.modPage.waitAndClick(e.userListItem); - await this.modPage.waitAndClick(e.startPrivateChat); + await openPrivateChat(this.modPage); await this.modPage.waitForSelector(e.sendButton); await this.userPage.waitAndClick(e.optionsButton); await this.userPage.waitAndClick(e.logout); diff --git a/bigbluebutton-tests/playwright/chat/util.js b/bigbluebutton-tests/playwright/chat/util.js index cefb575443..49141feaf7 100644 --- a/bigbluebutton-tests/playwright/chat/util.js +++ b/bigbluebutton-tests/playwright/chat/util.js @@ -1,8 +1,22 @@ +const { default: test } = require('@playwright/test'); const e = require('../core/elements'); +const { getSettings } = require('../core/settings'); -async function openChat(page) { - await page.waitForSelector(e.chatBox); - await page.waitForSelector(e.chatMessages); +async function openChat(testPage) { + const { chatEnabled } = getSettings(); + test.fail(!chatEnabled, 'Chat is disabled'); + + await testPage.waitForSelector(e.chatBox); + await testPage.waitForSelector(e.chatMessages); +} + +async function openPrivateChat(testPage) { + const { chatEnabled } = getSettings(); + test.fail(!chatEnabled, 'Chat is disabled'); + + await testPage.waitAndClick(e.userListItem); + await testPage.waitAndClick(e.startPrivateChat); } exports.openChat = openChat; +exports.openPrivateChat = openPrivateChat; diff --git a/bigbluebutton-tests/playwright/connectionStatus/connectionStatus.js b/bigbluebutton-tests/playwright/connectionStatus/connectionStatus.js index b01d7501cd..91edb33f51 100644 --- a/bigbluebutton-tests/playwright/connectionStatus/connectionStatus.js +++ b/bigbluebutton-tests/playwright/connectionStatus/connectionStatus.js @@ -1,10 +1,8 @@ const { expect } = require('@playwright/test'); const { MultiUsers } = require('../user/multiusers'); const e = require('../core/elements'); -const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); +const { ELEMENT_WAIT_TIME } = require('../core/constants'); const { openConnectionStatus, checkNetworkStatus } = require('./util'); -const { startScreenshare } = require('../screenshare/util'); -const { waitAndClearNotification } = require('../notifications/util'); class ConnectionStatus extends MultiUsers { diff --git a/bigbluebutton-tests/playwright/core/elements.js b/bigbluebutton-tests/playwright/core/elements.js index a19cd02667..96f029e048 100644 --- a/bigbluebutton-tests/playwright/core/elements.js +++ b/bigbluebutton-tests/playwright/core/elements.js @@ -72,8 +72,7 @@ exports.message1 = 'Hello User2'; exports.message2 = 'Hello User1'; exports.publicMessage1 = 'This is a Public Message from User1'; exports.publicMessage2 = 'This is a Public Message from User2'; -exports.longMessage5000 = '01234567890123456789012345678901234567890123456789'.repeat(100); -exports.longMessage5001 = '01234567890123456789012345678901234567890123456789'.repeat(100) + '0'; +exports.uniqueCharacterMessage = 'A'; // CustomParameters exports.audioOptionsButtons = 'span[data-test="audioModalOptions"] > button'; @@ -189,11 +188,12 @@ exports.messageTitle = 'h2[data-test="messageTitle"]'; exports.notesTitle = 'h2[data-test="notesTitle"]'; // User -exports.userAvatar = 'div[data-test="userAvatar"]'; +const userAvatar = 'div[data-test="userAvatar"]'; +exports.userAvatar = userAvatar; exports.moderatorAvatar = 'div[data-test="moderatorAvatar"]'; exports.viewerAvatar = 'div[data-test="viewerAvatar"]'; -exports.applauseIcon = `${this.userAvatar} > div > i[class="icon-bbb-applause"]`; -exports.awayIcon = `${this.userAvatar} > div > i[class="icon-bbb-time"]`; +exports.applauseIcon = `${userAvatar} > div > i[class="icon-bbb-applause"]`; +exports.awayIcon = `${userAvatar} > div > i[class="icon-bbb-time"]`; exports.setStatus = 'li[data-test="setStatus"]'; exports.away = 'li[data-test="away"]'; exports.applaud = 'li[data-test="applause"]'; @@ -202,7 +202,6 @@ exports.currentUser = 'div[data-test="userListItemCurrent"]'; exports.multiWhiteboardTool = 'span[data-test="multiWhiteboardTool"]'; exports.manageUsers = 'button[data-test="manageUsers"]'; exports.presenterClassName = 'presenter--'; -exports.anyUser = 'div[data-test="userListItem"]'; exports.userListToggleBtn = 'button[data-test="toggleUserList"]'; exports.mobileUser = 'span[data-test="mobileUser"]'; exports.connectionStatusBtn = 'button[data-test="connectionStatusButton"]'; @@ -217,6 +216,7 @@ exports.connectionStatusOfflineUser = 'div[data-test="offlineUser"]'; exports.connectionDataContainer = 'div[data-test="networkDataContainer"]'; exports.avatarsWrapperAvatar = 'div[data-test="avatarsWrapperAvatar"]'; exports.guestPolicyLabel = 'li[data-test="guestPolicyLabel"]'; +exports.downloadUserNamesList = 'li[data-test="downloadUserNamesList"]'; exports.waitingUsersBtn = 'div[data-test="waitingUsersBtn"]'; exports.joinMeetingDemoPage = 'div[class^="join-meeting"]'; exports.askModerator = 'button[data-test="askModerator"]'; diff --git a/bigbluebutton-tests/playwright/media/100PagesFile.pdf b/bigbluebutton-tests/playwright/core/media/100PagesFile.pdf similarity index 100% rename from bigbluebutton-tests/playwright/media/100PagesFile.pdf rename to bigbluebutton-tests/playwright/core/media/100PagesFile.pdf diff --git a/bigbluebutton-tests/playwright/media/mockPollSlide.pdf b/bigbluebutton-tests/playwright/core/media/mockPollSlide.pdf similarity index 100% rename from bigbluebutton-tests/playwright/media/mockPollSlide.pdf rename to bigbluebutton-tests/playwright/core/media/mockPollSlide.pdf diff --git a/bigbluebutton-tests/playwright/media/uploadTest.png b/bigbluebutton-tests/playwright/core/media/uploadTest.png similarity index 100% rename from bigbluebutton-tests/playwright/media/uploadTest.png rename to bigbluebutton-tests/playwright/core/media/uploadTest.png diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index f6ad2ac00c..f50e337d47 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -1,13 +1,12 @@ require('dotenv').config(); -const { expect } = require('@playwright/test'); -const yaml = require('js-yaml'); -const path = require('path'); -const fs = require('fs'); +const { expect, default: test } = require('@playwright/test'); +const { readFileSync } = require('fs'); const parameters = require('./parameters'); const helpers = require('./helpers'); const e = require('./elements'); const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } = require('./constants'); const { checkElement, checkElementLengthEqualTo } = require('./util'); +const { generateSettingsData } = require('./settings'); class Page { constructor(browser, page) { @@ -16,14 +15,6 @@ class Page { this.initParameters = Object.assign({}, parameters); } - async getSettingsYaml() { - try { - return yaml.load(fs.readFileSync(path.join(__dirname, '../../../bigbluebutton-html5/private/config/settings.yml'), 'utf8')); - } catch (err) { - console.log(err); - } - } - async bringToFront() { await this.page.bringToFront(); } @@ -43,15 +34,32 @@ class Page { this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, customParameter); const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, customParameter); await this.page.goto(joinUrl); - if (shouldCloseAudioModal) await this.closeAudioModal(); + this.settings = await generateSettingsData(this.page); + const { autoJoinAudioModal } = this.settings; + if (shouldCloseAudioModal && autoJoinAudioModal) await this.closeAudioModal(); + } + + async handleDownload(selector, testInfo, timeout = ELEMENT_WAIT_TIME) { + const [download] = await Promise.all([ + this.page.waitForEvent('download', { timeout }), + this.waitAndClick(selector, timeout), + ]); + await expect(download).toBeTruthy(); + const filePath = await download.path(); + const content = await readFileSync(filePath, 'utf8'); + await testInfo.attach('downloaded', { filePath }); + + return { + download, + content, + } } async joinMicrophone() { await this.waitForSelector(e.audioModal); await this.waitAndClick(e.microphoneButton); await this.waitForSelector(e.connectingToEchoTest); - const parsedSettings = await this.getSettingsYaml(); - const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout); + const { listenOnlyCallTimeout } = this.settings; await this.waitAndClick(e.echoYesButton, listenOnlyCallTimeout); await this.waitForSelector(e.isTalking); } @@ -67,6 +75,9 @@ class Page { } async shareWebcam(shouldConfirmSharing = true, videoPreviewTimeout = ELEMENT_WAIT_TIME) { + const { webcamSharingEnabled } = this.settings; + test.fail(!webcamSharingEnabled, 'Webcam sharing is disabled'); + await this.waitAndClick(e.joinVideo); if (shouldConfirmSharing) { await this.bringToFront(); diff --git a/bigbluebutton-tests/playwright/core/settings.js b/bigbluebutton-tests/playwright/core/settings.js new file mode 100644 index 0000000000..bdce8bb133 --- /dev/null +++ b/bigbluebutton-tests/playwright/core/settings.js @@ -0,0 +1,51 @@ +let settings; + +async function generateSettingsData(page) { + if (settings || !page) return settings; + + try { + const settingsData = await page.evaluate(() => { + return Meteor.settings.public; + }); + + settings = { + raiseHandButton: settingsData.app.raiseHandActionButton.enabled, + sharedNotesEnabled: settingsData.notes.enabled, + // Audio + autoJoinAudioModal: settingsData.app.autoJoin, + listenOnlyMode: settingsData.app.listenOnlyMode, + forceListenOnly: settingsData.app.forceListenOnly, + skipEchoTest: settingsData.app.skipCheck, + skipEchoTestOnJoin: settingsData.app.skipCheckOnJoin, + // Chat + chatEnabled: settingsData.chat.enabled, + publicChatOptionsEnabled: settingsData.chat.enableSaveAndCopyPublicChat, + maxMessageLength: settingsData.chat.max_message_length, + // Polling + pollEnabled: settingsData.poll.enabled, + pollChatMessage: settingsData.poll.chatMessage, + // Presentation + presentationDownloadable: settingsData.presentation.allowDownloadable, + externalVideoPlayer: settingsData.externalVideoPlayer.enabled, + presentationHidden: settingsData.layout.hidePresentation, + // Screensharing + screensharingEnabled: settingsData.kurento.enableScreensharing, + // Timeouts + listenOnlyCallTimeout: parseInt(settingsData.media.listenOnlyCallTimeout), + videoPreviewTimeout: parseInt(settingsData.kurento.gUMTimeout), + // Webcam + webcamSharingEnabled: settingsData.kurento.enableVideo, + skipVideoPreview: settingsData.kurento.skipVideoPreview, + skipVideoPreviewOnFirstJoin: settingsData.kurento.skipVideoPreviewOnFirstJoin, + } + + return settings; + } catch (err) { + console.log(`Unable to get public settings data: ${err}`); + } +} + +module.exports = exports = { + getSettings: () => settings, + generateSettingsData, +} diff --git a/bigbluebutton-tests/playwright/core/util.js b/bigbluebutton-tests/playwright/core/util.js index b7ec0a08c6..3c6473aced 100644 --- a/bigbluebutton-tests/playwright/core/util.js +++ b/bigbluebutton-tests/playwright/core/util.js @@ -1,3 +1,5 @@ +const { expect } = require("@playwright/test"); + // Common function checkElement([element, index = 0]) { return document.querySelectorAll(element)[index] !== undefined; @@ -8,5 +10,14 @@ function checkElementLengthEqualTo([element, count]) { return document.querySelectorAll(element).length == count; } +// Text +async function checkTextContent(baseContent, checkData) { + if (typeof checkData === 'string') checkData = new Array(checkData); + + const check = checkData.every(word => baseContent.includes(word)); + await expect(check).toBeTruthy(); +} + exports.checkElement = checkElement; exports.checkElementLengthEqualTo = checkElementLengthEqualTo; +exports.checkTextContent = checkTextContent; diff --git a/bigbluebutton-tests/playwright/customparameters/constants.js b/bigbluebutton-tests/playwright/customparameters/constants.js index 32ab2da097..3fc57e5c78 100644 --- a/bigbluebutton-tests/playwright/customparameters/constants.js +++ b/bigbluebutton-tests/playwright/customparameters/constants.js @@ -5,8 +5,9 @@ exports.listenOnlyMode = 'userdata-bbb_listen_only_mode=false'; exports.forceListenOnly = 'userdata-bbb_force_listen_only=true'; exports.skipCheck = 'userdata-bbb_skip_check_audio=true'; exports.skipCheckOnFirstJoin = 'userdata-bbb_skip_check_audio_on_first_join=true'; -exports.docTitle = 'playwright'; -exports.clientTitle = `userdata-bbb_client_title=${this.docTitle}`; +const docTitle = 'playwright'; +exports.docTitle = docTitle; +exports.clientTitle = `userdata-bbb_client_title=${docTitle}`; exports.askForFeedbackOnLogout = 'userdata-bbb_ask_for_feedback_on_logout=true'; exports.displayBrandingArea = 'userdata-bbb_display_branding_area=true'; exports.logo = 'logo=https://bigbluebutton.org/wp-content/themes/bigbluebutton/library/images/bigbluebutton-logo.png'; @@ -26,8 +27,9 @@ exports.outsideToggleRecording = 'userdata-bbb_outside_toggle_recording=true'; exports.showPublicChatOnLogin = 'userdata-bbb_show_public_chat_on_login=false'; exports.forceRestorePresentationOnNewEvents = 'userdata-bbb_force_restore_presentation_on_new_events=true'; exports.bannerText = 'bannerText=some text'; -exports.color = 'FFFF00'; -exports.bannerColor = `bannerColor=%23${this.color}`; +const color = 'FFFF00' +exports.color = color; +exports.bannerColor = `bannerColor=%23${color}`; exports.recordMeeting = 'record=true'; exports.skipVideoPreview = 'userdata-bbb_skip_video_preview=true'; exports.skipVideoPreviewOnFirstJoin = 'userdata-bbb_skip_video_preview_on_first_join=true'; diff --git a/bigbluebutton-tests/playwright/customparameters/customparameters.js b/bigbluebutton-tests/playwright/customparameters/customparameters.js index a307d6c94e..7396732e44 100644 --- a/bigbluebutton-tests/playwright/customparameters/customparameters.js +++ b/bigbluebutton-tests/playwright/customparameters/customparameters.js @@ -4,6 +4,7 @@ const e = require('../core/elements'); const c = require('./constants'); const { VIDEO_LOADING_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); const util = require('./util'); +const { getSettings } = require('../core/settings'); class CustomParameters extends MultiUsers { constructor(browser, context) { @@ -136,12 +137,13 @@ class CustomParameters extends MultiUsers { async forceRestorePresentationOnNewEvents(customParameter) { await this.initUserPage(true, this.context, { useModMeetingId: true, customParameter }); - await this.userPage.waitAndClick(e.minimizePresentation); + const { presentationHidden, pollEnabled } = getSettings(); + if (!presentationHidden) await this.userPage.waitAndClick(e.minimizePresentation); const zoomInCase = await util.zoomIn(this.modPage); await expect(zoomInCase).toBeTruthy(); const zoomOutCase = await util.zoomOut(this.modPage); await expect(zoomOutCase).toBeTruthy(); - await util.poll(this.modPage, this.userPage); + if (pollEnabled) await util.poll(this.modPage, this.userPage); await util.nextSlide(this.modPage); await util.previousSlide(this.modPage); await util.annotation(this.modPage); @@ -150,8 +152,9 @@ class CustomParameters extends MultiUsers { async forceRestorePresentationOnNewPollResult(customParameter) { await this.initUserPage(true, this.context, { useModMeetingId: true, customParameter }) - await this.userPage.waitAndClick(e.minimizePresentation); - await util.poll(this.modPage, this.userPage); + const { presentationHidden,pollEnabled } = getSettings(); + if (!presentationHidden) await this.userPage.waitAndClick(e.minimizePresentation); + if (pollEnabled) await util.poll(this.modPage, this.userPage); await this.userPage.waitForSelector(e.smallToastMsg); await this.userPage.checkElement(e.restorePresentation); } @@ -168,9 +171,8 @@ class CustomParameters extends MultiUsers { await this.modPage.shareWebcam(false); await this.modPage.waitAndClick(e.leaveVideo, VIDEO_LOADING_WAIT_TIME); await this.modPage.waitForSelector(e.joinVideo); - const parsedSettings = await this.modPage.getSettingsYaml(); - const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout); - await this.modPage.shareWebcam(videoPreviewTimeout); + const { videoPreviewTimeout } = this.modPage.settings; + await this.modPage.shareWebcam(true, videoPreviewTimeout); } async mirrorOwnWebcam() { diff --git a/bigbluebutton-tests/playwright/notifications/notifications.js b/bigbluebutton-tests/playwright/notifications/notifications.js index 67f352e252..228d8d72ba 100644 --- a/bigbluebutton-tests/playwright/notifications/notifications.js +++ b/bigbluebutton-tests/playwright/notifications/notifications.js @@ -3,6 +3,7 @@ const e = require('../core/elements'); const util = require('./util'); const { openSettings } = require('../settings/util'); const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); +const { default: test } = require('@playwright/test'); class Notifications extends MultiUsers { constructor(browser, context) { @@ -38,6 +39,9 @@ class Notifications extends MultiUsers { } async raiseAndLowerHandNotification() { + const { raiseHandButton } = getSettings(); + test.fail(!raiseHandButton, 'Raise/lower hand button is disabled'); + await this.modPage.waitAndClick(e.raiseHandBtn); await this.modPage.waitForSelector(e.smallToastMsg); await util.checkNotificationText(this.modPage, e.raisingHandToast); diff --git a/bigbluebutton-tests/playwright/notifications/notifications.spec.js b/bigbluebutton-tests/playwright/notifications/notifications.spec.js index bf48c6a503..5a862adce1 100644 --- a/bigbluebutton-tests/playwright/notifications/notifications.spec.js +++ b/bigbluebutton-tests/playwright/notifications/notifications.spec.js @@ -49,7 +49,7 @@ test.describe.parallel('Notifications', () => { await presenterNotifications.publishPollResults(); }); - test('Presentation upload notification', async ({ browser, context, page }) => { + test.fixme('Presentation upload notification', async ({ browser, context, page }) => { // this test is unstable, there's an apparent timing issue around the visibility of smallToastMsg const presenterNotifications = new PresenterNotifications(browser, context); await presenterNotifications.initPages(page); await presenterNotifications.fileUploaderNotification(); diff --git a/bigbluebutton-tests/playwright/package-lock.json b/bigbluebutton-tests/playwright/package-lock.json index 115453b2cf..bc83176eb6 100644 --- a/bigbluebutton-tests/playwright/package-lock.json +++ b/bigbluebutton-tests/playwright/package-lock.json @@ -4,12 +4,10 @@ "requires": true, "packages": { "": { - "name": "playwright", "devDependencies": { "@playwright/test": "^1.18.1", "axios": "^0.26.1", "dotenv": "^16.0.0", - "js-yaml": "^4.1.0", "playwright": "^1.18.1", "sha1": "^1.1.1" } @@ -1054,12 +1052,6 @@ "node": ">=4" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -1967,18 +1959,6 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3410,12 +3390,6 @@ "color-convert": "^1.9.0" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -4093,15 +4067,6 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", diff --git a/bigbluebutton-tests/playwright/package.json b/bigbluebutton-tests/playwright/package.json index e9017df040..fb7a7414c8 100644 --- a/bigbluebutton-tests/playwright/package.json +++ b/bigbluebutton-tests/playwright/package.json @@ -9,7 +9,6 @@ "@playwright/test": "^1.18.1", "axios": "^0.26.1", "dotenv": "^16.0.0", - "js-yaml": "^4.1.0", "playwright": "^1.18.1", "sha1": "^1.1.1" } diff --git a/bigbluebutton-tests/playwright/polling/poll.js b/bigbluebutton-tests/playwright/polling/poll.js index 435b62da97..4f22ab4d06 100644 --- a/bigbluebutton-tests/playwright/polling/poll.js +++ b/bigbluebutton-tests/playwright/polling/poll.js @@ -1,4 +1,4 @@ -const { expect } = require('@playwright/test'); +const { expect, default: test } = require('@playwright/test'); const { MultiUsers } = require('../user/multiusers'); const e = require('../core/elements'); const util = require('./util.js'); @@ -64,6 +64,9 @@ class Polling extends MultiUsers { } async pollResultsOnChat() { + const { pollChatMessage } = getSettings(); + test.fail(!pollChatMessage, 'Poll results on chat is disabled'); + await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME); await util.startPoll(this.modPage, true); await this.modPage.waitAndClick(e.chatButton); diff --git a/bigbluebutton-tests/playwright/polling/polling.spec.js b/bigbluebutton-tests/playwright/polling/polling.spec.js index b5d05df9d3..a6a84722e7 100644 --- a/bigbluebutton-tests/playwright/polling/polling.spec.js +++ b/bigbluebutton-tests/playwright/polling/polling.spec.js @@ -12,7 +12,7 @@ test.describe.parallel('Polling', () => { test('Create anonymous poll', async ({ browser, context, page }) => { const polling = new Polling(browser, context); await polling.initPages(page); - await polling.pollAnonymous() + await polling.pollAnonymous(); }); test('Create quick poll - from the slide', async ({ browser, context, page }) => { diff --git a/bigbluebutton-tests/playwright/polling/util.js b/bigbluebutton-tests/playwright/polling/util.js index b33b0949bc..5514e7a407 100644 --- a/bigbluebutton-tests/playwright/polling/util.js +++ b/bigbluebutton-tests/playwright/polling/util.js @@ -1,6 +1,10 @@ const e = require('../core/elements.js'); +const { getSettings } = require('../core/settings.js'); async function openPoll(test) { + const { pollEnabled } = getSettings(); + test.fail(!pollEnabled, 'Polling is disabled'); + await test.waitAndClick(e.actions); await test.waitAndClick(e.polling); await test.waitForSelector(e.hidePollDesc); diff --git a/bigbluebutton-tests/playwright/presentation/presentation.js b/bigbluebutton-tests/playwright/presentation/presentation.js index 5ddc9fc95c..4f698ab2c5 100644 --- a/bigbluebutton-tests/playwright/presentation/presentation.js +++ b/bigbluebutton-tests/playwright/presentation/presentation.js @@ -1,10 +1,11 @@ -const { expect } = require('@playwright/test'); +const { expect, default: test } = require('@playwright/test'); const { MultiUsers } = require('../user/multiusers'); const Page = require('../core/page'); const e = require('../core/elements'); const { checkSvgIndex, getSvgOuterHtml, uploadPresentation } = require('./util.js'); const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); const { sleep } = require('../core/helpers'); +const { getSettings } = require('../core/settings'); class Presentation extends MultiUsers { constructor(browser, context) { @@ -31,8 +32,11 @@ class Presentation extends MultiUsers { } async hideAndRestorePresentation() { - await this.modPage.waitForSelector(e.whiteboard); - await this.modPage.waitAndClick(e.minimizePresentation); + const { presentationHidden } = getSettings(); + if (!presentationHidden) { + await this.modPage.waitForSelector(e.whiteboard); + await this.modPage.waitAndClick(e.minimizePresentation); + } await this.modPage.wasRemoved(e.presentationContainer); await this.modPage.waitAndClick(e.restorePresentation); @@ -40,6 +44,9 @@ class Presentation extends MultiUsers { } async startExternalVideo() { + const { externalVideoPlayer } = getSettings(); + test.fail(!externalVideoPlayer, 'External video is disabled'); + await this.modPage.waitForSelector(e.whiteboard); await this.modPage.waitAndClick(e.actions); await this.modPage.waitAndClick(e.shareExternalVideoBtn); @@ -72,7 +79,10 @@ class Presentation extends MultiUsers { await expect(userSlides0).not.toEqual(userSlides1); } - async allowAndDisallowDownload() { + async allowAndDisallowDownload(testInfo) { + const { presentationDownloadable } = getSettings(); + test.fail(!presentationDownloadable, 'Presentation download is disable'); + // allow the presentation download await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME); await this.modPage.waitAndClick(e.actions); @@ -83,6 +93,7 @@ class Presentation extends MultiUsers { await this.userPage.waitForSelector(e.toastDownload); // check download button in presentation after ALLOW it - should be true await this.userPage.hasElement(e.presentationDownloadBtn); + await this.userPage.handleDownload(e.presentationDownloadBtn, testInfo); // disallow the presentation download await this.modPage.waitAndClick(e.actions); diff --git a/bigbluebutton-tests/playwright/presentation/presentation.spec.js b/bigbluebutton-tests/playwright/presentation/presentation.spec.js index cc951c566e..29c155e834 100644 --- a/bigbluebutton-tests/playwright/presentation/presentation.spec.js +++ b/bigbluebutton-tests/playwright/presentation/presentation.spec.js @@ -27,10 +27,10 @@ test.describe.parallel('Presentation', () => { await presentation.uploadPresentationTest(); }); - test('Allow and disallow presentation download', async ({ browser, context, page }) => { + test('Allow and disallow presentation download', async ({ browser, context, page }, testInfo) => { const presentation = new Presentation(browser, context); await presentation.initPages(page); - await presentation.allowAndDisallowDownload(); + await presentation.allowAndDisallowDownload(testInfo); }); test('Remove all presentation', async ({ browser, context, page }) => { diff --git a/bigbluebutton-tests/playwright/presentation/util.js b/bigbluebutton-tests/playwright/presentation/util.js index 78feda58a1..e22c861179 100644 --- a/bigbluebutton-tests/playwright/presentation/util.js +++ b/bigbluebutton-tests/playwright/presentation/util.js @@ -19,7 +19,7 @@ async function uploadPresentation(test, fileName, uploadTimeout = ELEMENT_WAIT_L await test.waitAndClick(e.managePresentations); await test.waitForSelector(e.fileUpload); - await test.page.setInputFiles(e.fileUpload, path.join(__dirname, `../media/${fileName}`)); + await test.page.setInputFiles(e.fileUpload, path.join(__dirname, `../core/media/${fileName}`)); await test.hasText('body', e.statingUploadPresentationToast); await test.waitAndClick(e.confirmManagePresentation); diff --git a/bigbluebutton-tests/playwright/screenshare/screenshare.js b/bigbluebutton-tests/playwright/screenshare/screenshare.js index 01c4244282..e9dd40aea9 100644 --- a/bigbluebutton-tests/playwright/screenshare/screenshare.js +++ b/bigbluebutton-tests/playwright/screenshare/screenshare.js @@ -1,6 +1,8 @@ +const { default: test } = require('@playwright/test'); const Page = require('../core/page'); -const { startScreenshare, getScreenShareBreakoutContainer } = require('./util'); +const { startScreenshare } = require('./util'); const e = require('../core/elements'); +const { getSettings } = require('../core/settings'); class ScreenShare extends Page { constructor(browser, page) { @@ -8,6 +10,8 @@ class ScreenShare extends Page { } async startSharing() { + const { screensharingEnabled } = getSettings(); + test.fail(!screensharingEnabled, 'Screensharing is disabled'); await startScreenshare(this); await this.hasElement(e.isSharingScreen); } diff --git a/bigbluebutton-tests/playwright/settings/util.js b/bigbluebutton-tests/playwright/settings/util.js index 9cb0dd2cb9..7075d96a84 100644 --- a/bigbluebutton-tests/playwright/settings/util.js +++ b/bigbluebutton-tests/playwright/settings/util.js @@ -11,7 +11,7 @@ async function getLocaleValues(elements, locale) { let currentLocale = {}; try { currentLocale = require(`../../../bigbluebutton-html5/public/locales/${locale.replace('-', '_')}.json`); - } catch (e) { } + } catch (err) { } for (const selector in elements) { const currentKey = elements[selector]; @@ -22,7 +22,7 @@ async function getLocaleValues(elements, locale) { let generalLocale = {}; try { generalLocale = require(`../../../bigbluebutton-html5/public/locales/${generalLocaleName}.json`); - } catch (e) { } + } catch (err) { } return generalLocale[currentKey] ? generalLocale[currentKey] : defaultLocale[currentKey]; } } diff --git a/bigbluebutton-tests/playwright/sharednotes/sharednotes.js b/bigbluebutton-tests/playwright/sharednotes/sharednotes.js index a48ed35108..4da29c242b 100644 --- a/bigbluebutton-tests/playwright/sharednotes/sharednotes.js +++ b/bigbluebutton-tests/playwright/sharednotes/sharednotes.js @@ -1,4 +1,6 @@ +const { default: test } = require('@playwright/test'); const Page = require('../core/page'); +const { getSettings } = require('../core/settings'); const { startSharedNotes } = require('./util'); class SharedNotes extends Page { @@ -7,6 +9,8 @@ class SharedNotes extends Page { } async openSharedNotes() { + const { sharedNotesEnabled } = getSettings(); + test.fail(!sharedNotesEnabled, 'Shared notes is disabled'); await startSharedNotes(this); } } diff --git a/bigbluebutton-tests/playwright/stress/stress.spec.js b/bigbluebutton-tests/playwright/stress/stress.spec.js index ad02557ecd..b0ccc77e61 100644 --- a/bigbluebutton-tests/playwright/stress/stress.spec.js +++ b/bigbluebutton-tests/playwright/stress/stress.spec.js @@ -9,7 +9,7 @@ test.describe.parallel('Stress', () => { await stress.moderatorAsPresenter(); }); - test('All users must receive breakout room invitations', async ({ browser, context, page }) => { + test.fixme('All users must receive breakout room invitations', async ({ browser, context, page }) => { const stress = new Stress(browser, context, page); await stress.breakoutRoomInvitation(); }); diff --git a/bigbluebutton-tests/playwright/user/lockViewers.js b/bigbluebutton-tests/playwright/user/lockViewers.js index d3bdb4670a..db1eb6f3b8 100644 --- a/bigbluebutton-tests/playwright/user/lockViewers.js +++ b/bigbluebutton-tests/playwright/user/lockViewers.js @@ -20,7 +20,7 @@ class LockViewers extends MultiUsers { await openLockViewers(this.modPage); await this.modPage.waitAndClickElement(e.lockShareWebcam); await this.modPage.waitAndClick(e.applyLockSettings); - await waitAndClearNotification(this.modPage); + // await waitAndClearNotification(this.modPage); // notification check is unstable const videoContainerLockedCount = await this.userPage2.getSelectorCount(e.webcamVideoItem); expect(videoContainerLockedCount).toBe(1); @@ -99,13 +99,13 @@ class LockViewers extends MultiUsers { } async lockSeeOtherViewersUserList() { - const usersCount = this.userPage.getLocator(e.userListItem); - expect(await usersCount.count()).toBe(2); + expect(await this.userPage.getLocator(e.userListItem).count()).toBe(2); await openLockViewers(this.modPage); await this.modPage.waitAndClickElement(e.lockUserList); await this.modPage.waitAndClick(e.applyLockSettings); - expect(await usersCount.count()).toBe(1); + await sleep(1000); + expect(await this.userPage.getLocator(e.userListItem).count()).toBe(1); await this.userPage2.hasText(e.userListItem, this.modPage.username); } diff --git a/bigbluebutton-tests/playwright/user/multiusers.js b/bigbluebutton-tests/playwright/user/multiusers.js index 9ee13fd256..53151f1835 100644 --- a/bigbluebutton-tests/playwright/user/multiusers.js +++ b/bigbluebutton-tests/playwright/user/multiusers.js @@ -1,9 +1,11 @@ -const { expect } = require('@playwright/test'); +const { expect, default: test } = require('@playwright/test'); const Page = require('../core/page'); const e = require('../core/elements'); const { waitAndClearNotification } = require('../notifications/util'); const { sleep } = require('../core/helpers'); const { checkAvatarIcon, checkIsPresenter } = require('./util'); +const { checkTextContent } = require('../core/util'); +const { getSettings } = require('../core/settings'); class MultiUsers { constructor(browser, context) { @@ -118,20 +120,16 @@ class MultiUsers { await this.modPage2.wasRemoved(e.manageUsers); } - async raiseHandTest() { + async raiseAndLowerHand() { + const { raiseHandButton } = getSettings(); + test.fail(!raiseHandButton, 'Raise/lower hand button is disabled'); + await this.userPage.waitAndClick(e.raiseHandBtn); await this.userPage.hasElement(e.lowerHandBtn); - } - - async getAvatarColorAndCompareWithUserListItem() { const getBackgroundColorComputed = (locator) => locator.evaluate((elem) => getComputedStyle(elem).backgroundColor); - const avatarInToastElementColor = this.modPage.getLocator(e.avatarsWrapperAvatar); const avatarInUserListColor = this.modPage.getLocator(`${e.userListItem} > div ${e.userAvatar}`); await expect(getBackgroundColorComputed(avatarInToastElementColor)).toStrictEqual(getBackgroundColorComputed(avatarInUserListColor)); - } - - async lowerHandTest() { await waitAndClearNotification(this.userPage); await this.userPage.waitAndClick(e.lowerHandBtn); await this.userPage.hasElement(e.raiseHandBtn); @@ -151,6 +149,18 @@ class MultiUsers { await this.modPage.hasElement(e.chatButton); } + async saveUserNames(testInfo) { + await this.modPage.waitAndClick(e.manageUsers); + const { content } = await this.modPage.handleDownload(e.downloadUserNamesList, testInfo); + + const dataToCheck = [ + this.modPage.username, + this.userPage.username, + this.modPage.meetingId, + ]; + await checkTextContent(content, dataToCheck); + } + async selectRandomUser() { // check with no viewer joined await this.modPage.waitAndClick(e.actions); diff --git a/bigbluebutton-tests/playwright/user/user.spec.js b/bigbluebutton-tests/playwright/user/user.spec.js index c1f99ae0b3..d5dc519108 100644 --- a/bigbluebutton-tests/playwright/user/user.spec.js +++ b/bigbluebutton-tests/playwright/user/user.spec.js @@ -12,9 +12,7 @@ test.describe.parallel('User', () => { test('Raise and lower Hand Toast', async ({ browser, context, page }) => { const multiusers = new MultiUsers(browser, context); await multiusers.initPages(page); - await multiusers.raiseHandTest(); - await multiusers.getAvatarColorAndCompareWithUserListItem(); - await multiusers.lowerHandTest(); + await multiusers.raiseAndLowerHand(); }); test('Toggle user list', async ({ browser, context, page }) => { @@ -142,6 +140,12 @@ test.describe.parallel('User', () => { }); }); + test('Save user names', async ({ browser, context, page }, testInfo) => { + const multiusers = new MultiUsers(browser, context); + await multiusers.initPages(page); + await multiusers.saveUserNames(testInfo); + }); + test('Select random user', async ({ browser, context, page }) => { const multiusers = new MultiUsers(browser, context); await multiusers.initModPage(page); diff --git a/bigbluebutton-tests/playwright/virtualizedlist/virtualize.js b/bigbluebutton-tests/playwright/virtualizedlist/virtualize.js index fdf4dfdf29..e6f34c9bb4 100644 --- a/bigbluebutton-tests/playwright/virtualizedlist/virtualize.js +++ b/bigbluebutton-tests/playwright/virtualizedlist/virtualize.js @@ -13,7 +13,7 @@ class VirtualizeList { // Join BigBlueButton meeting async init() { await this.page1.init(true, true, { fullName: 'BroadCaster1' }); - await this.page1.waitForSelector(e.anyUser); + await this.page1.waitForSelector(e.firstUser); for (let i = 1; i <= parseInt(USER_LIST_VLIST_BOTS_LISTENING); i++) { const newPage = await this.browser.newPage(); const viewerPage = new Page(this.browser, newPage); @@ -26,7 +26,7 @@ class VirtualizeList { } async test() { - const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.getSelectorCount(e.anyUser); + const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.getSelectorCount(e.userListItem); const totalNumberOfUsersMongo = await this.page1.page.evaluate(() => { const collection = require('/imports/api/users/index.js'); return collection.default._collection.find().count(); diff --git a/bigbluebutton-tests/playwright/virtualizedlist/virtualizedlist.spec.js b/bigbluebutton-tests/playwright/virtualizedlist/virtualizedlist.spec.js index 084e51ad40..9fdba2e40e 100644 --- a/bigbluebutton-tests/playwright/virtualizedlist/virtualizedlist.spec.js +++ b/bigbluebutton-tests/playwright/virtualizedlist/virtualizedlist.spec.js @@ -2,7 +2,7 @@ const { test } = require('@playwright/test'); const { VirtualizeList } = require('./virtualize'); test.describe.parallel('Virtualize list', () => { - test('Virtualized Users List', async ({ browser, page }) => { + test.fixme('Virtualized Users List', async ({ browser, page }) => { test.setTimeout(0); const virtualizeList = new VirtualizeList(browser, page); await virtualizeList.init(); diff --git a/bigbluebutton-tests/playwright/webcam/webcam.js b/bigbluebutton-tests/playwright/webcam/webcam.js index a4222fc115..051c8b8125 100644 --- a/bigbluebutton-tests/playwright/webcam/webcam.js +++ b/bigbluebutton-tests/playwright/webcam/webcam.js @@ -10,20 +10,15 @@ class Webcam extends Page { } async share() { - const parsedSettings = await this.getSettingsYaml(); - const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout); - await this.shareWebcam(videoPreviewTimeout); - + const { videoPreviewTimeout, skipVideoPreview, skipVideoPreviewOnFirstJoin } = this.settings; + await this.shareWebcam(!(skipVideoPreview || skipVideoPreviewOnFirstJoin), videoPreviewTimeout); await this.hasElement('video'); } async checksContent() { - const parsedSettings = await this.getSettingsYaml(); - const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout); - - await this.shareWebcam(videoPreviewTimeout); + const { videoPreviewTimeout, skipVideoPreview, skipVideoPreviewOnFirstJoin } = this.settings; + await this.shareWebcam(!(skipVideoPreview || skipVideoPreviewOnFirstJoin), videoPreviewTimeout); const respUser = await webcamContentCheck(this); - await expect(respUser).toBeTruthy(); } @@ -37,9 +32,8 @@ class Webcam extends Page { async webcamLayoutStart() { await this.joinMicrophone(); - const parsedSettings = await this.getSettingsYaml(); - const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout); - await this.shareWebcam(videoPreviewTimeout); + const { videoPreviewTimeout, skipVideoPreview, skipVideoPreviewOnFirstJoin } = this.settings; + await this.shareWebcam(!(skipVideoPreview || skipVideoPreviewOnFirstJoin), videoPreviewTimeout); } } diff --git a/bigbluebutton-tests/playwright/webcam/webcam.spec.js b/bigbluebutton-tests/playwright/webcam/webcam.spec.js index 8cf425a3af..a9746bc4f7 100644 --- a/bigbluebutton-tests/playwright/webcam/webcam.spec.js +++ b/bigbluebutton-tests/playwright/webcam/webcam.spec.js @@ -2,19 +2,19 @@ const { test } = require('@playwright/test'); const { Webcam } = require('./webcam'); test.describe.parallel('Webcam', () => { - test('Shares webcam', async ({ browser, context, page }) => { + test('Shares webcam', async ({ browser, page }) => { const webcam = new Webcam(browser, page); await webcam.init(true, true); await webcam.share(); }); - test('Checks content of webcam', async ({ browser, context, page }) => { + test('Checks content of webcam', async ({ browser, page }) => { const webcam = new Webcam(browser, page); await webcam.init(true, true); await webcam.checksContent(); }); - test('Checks webcam talking indicator', async ({ browser, context, page }) => { + test('Checks webcam talking indicator', async ({ browser, page }) => { const webcam = new Webcam(browser, page); await webcam.init(true, false); await webcam.talkingIndicator(); diff --git a/bigbluebutton-web/.dockerignore b/bigbluebutton-web/.dockerignore deleted file mode 100644 index 94143827ed..0000000000 --- a/bigbluebutton-web/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -Dockerfile diff --git a/bigbluebutton-web/Dockerfile b/bigbluebutton-web/Dockerfile deleted file mode 100644 index 74a4d6837f..0000000000 --- a/bigbluebutton-web/Dockerfile +++ /dev/null @@ -1,64 +0,0 @@ -FROM bbb-common-web AS builder - -RUN mkdir -p /root/tools \ - && cd /root/tools \ - && wget https://services.gradle.org/distributions/gradle-2.12-bin.zip \ - && unzip gradle-2.12-bin.zip \ - && ln -s gradle-2.12 gradle - -RUN mkdir -p /root/tools \ - && cd /root/tools \ - && wget https://github.com/grails/grails-core/releases/download/v2.5.2/grails-2.5.2.zip \ - && unzip grails-2.5.2.zip \ - && ln -s grails-2.5.2 grails - -ENV PATH="/root/tools/gradle/bin:/root/tools/grails/bin:${PATH}" - -ARG COMMON_VERSION=0.0.1-SNAPSHOT - -COPY . /source - -RUN cd /source \ - && find -name build.gradle -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-message[^:]*\):.*|\1:$COMMON_VERSION'|g" {} \; \ - && find -name build.gradle -exec sed -i "s|\(.*org.bigbluebutton.*bbb-common-web[^:]*\):.*|\1:$COMMON_VERSION'|g" {} \; - -RUN cd /source \ - && gradle resolveDeps \ - && grails war - -FROM tomcat:7-jre8 - -WORKDIR $CATALINA_HOME - -ENV DOCKERIZE_VERSION v0.6.1 -RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz - -ENV DEBIAN_FRONTEND noninteractive -RUN apt-get update \ - && apt-get -y install imagemagick xpdf-utils netcat libreoffice ttf-liberation fonts-crosextra-carlito fonts-crosextra-caladea unzip procps \ - && wget http://ftp.us.debian.org/debian/pool/main/libj/libjpeg8/libjpeg8_8d-1+deb7u1_amd64.deb \ - && dpkg -i libjpeg8*.deb \ - && rm libjpeg8*.deb - -RUN echo "deb http://ubuntu.bigbluebutton.org/xenial-200-dev bigbluebutton-xenial main " | tee /etc/apt/sources.list.d/bigbluebutton.list \ - && wget http://ubuntu.bigbluebutton.org/repo/bigbluebutton.asc -O- | apt-key add - \ - && apt-get update \ - && apt-get -y install bbb-swftools - -# clean default webapps -RUN rm -r webapps/* - -COPY --from=builder /source/target/bigbluebutton-0.9.0.war webapps/bigbluebutton.war - -RUN unzip -q webapps/bigbluebutton.war -d webapps/bigbluebutton \ - && rm webapps/bigbluebutton.war - -COPY turn-stun-servers.xml.tmpl turn-stun-servers.xml.tmpl - -COPY docker-entrypoint.sh /usr/local/bin/ - -CMD [ "dockerize", \ - "-template", "turn-stun-servers.xml.tmpl:webapps/bigbluebutton/WEB-INF/spring/turn-stun-servers.xml", \ - "docker-entrypoint.sh" ] diff --git a/bigbluebutton-web/build.gradle b/bigbluebutton-web/build.gradle index 9c2989b1db..a2076b3acf 100755 --- a/bigbluebutton-web/build.gradle +++ b/bigbluebutton-web/build.gradle @@ -57,7 +57,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-autoconfigure" implementation "org.grails:grails-core" implementation "org.springframework.boot:spring-boot-starter-actuator" - implementation "org.springframework.boot:spring-boot-starter-tomcat" + implementation "org.springframework.boot:spring-boot-starter-tomcat:2.6.6" implementation "org.grails:grails-web-boot" implementation "org.grails:grails-logging" implementation "org.grails:grails-plugin-rest" @@ -72,6 +72,10 @@ dependencies { implementation "org.grails.plugins:scaffolding" implementation "org.grails.plugins:events" implementation "org.grails.plugins:gsp" + implementation "org.apache.tomcat.embed:tomcat-embed-core:${tomcatEmbedVersion}" + implementation "org.apache.tomcat.embed:tomcat-embed-el:${tomcatEmbedVersion}" + implementation "org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatEmbedVersion}" + implementation "org.apache.tomcat:tomcat-annotations-api:${tomcatEmbedVersion}" //--- BigBlueButton Dependencies Start - Transitive dependencies have to be re-defined below implementation "org.bigbluebutton:bbb-common-message_2.13:0.0.21-SNAPSHOT" implementation "org.bigbluebutton:bbb-common-web:0.0.3-SNAPSHOT" diff --git a/bigbluebutton-web/docker-entrypoint.sh b/bigbluebutton-web/docker-entrypoint.sh deleted file mode 100755 index ff6b757180..0000000000 --- a/bigbluebutton-web/docker-entrypoint.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -xe - -mkdir -p /var/bigbluebutton/recording/raw -mkdir -p /var/bigbluebutton/recording/process -mkdir -p /var/bigbluebutton/recording/publish -mkdir -p /var/bigbluebutton/recording/status/recorded -mkdir -p /var/bigbluebutton/recording/status/archived -mkdir -p /var/bigbluebutton/recording/status/processed -mkdir -p /var/bigbluebutton/recording/status/sanity -mkdir -p /var/bigbluebutton/published -mkdir -p /var/bigbluebutton/deleted -mkdir -p /var/bigbluebutton/unpublished - -export JAVA_OPTS="${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -DsecuritySalt=${SHARED_SECRET} -Dredis.host=redis -DredisHost=redis -Dbigbluebutton.web.serverURL=https://${SERVER_DOMAIN} -DsvgImagesRequired=true" -sed -i "s|^securerandom\.source=.*|securerandom.source=file:/dev/urandom|g" ${JAVA_HOME}/lib/security/java.security - -exec catalina.sh run diff --git a/bigbluebutton-web/gradle.properties b/bigbluebutton-web/gradle.properties index 506fcddc46..535320c838 100644 --- a/bigbluebutton-web/gradle.properties +++ b/bigbluebutton-web/gradle.properties @@ -2,4 +2,5 @@ grailsVersion=5.0.1 gormVersion=7.1.0 gradleWrapperVersion=7.3.1 grailsGradlePluginVersion=5.0.0 -groovyVersion=3.0.9 \ No newline at end of file +groovyVersion=3.0.9 +tomcatEmbedVersion=9.0.62 diff --git a/bigbluebutton-web/grails-app/conf/application.yml b/bigbluebutton-web/grails-app/conf/application.yml index 27de1c78ef..d0d3a63239 100644 --- a/bigbluebutton-web/grails-app/conf/application.yml +++ b/bigbluebutton-web/grails-app/conf/application.yml @@ -35,9 +35,10 @@ endpoints: enabled: true server: - session: - cookie: - secure: true + servlet: + session: + cookie: + secure: true --- grails: diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties index cab5db13ab..e70facc768 100755 --- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties +++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties @@ -181,7 +181,7 @@ authenticatedGuest=true #--------------------------------------------------- # Default Meeting Layout # Valid values are CUSTOM_LAYOUT, SMART_LAYOUT, PRESENTATION_FOCUS, VIDEO_FOCUS -defaultMeetingLayout=SMART_LAYOUT +defaultMeetingLayout=CUSTOM_LAYOUT # #---------------------------------------------------- @@ -196,7 +196,7 @@ defaultMeetingLayout=SMART_LAYOUT # # native2ascii -encoding UTF8 bigbluebutton.properties bigbluebutton.properties # -defaultWelcomeMessage=Welcome to %%CONFNAME%%!

For help on using BigBlueButton see these (short) tutorial videos.

To join the audio bridge click the phone button. Use a headset to avoid causing background noise for others. +defaultWelcomeMessage=Welcome to %%CONFNAME%%!

For help on using BigBlueButton see these (short) tutorial videos.

To join the audio bridge click the speaker button. Use a headset to avoid causing background noise for others. defaultWelcomeMessageFooter=This server is running BigBlueButton. # Default maximum number of users a meeting can have. @@ -363,6 +363,8 @@ beans.presentationService.testPresentationName=appkonference beans.presentationService.testUploadedPresentation=appkonference.txt # Default Uploaded presentation file beans.presentationService.defaultUploadedPresentation=${bigbluebutton.web.serverURL}/default.pdf +# Discard default presentation (default.pdf) when Pre-upload Slides are sent within the create call (default true) +beans.presentationService.preUploadedPresentationOverrideDefault=true presentationBaseURL=${bigbluebutton.web.serverURL}/bigbluebutton/presentation diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy index d86bf5d026..43f9366729 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy @@ -264,14 +264,56 @@ class ApiController { // Now determine if this user is a moderator or a viewer. String role = null; - if (meeting.getModeratorPassword().equals(attPW)) { - role = Meeting.ROLE_MODERATOR - } else if (meeting.getViewerPassword().equals(attPW)) { - role = Meeting.ROLE_ATTENDEE - } + // First Case: send a valid role if (!StringUtils.isEmpty(params.role) && roles.containsKey(params.role.toLowerCase())) { - role = roles.get(params.role.toLowerCase()); + role = roles.get(params.role.toLowerCase()); + + // Second case: role is not present or valid BUT there is password + } else if (attPW != null && !attPW.isEmpty()){ + // Check if the meeting has passwords + if ((meeting.getModeratorPassword() != null && !meeting.getModeratorPassword().isEmpty()) + && (meeting.getViewerPassword() != null && !meeting.getViewerPassword().isEmpty())){ + // Check which role does the user belong + if (meeting.getModeratorPassword().equals(attPW)) { + role = Meeting.ROLE_MODERATOR + } else if (meeting.getViewerPassword().equals(attPW)) { + role = Meeting.ROLE_ATTENDEE + } else { + log.debug("Password does not match any of the registered ones"); + response.addHeader("Cache-Control", "no-cache") + withFormat { + xml { + render(text: responseBuilder.buildError("Params required", "You must enter a valid password", + RESP_CODE_FAILED), contentType: "text/xml") + } + } + return + } + // In this case, the meeting doesn't have any password registered and there is no role param + } else { + log.debug("This meeting doesn't have any password"); + response.addHeader("Cache-Control", "no-cache") + withFormat { + xml { + render(text: responseBuilder.buildError("Params required", "You must send the 'role' parameter, since " + + "this meeting doesn't have any password.", RESP_CODE_FAILED), contentType: "text/xml") + } + } + return + } + + // Third case: No valid role + no valid password + } else { + log.debug("No matching params encountered"); + response.addHeader("Cache-Control", "no-cache") + withFormat { + xml { + render(text: responseBuilder.buildError("Params required", "You must either send the valid role of the user, or " + + "the password, sould the meeting has one.", RESP_CODE_FAILED), contentType: "text/xml") + } + } + return } // We preprend "w_" to our internal meeting Id to indicate that this is a web user. @@ -1273,75 +1315,93 @@ class ApiController { key, value -> params[key] = sanitizeInput(value) } + Boolean preUploadedPresentationOverrideDefault=true + if (!isFromInsertAPI) { + String[] po = request.getParameterMap().get("preUploadedPresentationOverrideDefault") + if (po == null) preUploadedPresentationOverrideDefault = presentationService.preUploadedPresentationOverrideDefault.toBoolean() + else preUploadedPresentationOverrideDefault = po[0].toBoolean() + } + + Boolean isDefaultPresentationUsed = false; String requestBody = request.inputStream == null ? null : request.inputStream.text; requestBody = StringUtils.isEmpty(requestBody) ? null : requestBody; + Boolean isDefaultPresentationCurrent = false; + def listOfPresentation = [] if (requestBody == null) { if (isFromInsertAPI){ log.warn("Insert Document API called without a payload - ignoring") return; } - downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId(), true /* default presentation */, '', false, true); + listOfPresentation << [name: "default", current: true]; } else { def xml = new XmlSlurper().parseText(requestBody); + Boolean hasCurrent = false; xml.children().each { module -> log.debug("module config found: [${module.@name}]"); if ("presentation".equals(module.@name.toString())) { - // need to iterate over presentation files and process them - // In this first foreach we are going to know if some presentation has - // the current property - def Boolean hasCurrent = false; for (document in module.children()) { if (!StringUtils.isEmpty(document.@current.toString()) && java.lang.Boolean.parseBoolean( - document.@current.toString())) { + document.@current.toString()) && !hasCurrent) { + listOfPresentation.add(0, document) hasCurrent = true; - break - } - } - Boolean foundCurrent = !hasCurrent; - int lastIndex = module.children().size() - 1 - module.children().eachWithIndex { document, index -> - def Boolean isCurrent = false; - def Boolean isRemovable = true; - def Boolean isDownloadable = false; - if (index == 0 && !hasCurrent){ - isCurrent = true - } - - // Extracting all properties inside the xml - if (!StringUtils.isEmpty(document.@removable.toString())) { - isRemovable = java.lang.Boolean.parseBoolean(document.@removable.toString()); - } - if (!StringUtils.isEmpty(document.@downloadable.toString())) { - isDownloadable = java.lang.Boolean.parseBoolean(document.@downloadable.toString()); - } - // I need to make sure that only one of the documents is going to be the current. - if (!StringUtils.isEmpty(document.@current.toString()) && !foundCurrent) { - isCurrent = java.lang.Boolean.parseBoolean(document.@current.toString()); - foundCurrent = isCurrent; - } - - isCurrent = isCurrent && !isFromInsertAPI - - // Verifying whether the document is a base64 encoded or a url to download. - if (!StringUtils.isEmpty(document.@url.toString())) { - def fileName; - if (!StringUtils.isEmpty(document.@filename.toString())) { - log.debug("user provided filename: [${module.@filename}]"); - fileName = document.@filename.toString(); - } - downloadAndProcessDocument(document.@url.toString(), conf.getInternalId(), isCurrent /* default presentation */, - fileName, isDownloadable, isRemovable); - } else if (!StringUtils.isEmpty(document.@name.toString())) { - def b64 = new Base64() - def decodedBytes = b64.decode(document.text().getBytes()) - processDocumentFromRawBytes(decodedBytes, document.@name.toString(), - conf.getInternalId(), isCurrent , isDownloadable, isRemovable/* default presentation */); } else { - log.debug("presentation module config found, but it did not contain url or name attributes"); + listOfPresentation << document } } + Boolean uploadDefault = !preUploadedPresentationOverrideDefault && !isDefaultPresentationUsed && !isFromInsertAPI; + if (uploadDefault) { + isDefaultPresentationCurrent = !hasCurrent; + hasCurrent = true + isDefaultPresentationUsed = true + if (isDefaultPresentationCurrent) { + listOfPresentation.add(0, [name: "default", current: true]) + } else { + listOfPresentation << [name: "default", current: false]; + } + } + } + } + } + + listOfPresentation.eachWithIndex { document, index -> + def Boolean isCurrent = false; + def Boolean isRemovable = true; + def Boolean isDownloadable = false; + + if (document.name != null && "default".equals(document.name)) { + downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId(), document.current /* default presentation */, '', false, true); + } else{ + // Extracting all properties inside the xml + if (!StringUtils.isEmpty(document.@removable.toString())) { + isRemovable = java.lang.Boolean.parseBoolean(document.@removable.toString()); + } + if (!StringUtils.isEmpty(document.@downloadable.toString())) { + isDownloadable = java.lang.Boolean.parseBoolean(document.@downloadable.toString()); + } + // The array has already been processed to let the first be the current. (This way it is + // ensured that only one document is current) + if (index == 0) { + isCurrent = true + } + isCurrent = isCurrent && !isFromInsertAPI + // Verifying whether the document is a base64 encoded or a url to download. + if (!StringUtils.isEmpty(document.@url.toString())) { + def fileName; + if (!StringUtils.isEmpty(document.@filename.toString())) { + log.debug("user provided filename: [${document.@filename}]"); + fileName = document.@filename.toString(); + } + downloadAndProcessDocument(document.@url.toString(), conf.getInternalId(), isCurrent /* default presentation */, + fileName, isDownloadable, isRemovable); + } else if (!StringUtils.isEmpty(document.@name.toString())) { + def b64 = new Base64() + def decodedBytes = b64.decode(document.text().getBytes()) + processDocumentFromRawBytes(decodedBytes, document.@name.toString(), + conf.getInternalId(), isCurrent, isDownloadable, isRemovable/* default presentation */); + } else { + log.debug("presentation module config found, but it did not contain url or name attributes"); } } } diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy index 6125c42777..f03d6cff79 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy @@ -126,6 +126,7 @@ class PresentationController { def filenameExt = "" def presId = "" def pres = null + def temporaryPresentationId = params.temporaryPresentationId def file = request.getFile('fileUpload') if (file && !file.empty) { @@ -161,6 +162,7 @@ class PresentationController { podId, meetingId, presId, + temporaryPresentationId, presFilename, presentationBaseUrl, current, diff --git a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy index f10b43302a..b35d2a4f3c 100755 --- a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy +++ b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy @@ -34,6 +34,7 @@ class PresentationService { def testUploadedPresentation def defaultUploadedPresentation def presentationBaseUrl + def preUploadedPresentationOverrideDefault def deletePresentation = {conf, room, filename -> def directory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + filename) diff --git a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/create-meeting.ftlx b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/create-meeting.ftlx index cb0aba7c9d..0d72856afa 100644 --- a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/create-meeting.ftlx +++ b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/create-meeting.ftlx @@ -6,8 +6,12 @@ ${meeting.getExternalId()} <#-- Yielded --> ${meeting.getInternalId()} <#-- Yielded --> ${meeting.getParentMeetingId()} <#-- Yielded --> - ${meeting.getViewerPassword()} <#-- Yielded --> - ${meeting.getModeratorPassword()} <#-- Yielded --> + <#if meeting.getViewerPassword()?? && meeting.getViewerPassword()!="" > + ${meeting.getViewerPassword()} + + <#if meeting.getModeratorPassword()?? && meeting.getModeratorPassword()!=""> + ${meeting.getModeratorPassword()} + ${meeting.getCreateTime()?c} ${meeting.getTelVoice()} <#-- Yielded --> ${meeting.getDialNumber()} <#-- Yielded --> diff --git a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meeting-info.ftlx b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meeting-info.ftlx index 3c461fa7db..57ad73a810 100755 --- a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meeting-info.ftlx +++ b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meeting-info.ftlx @@ -10,8 +10,12 @@ ${createdOn} ${meeting.getTelVoice()} ${meeting.getDialNumber()} - ${meeting.getViewerPassword()} - ${meeting.getModeratorPassword()} + <#if meeting.getViewerPassword()?? && meeting.getViewerPassword()!="" > + ${meeting.getViewerPassword()} + + <#if meeting.getModeratorPassword()?? && meeting.getModeratorPassword()!=""> + ${meeting.getModeratorPassword()} + ${meeting.isRunning()?c} ${meeting.getDuration()?c} ${meeting.hasUserJoined()?c} diff --git a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meetings.ftlx b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meetings.ftlx index 609f328aa7..2de87faba9 100755 --- a/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meetings.ftlx +++ b/bigbluebutton-web/src/main/webapp/WEB-INF/freemarker/get-meetings.ftlx @@ -15,8 +15,12 @@ ${meetingDetail.getCreatedOn()} ${meeting.getTelVoice()} ${meeting.getDialNumber()} - ${meeting.getViewerPassword()} - ${meeting.getModeratorPassword()} + <#if meeting.getViewerPassword()?? && meeting.getViewerPassword()!="" > + ${meeting.getViewerPassword()} + + <#if meeting.getModeratorPassword()?? && meeting.getModeratorPassword()!=""> + ${meeting.getModeratorPassword()} + ${meeting.isRunning()?c} ${meeting.getDuration()?c} ${meeting.hasUserJoined()?c} diff --git a/build/packages-template/bbb-config/after-install.sh b/build/packages-template/bbb-config/after-install.sh index da685ff5bf..f1689f62aa 100644 --- a/build/packages-template/bbb-config/after-install.sh +++ b/build/packages-template/bbb-config/after-install.sh @@ -130,6 +130,17 @@ if [ ! -e /etc/bigbluebutton/nginx/include_default.nginx ] ; then ln -s /usr/share/bigbluebutton/include_default.nginx /etc/bigbluebutton/nginx/include_default.nginx fi +# set full BBB version in settings.yml so it can be displayed in the client +BBB_RELEASE_FILE=/etc/bigbluebutton/bigbluebutton-release +BBB_HTML5_SETTINGS_FILE=/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml +if [[ -f $BBB_RELEASE_FILE ]] ; then + BBB_FULL_VERSION=$(cat $BBB_RELEASE_FILE | sed -n '/^BIGBLUEBUTTON_RELEASE/{s/.*=//;p}' ) + echo "setting BBB_FULL_VERSION=$BBB_FULL_VERSION in $BBB_HTML5_SETTINGS_FILE " + if [[ -f $BBB_HTML5_SETTINGS_FILE ]] ; then + yq w -i $BBB_HTML5_SETTINGS_FILE public.app.bbbServerVersion $BBB_FULL_VERSION + fi +fi + # Fix permissions for logging chown bigbluebutton:bigbluebutton /var/log/bbb-fsesl-akka diff --git a/build/packages-template/bbb-config/build.sh b/build/packages-template/bbb-config/build.sh index 0c1c797090..f216cc0160 100755 --- a/build/packages-template/bbb-config/build.sh +++ b/build/packages-template/bbb-config/build.sh @@ -83,4 +83,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --after-remove after-remove.sh \ --description "BigBlueButton configuration utilities" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-html5/after-install.sh b/build/packages-template/bbb-html5/after-install.sh index 1826a0a87b..e96d8df68f 100644 --- a/build/packages-template/bbb-html5/after-install.sh +++ b/build/packages-template/bbb-html5/after-install.sh @@ -60,7 +60,7 @@ source /etc/lsb-release # Set up specific version of node if [ "$DISTRIB_CODENAME" == "focal" ]; then - node_version="14.18.3" + node_version="14.19.1" if [[ ! -d /usr/share/node-v${node_version}-linux-x64 ]]; then cd /usr/share tar xfz "node-v${node_version}-linux-x64.tar.gz" diff --git a/build/packages-template/bbb-html5/build.sh b/build/packages-template/bbb-html5/build.sh index f79e1adbd1..4d04818d82 100755 --- a/build/packages-template/bbb-html5/build.sh +++ b/build/packages-template/bbb-html5/build.sh @@ -92,11 +92,11 @@ cp bbb-html5-frontend@.service staging/usr/lib/systemd/system mkdir -p staging/usr/share -if [ ! -f node-v14.18.3-linux-x64.tar.gz ]; then - wget https://nodejs.org/dist/v14.18.3/node-v14.18.3-linux-x64.tar.gz +if [ ! -f node-v14.19.1-linux-x64.tar.gz ]; then + wget https://nodejs.org/dist/v14.19.1/node-v14.19.1-linux-x64.tar.gz fi -cp node-v14.18.3-linux-x64.tar.gz staging/usr/share +cp node-v14.19.1-linux-x64.tar.gz staging/usr/share if [ -f staging/usr/share/meteor/bundle/programs/web.browser/head.html ]; then sed -i "s/VERSION/$(($BUILD))/" staging/usr/share/meteor/bundle/programs/web.browser/head.html @@ -129,4 +129,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --after-remove after-remove.sh \ --description "The HTML5 components for BigBlueButton" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-html5/opts-focal.sh b/build/packages-template/bbb-html5/opts-focal.sh index f2120b97bc..1c434e0f83 100644 --- a/build/packages-template/bbb-html5/opts-focal.sh +++ b/build/packages-template/bbb-html5/opts-focal.sh @@ -1,4 +1,3 @@ . ./opts-global.sh -# TODO - add yq OPTS="$OPTS -d bc,bbb-pads,bbb-webrtc-sfu,bbb-web,mongodb-org -t deb" diff --git a/build/packages-template/bbb-html5/systemd_start.sh b/build/packages-template/bbb-html5/systemd_start.sh index ea1f1f8011..05f7a48fbe 100644 --- a/build/packages-template/bbb-html5/systemd_start.sh +++ b/build/packages-template/bbb-html5/systemd_start.sh @@ -49,7 +49,7 @@ fi export MONGO_OPLOG_URL=mongodb://127.0.1.1/local export MONGO_URL=mongodb://127.0.1.1/meteor export NODE_ENV=production -export NODE_VERSION=node-v14.18.3-linux-x64 +export NODE_VERSION=node-v14.19.1-linux-x64 export SERVER_WEBSOCKET_COMPRESSION=0 export BIND_IP=127.0.0.1 PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=$INSTANCE_ID diff --git a/build/packages-template/bbb-html5/systemd_start_frontend.sh b/build/packages-template/bbb-html5/systemd_start_frontend.sh index 7ab471fe72..651ee51214 100644 --- a/build/packages-template/bbb-html5/systemd_start_frontend.sh +++ b/build/packages-template/bbb-html5/systemd_start_frontend.sh @@ -49,7 +49,7 @@ fi export MONGO_OPLOG_URL=mongodb://127.0.1.1/local export MONGO_URL=mongodb://127.0.1.1/meteor export NODE_ENV=production -export NODE_VERSION=node-v14.18.3-linux-x64 +export NODE_VERSION=node-v14.19.1-linux-x64 export SERVER_WEBSOCKET_COMPRESSION=0 export BIND_IP=127.0.0.1 PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js diff --git a/build/packages-template/bbb-playback-podcast/build.sh b/build/packages-template/bbb-playback-podcast/build.sh index 81fef06139..9da0a94297 100755 --- a/build/packages-template/bbb-playback-podcast/build.sh +++ b/build/packages-template/bbb-playback-podcast/build.sh @@ -42,6 +42,7 @@ fpm -s dir -C ./staging -n $PACKAGE \ --after-install after-install.sh \ --description "BigBluebutton playback in podcast" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-playback-presentation/build.sh b/build/packages-template/bbb-playback-presentation/build.sh index 1b34e14ac5..3cc6a059e2 100755 --- a/build/packages-template/bbb-playback-presentation/build.sh +++ b/build/packages-template/bbb-playback-presentation/build.sh @@ -42,6 +42,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --after-install after-install.sh \ --description "BigBluebutton playback of presentation" \ $DIRECTORIES \ - $OPTS - - + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-playback-presentation/opts-focal.sh b/build/packages-template/bbb-playback-presentation/opts-focal.sh index a08b591466..fcaf24a4c4 100755 --- a/build/packages-template/bbb-playback-presentation/opts-focal.sh +++ b/build/packages-template/bbb-playback-presentation/opts-focal.sh @@ -1,4 +1,3 @@ . ./opts-global.sh -# TODO - add yq OPTS="$OPTS -t deb -d bbb-record-core" diff --git a/build/packages-template/bbb-record-core/build.sh b/build/packages-template/bbb-record-core/build.sh index b8c19fea30..2383799f8d 100755 --- a/build/packages-template/bbb-record-core/build.sh +++ b/build/packages-template/bbb-record-core/build.sh @@ -59,4 +59,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --before-remove before-remove.sh \ --description "BigBlueButton record and playback" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-record-core/opts-focal.sh b/build/packages-template/bbb-record-core/opts-focal.sh index 494bc8debe..facb83987b 100755 --- a/build/packages-template/bbb-record-core/opts-focal.sh +++ b/build/packages-template/bbb-record-core/opts-focal.sh @@ -1,4 +1,3 @@ . ./opts-global.sh -# TODO - add yq OPTS="$OPTS -t deb -d bbb-mkclean,ffmpeg,gir1.2-pango-1.0,libcurl4,libncurses5,libsystemd0,poppler-utils,python3,python3-attr,python3-cairo,python3-gi,python3-gi-cairo,python3-icu,python3-lxml,redis-server,rsync,ruby,ruby-bundler,zlib1g" diff --git a/build/packages-template/bbb-webhooks/build.sh b/build/packages-template/bbb-webhooks/build.sh index c39ed572eb..2c077af26d 100755 --- a/build/packages-template/bbb-webhooks/build.sh +++ b/build/packages-template/bbb-webhooks/build.sh @@ -45,4 +45,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --before-remove before-remove.sh \ --description "BigBlueButton Webhooks" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-webhooks/opts-focal.sh b/build/packages-template/bbb-webhooks/opts-focal.sh index f830536f71..6a90d99154 100644 --- a/build/packages-template/bbb-webhooks/opts-focal.sh +++ b/build/packages-template/bbb-webhooks/opts-focal.sh @@ -1,4 +1,3 @@ . ./opts-global.sh -# TODO - add yq OPTS="$OPTS -t deb -d nodejs,npm" diff --git a/build/packages-template/bbb-webrtc-sfu/build.sh b/build/packages-template/bbb-webrtc-sfu/build.sh index e32807648e..fc6b3f6f0a 100755 --- a/build/packages-template/bbb-webrtc-sfu/build.sh +++ b/build/packages-template/bbb-webrtc-sfu/build.sh @@ -63,4 +63,5 @@ fpm -s dir -C ./staging -n $PACKAGE \ --before-remove before-remove.sh \ --description "BigBlueButton WebRTC SFU" \ $DIRECTORIES \ - $OPTS + $OPTS \ + -d 'yq (>= 3)' -d 'yq (<< 4)' diff --git a/build/packages-template/bbb-webrtc-sfu/opts-focal.sh b/build/packages-template/bbb-webrtc-sfu/opts-focal.sh index 914ee1584e..6e0aa914fc 100644 --- a/build/packages-template/bbb-webrtc-sfu/opts-focal.sh +++ b/build/packages-template/bbb-webrtc-sfu/opts-focal.sh @@ -1,4 +1,3 @@ . ./opts-global.sh -# TODO - add yq OPTS="$OPTS -t deb -d git-core,nginx,kurento-media-server,openh264-gst-plugins-bad-1.5,bbb-apps-akka,nodejs,npm,build-essential,xmlstarlet" diff --git a/labs/docker/Makefile b/labs/docker/Makefile deleted file mode 100644 index 8193e70121..0000000000 --- a/labs/docker/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -SHELL=/bin/bash - -# in order to build images for bigbluebutton/bigbluebutton-docker, run: -# IMAGE_ACCOUNT=bigbluebutton IMAGE_REPO=bigbluebutton-docker make release - -# build options -BUILD_REVISION=`git rev-parse --short HEAD` -BUILD_DIR_BASE=`git rev-parse --git-dir`/.. -BUILD_VERSION?= -BUILD_IMAGE=0 -IMAGE_ACCOUNT?= -IMAGE_REPO?= -IMAGE_TAG?=latest -TAG_REVISION?=0 - -all: release - -image: - -cd $(DIR) && docker build -t $(IMAGE_NAME):$(IMAGE_TAG) $(BUILD_ARGS) . - if [ "$(BUILD_IMAGE)" == "0" ]; then \ - if [ "$(IMAGE_ACCOUNT)" != "" ]; then \ - if [ "$(IMAGE_REPO)" != "" ]; then \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_ACCOUNT)/$(IMAGE_REPO):$(IMAGE_NAME); \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_ACCOUNT)/$(IMAGE_REPO):$(IMAGE_NAME)-$(IMAGE_TAG); \ - if [ "$(TAG_REVISION)" == "1" ]; then \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_ACCOUNT)/$(IMAGE_REPO):$(IMAGE_NAME)-$(BUILD_REVISION); \ - fi \ - fi \ - else \ - if [ "$(IMAGE_REPO)" != "" ]; then \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_REPO):$(IMAGE_NAME); \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_REPO):$(IMAGE_NAME)-$(IMAGE_TAG); \ - if [ "$(TAG_REVISION)" == "1" ]; then \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_REPO):$(IMAGE_NAME)-$(BUILD_REVISION); \ - fi \ - else \ - if [ "$(TAG_REVISION)" == "1" ]; then \ - docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_NAME):$(BUILD_REVISION); \ - fi \ - fi \ - fi \ - fi - -release: - make image DIR=$(BUILD_DIR_BASE)/labs/docker/sbt IMAGE_NAME=sbt IMAGE_TAG=0.13.8 BUILD_IMAGE=1 - make image DIR=$(BUILD_DIR_BASE)/bbb-common-message IMAGE_NAME=bbb-common-message BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" BUILD_IMAGE=1 - make image DIR=$(BUILD_DIR_BASE)/bbb-common-web IMAGE_NAME=bbb-common-web BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" BUILD_IMAGE=1 - make image DIR=$(BUILD_DIR_BASE)/bbb-fsesl-client IMAGE_NAME=bbb-fsesl-client BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" BUILD_IMAGE=1 - make image DIR=$(BUILD_DIR_BASE)/akka-bbb-apps IMAGE_NAME=bbb-apps-akka BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" - make image DIR=$(BUILD_DIR_BASE)/akka-bbb-fsesl IMAGE_NAME=bbb-fsesl-akka BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" - make image DIR=$(BUILD_DIR_BASE)/bigbluebutton-web IMAGE_NAME=bbb-web BUILD_ARGS="--build-arg COMMON_VERSION=0.0.1-SNAPSHOT" - make image DIR=$(BUILD_DIR_BASE)/bigbluebutton-html5 IMAGE_NAME=bbb-html5 - make image DIR=$(BUILD_DIR_BASE)/labs/bbb-webrtc-sfu IMAGE_NAME=bbb-webrtc-sfu - make image DIR=$(BUILD_DIR_BASE)/bbb-webhooks IMAGE_NAME=bbb-webhooks - make image DIR=$(BUILD_DIR_BASE)/labs/docker/kurento IMAGE_NAME=bbb-kurento - make image DIR=$(BUILD_DIR_BASE)/labs/docker/freeswitch IMAGE_NAME=bbb-freeswitch - make image DIR=$(BUILD_DIR_BASE)/labs/docker/nginx IMAGE_NAME=bbb-nginx - make image DIR=$(BUILD_DIR_BASE)/labs/docker/coturn IMAGE_NAME=bbb-coturn - make image DIR=$(BUILD_DIR_BASE)/bbb-lti IMAGE_NAME=bbb-lti diff --git a/labs/docker/README.md b/labs/docker/README.md deleted file mode 100644 index 654d2201a6..0000000000 --- a/labs/docker/README.md +++ /dev/null @@ -1,274 +0,0 @@ -IMPORTANT: this is a work in progress! - -# Purpose - -The purpose of this repo is to get BigBlueButton working in a multi-container Docker configuration over a single port, then to deploy and scale it using Kubernetes - -# Launching BBB via Docker - -## Prerequisites - -#### Ensure you have the latest version of Docker-CE by following the install steps - -Ubuntu: https://docs.docker.com/install/linux/docker-ce/ubuntu/ - -Fedora: https://docs.docker.com/install/linux/docker-ce/fedora/ - -#### Make sure to also do the post install steps - -https://docs.docker.com/install/linux/linux-postinstall/ - -#### Install docker-compose - -Ubuntu: -``` -sudo apt-get install docker-compose -``` - -Fedora: -``` -sudo dnf install docker-compose -``` - -## Build all docker images - -#### Build all docker images with one command -``` -cd labs/docker/ -make release -``` - -#### Verify that you have all the necessary images -``` -docker images -``` - -You should see: -* sbt -* bbb-common-message -* bbb-common-web -* bbb-fsesl-client -* bbb-apps-akka -* bbb-fsesl-akka -* bbb-web -* bbb-html5 -* bbb-webrtc-sfu -* bbb-webhooks -* bbb-kurento -* bbb-freeswitch -* bbb-nginx -* bbb-coturn -* bbb-lti - - -In the event that any of the above images are missing, you'll need to build them individually - -## Build images individually - -sbt is needed to build the Scala components -``` -cd labs/docker/sbt/ -docker build -t 'sbt:0.13.8' . -``` - -Build libraries -``` -cd bbb-common-message/ -docker build -t 'bbb-common-message' --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . - -cd bbb-common-web/ -docker build -t 'bbb-common-web' --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . - -cd bbb-fsesl-client/ -docker build -t 'bbb-fsesl-client' --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . -``` - -Build akka components -``` -cd akka-bbb-apps/ -docker build -t bbb-apps-akka --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . - -# Not needed since we're setting up HTML5 only -cd akka-bbb-transcode/ -docker build -t bbb-transcode --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . - -cd akka-bbb-fsesl/ -docker build -t bbb-fsesl-akka --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . -``` - -Build bbb-web -``` -cd bigbluebutton-web/ -docker build -t bbb-web --build-arg COMMON_VERSION=0.0.1-SNAPSHOT . -``` - -Build bbb-html5 -``` -cd bigbluebutton-html5/ -docker build -t bbb-html5 . -``` - -Build bbb-webrtc-sfu -``` -cd labs/bbb-webrtc-sfu/ -docker build -t bbb-webrtc-sfu . -``` - -Build bbb-webhooks -``` -cd bbb-webhooks/ -docker build -t bbb-webhooks . -``` - -Build Kurento Media Server -``` -cd labs/docker/kurento/ -docker build -t bbb-kurento . -``` - -Build FreeSWITCH -``` -cd labs/docker/freeswitch/ -docker build -t bbb-freeswitch . -``` - -Build nginx -``` -cd labs/docker/nginx/ -docker build -t bbb-nginx . -``` - -Build coturn -``` -cd labs/docker/coturn -docker build -t bbb-coturn . -``` - -(Optional) Build bbb-lti -``` -cd bbb-lti/ -docker build -t bbb-lti . -``` - -## Setup - -#### Export your configuration as environment variables -NOTE: replace the example SERVER_DOMAIN's value with your own FQDN -``` -export SERVER_DOMAIN=docker.bigbluebutton.org -export EXTERNAL_IP=$(dig +short $SERVER_DOMAIN | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' | head -n 1) -export SHARED_SECRET=`openssl rand -hex 16` -export COTURN_REST_SECRET=`openssl rand -hex 16` -export SECRET_KEY_BASE=`openssl rand -hex 64` -export SCREENSHARE_EXTENSION_KEY=akgoaoikmbmhcopjgakkcepdgdgkjfbc -export SCREENSHARE_EXTENSION_LINK=https://chrome.google.com/webstore/detail/bigbluebutton-screenshare/akgoaoikmbmhcopjgakkcepdgdgkjfbc -export TAG_PREFIX= -export TAG_SUFFIX= -``` - -#### Create a volume for the SSL certs -``` -docker volume create docker_ssl-conf -``` - -#### Generate SSL certs -``` -docker run --rm -p 80:80 -v docker_ssl-conf:/etc/letsencrypt -it certbot/certbot certonly --non-interactive --register-unsafely-without-email --agree-tos --expand --domain $SERVER_DOMAIN --standalone - -# certificate path: docker_ssl-conf/live/$SERVER_DOMAIN/fullchain.pem -# key path: docker_ssl-conf/live/$SERVER_DOMAIN/privkey.pem -``` -NOTE: If running on AWS, you won't be able to use the default Public DNS for your SERVER_DOMAIN as Let's Encrypt doesn't allow generating SSL certs from any *.amazonaws.com domain. Alternatively, you can create a PTR record that goes from a non-AWS FQDN to the AWS FQDN. - -#### Create a volume for the static files (optional) -``` -docker volume create docker_static -cd bigbluebutton-config/web/ -docker run -d --rm --name nginx -v docker_static:/var/www/bigbluebutton-default nginx tail -f /dev/null -docker cp . nginx:/var/www/bigbluebutton-default -docker exec -it nginx chown -R www-data:www-data /var/www/bigbluebutton-default -docker stop nginx -``` - -#### Ensure the following ports are open -* TCP/UDP 3478 -* TCP 80 -* TCP 443 - -## Run - -#### Launch everything with docker compose -``` -cd labs/docker/ -docker-compose up -``` - -#### Access your server via greenlight and create meetings - -https:///b - -#### To shut down and exit gracefully -``` -CTRL+C -``` - - -# Setting up a Kubernetes Cluster - -## Prerequisites - -#### Install kubeadm, kubelet, and kubectl - -https://kubernetes.io/docs/setup/independent/install-kubeadm/ - -#### Disable swap by commenting out the "swap" line in /etc/fstab, then do a reboot -``` -sudo vi /etc/fstab -sudo systemctl reboot -``` - -#### Verify swap is disabled -``` -sudo free -h -``` - -#### Install Minikube - -https://kubernetes.io/docs/tasks/tools/install-minikube/ - -#### Install VirtualBox Manager - -Ubuntu: -``` -sudo apt-get install virtualbox -``` - -Fedora: -``` -sudo dnf install virtualbox -``` - -## Setup - -#### The following kernel modules are required to avoid preflight errors and warnings during cluster setup -* ip_vs -* ip_vs_rr -* ip_vs_wrr -* ip_vs_sh - -#### Check if kernel modules are already loaded -``` -lsmod | grep ip_vs -``` - -#### Add the kernel modules (if not already loaded) -``` -sudo modprobe ip_vs -sudo modprobe ip_vs_rr -sudo modprobe ip_vs_wrr -sudo modprobe ip_vs_sh -``` - -#### Create a single master cluster with kubeadm - -https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/ diff --git a/labs/docker/coturn/Dockerfile b/labs/docker/coturn/Dockerfile deleted file mode 100644 index aa4912ae02..0000000000 --- a/labs/docker/coturn/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y coturn wget - -ENV DOCKERIZE_VERSION v0.6.1 -RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz - -COPY ./turnserver.conf.tmpl /etc/turnserver.conf.tmpl - -CMD [ "dockerize", \ - "-template", "/etc/turnserver.conf.tmpl:/etc/turnserver.conf", \ - "turnserver", "--syslog" ] diff --git a/labs/docker/coturn/turnserver.conf.tmpl b/labs/docker/coturn/turnserver.conf.tmpl deleted file mode 100644 index c9810fb822..0000000000 --- a/labs/docker/coturn/turnserver.conf.tmpl +++ /dev/null @@ -1,14 +0,0 @@ -listening-port={{ .Env.PORT }} -min-port=49152 -max-port=65535 -fingerprint -lt-cred-mech -realm={{ .Env.SERVER_DOMAIN }} -external-ip={{ .Env.EXTERNAL_IP }} - -{{ if isTrue .Env.ENABLE_REST_API }} -use-auth-secret -static-auth-secret={{ .Env.SECRET }} -{{ else }} -user={{ .Env.LT_USER }}:{{ .Env.LT_SECRET }} -{{ end }} diff --git a/labs/docker/docker-compose.yml b/labs/docker/docker-compose.yml deleted file mode 100644 index 8ee7fb82da..0000000000 --- a/labs/docker/docker-compose.yml +++ /dev/null @@ -1,183 +0,0 @@ -version: '2' - -services: - mongo: - image: mongo:3.4 - restart: unless-stopped - - redis: - image: redis - restart: unless-stopped - - bbb-html5: - image: ${TAG_PREFIX}bbb-html5${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - mongo - - redis - environment: - MONGO_URL: mongodb://mongo/bbbhtml5 - METEOR_SETTINGS_MODIFIER: ".public.kurento.wsUrl = \"wss://${SERVER_DOMAIN}/bbb-webrtc-sfu\" | .public.kurento.enableVideo = true | .public.kurento.enableScreensharing = true | .public.kurento.chromeDefaultExtensionKey = \"${SCREENSHARE_EXTENSION_KEY}\" | .public.kurento.chromeDefaultExtensionLink = \"${SCREENSHARE_EXTENSION_LINK}\" | .public.kurento.enableVideoStats = true | .public.kurento.enableListenOnly = true" - REDIS_HOST: redis - ROOT_URL: http://127.0.0.1/html5client - labels: - - "traefik.backend=bbb-html5" - - "traefik.frontend.rule=PathPrefix: /html5client,/_timesync" - - bbb-webhooks: - image: ${TAG_PREFIX}bbb-webhooks${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - redis - environment: - REDIS_HOST: redis - SHARED_SECRET: ${SHARED_SECRET} - BEARER_AUTH: 1 - SERVER_DOMAIN: ${SERVER_DOMAIN} - labels: - - "traefik.backend=bbb-webhooks" - - "traefik.frontend.rule=PathPrefix: /bigbluebutton/api/hooks" - - bbb-freeswitch: - image: ${TAG_PREFIX}bbb-freeswitch${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - coturn - volumes: - - media-audio:/var/freeswitch/meetings - - bbb-webrtc-sfu: - image: ${TAG_PREFIX}bbb-webrtc-sfu${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - redis - - kurento - - bbb-freeswitch - environment: - KURENTO_NAME: kurento - KURENTO_URL: ws://kurento:8888/kurento - REDIS_HOST: redis - FREESWITCH_IP: bbb-freeswitch - LOG_LEVEL: debug - labels: - - "traefik.backend=bbb-webrtc-sfu" - - "traefik.frontend.rule=PathPrefix: /bbb-webrtc-sfu" - - coturn: - image: ${TAG_PREFIX}bbb-coturn${TAG_SUFFIX} - restart: unless-stopped - environment: - TURN_DOMAIN: ${SERVER_DOMAIN} - SECRET: ${COTURN_REST_SECRET} - EXTERNAL_IP: ${EXTERNAL_IP} - ENABLE_REST_API: 1 - PORT: 3478 - ports: - - 3478:3478/udp - - 3478:3478/tcp - - kurento: - image: ${TAG_PREFIX}bbb-kurento${TAG_SUFFIX} - restart: unless-stopped - volumes: - - media-video:/var/kurento/recordings - - media-screenshare:/var/kurento/screenshare - environment: - STUN_IP: ${EXTERNAL_IP} - STUN_PORT: 3478 - - bbb-apps-akka: - image: ${TAG_PREFIX}bbb-apps-akka${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - redis - environment: - JAVA_OPTS: -Dredis.host=redis - - bbb-fsesl-akka: - image: ${TAG_PREFIX}bbb-fsesl-akka${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - bbb-freeswitch - - redis - command: ["wait-for-it.sh", "bbb-freeswitch:8021", "--timeout=60", "--strict", "--", "/usr/share/bbb-fsesl-akka/bin/bbb-fsesl-akka"] - environment: - JAVA_OPTS: -Dredis.host=redis -Dfreeswitch.esl.host=bbb-freeswitch - - bbb-web: - image: ${TAG_PREFIX}bbb-web${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - redis - volumes: - - bigbluebutton:/var/bigbluebutton - environment: - SERVER_DOMAIN: ${SERVER_DOMAIN} - SHARED_SECRET: ${SHARED_SECRET} - TURN_DOMAIN: ${SERVER_DOMAIN} - TURN_SECRET: ${COTURN_REST_SECRET} - labels: - - "traefik.backend=bbb-web" - - "traefik.frontend.rule=PathPrefix: /bigbluebutton" - - bbb-greenlight: - image: bigbluebutton/greenlight:v2 - restart: unless-stopped - volumes: - - greenlight_db:/usr/src/app/db/production - - greenlight_logs:/usr/src/app/log - environment: - BIGBLUEBUTTON_ENDPOINT: https://${SERVER_DOMAIN}/bigbluebutton/ - BIGBLUEBUTTON_SECRET: ${SHARED_SECRET} - SECRET_KEY_BASE: ${SECRET_KEY_BASE} - ALLOW_GREENLIGHT_ACCOUNTS: "true" - labels: - - "traefik.backend=bbb-greenlight" - - "traefik.frontend.rule=PathPrefix: /b" - - # when we're able to setup traefik properly for wss, nginx is no longer needed - nginx: - image: ${TAG_PREFIX}bbb-nginx${TAG_SUFFIX} - restart: unless-stopped - depends_on: - - bbb-freeswitch - environment: - SERVER_DOMAIN: ${SERVER_DOMAIN} - labels: - - "traefik.backend=bbb-freeswitch" - - "traefik.frontend.rule=PathPrefix: /ws" - - traefik: - image: traefik - restart: unless-stopped - ports: - - 80:80 - - 8080:8080 - - 443:443 - command: traefik - - --docker - - --logLevel=INFO - - --acme - - --acme.httpchallenge - - --acme.httpchallenge.entrypoint=http - - --acme.acmelogging - - --acme.storage=/etc/traefik/acme/acme.json - - --acme.email=felipe@mconf.com - - --acme.entrypoint=https - - --acme.domains=${SERVER_DOMAIN} - - --defaultentrypoints=http,https - - --entryPoints='Name:http Address::80 Redirect.EntryPoint:https' - - --entryPoints='Name:https Address::443 TLS' - volumes: - - traefik-acme:/etc/traefik/acme/ - - /var/run/docker.sock:/var/run/docker.sock - -volumes: - traefik-acme: - static: - bigbluebutton: - media-audio: - media-video: - media-screenshare: - greenlight_db: - greenlight_logs: diff --git a/labs/docker/freeswitch/Dockerfile b/labs/docker/freeswitch/Dockerfile deleted file mode 100644 index 86865a8fb8..0000000000 --- a/labs/docker/freeswitch/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM ubuntu:16.04 - -ENV DEBIAN_FRONTEND noninteractive - -RUN apt-get update \ - && apt-get -y install wget libedit-dev xmlstarlet - -RUN echo "deb http://ubuntu.bigbluebutton.org/xenial-200-dev bigbluebutton-xenial main " | tee /etc/apt/sources.list.d/bigbluebutton.list \ - && wget http://ubuntu.bigbluebutton.org/repo/bigbluebutton.asc -O- | apt-key add - \ - && apt-get update \ - && apt-get -y install bbb-freeswitch-core \ - && find /opt/freeswitch/conf/sip_profiles/ -name "*ipv6*" -prune -exec rm -rf "{}" \; - -EXPOSE 7443 - -COPY docker-entrypoint.sh /usr/local/bin/ -COPY event_socket_conf.xml /opt/freeswitch/conf/autoload_configs/event_socket.conf.xml - -RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64 \ - && chmod +x /usr/local/bin/dumb-init - -ENTRYPOINT ["/usr/local/bin/dumb-init", "--"] - -CMD [ "docker-entrypoint.sh" ] diff --git a/labs/docker/freeswitch/docker-entrypoint.sh b/labs/docker/freeswitch/docker-entrypoint.sh deleted file mode 100755 index 90e82ba379..0000000000 --- a/labs/docker/freeswitch/docker-entrypoint.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -xe - -IP=$(hostname -I | cut -d' ' -f1) - -xmlstarlet edit --inplace --update '//X-PRE-PROCESS[@cmd="set" and starts-with(@data, "external_rtp_ip=")]/@data' --value "stun:coturn" /opt/freeswitch/conf/vars.xml -xmlstarlet edit --inplace --update '//X-PRE-PROCESS[@cmd="set" and starts-with(@data, "external_sip_ip=")]/@data' --value "stun:coturn" /opt/freeswitch/conf/vars.xml -xmlstarlet edit --inplace --update '//X-PRE-PROCESS[@cmd="set" and starts-with(@data, "local_ip_v4=")]/@data' --value "${IP}" /opt/freeswitch/conf/vars.xml -# add wss-binding element -xmlstarlet edit --inplace --subnode '//settings' --type elem --name 'newsubnode' --value '' /opt/freeswitch/conf/sip_profiles/external.xml -xmlstarlet edit --inplace --insert '//newsubnode' --type attr --name 'name' --value 'wss-binding' /opt/freeswitch/conf/sip_profiles/external.xml -xmlstarlet edit --inplace --insert '//newsubnode' --type attr --name 'value' --value ':7443' /opt/freeswitch/conf/sip_profiles/external.xml -xmlstarlet edit --inplace --rename '//newsubnode' --value 'param' /opt/freeswitch/conf/sip_profiles/external.xml - -/opt/freeswitch/bin/freeswitch diff --git a/labs/docker/freeswitch/event_socket_conf.xml b/labs/docker/freeswitch/event_socket_conf.xml deleted file mode 100644 index c10b16fb1b..0000000000 --- a/labs/docker/freeswitch/event_socket_conf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/labs/docker/k8s/bbb-apps-akka.yaml b/labs/docker/k8s/bbb-apps-akka.yaml deleted file mode 100644 index d21e1d44ab..0000000000 --- a/labs/docker/k8s/bbb-apps-akka.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-apps-akka - version: latest - name: bbb-apps-akka - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-apps-akka - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-apps-akka - version: latest - name: bbb-apps-akka - spec: - containers: - - env: - - name: JAVA_OPTS - value: -Dredis.host=redis - image: fcecagno/bigbluebutton:bbb-apps-akka - imagePullPolicy: Always - name: bbb-apps-akka - ports: - - containerPort: 8080 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule diff --git a/labs/docker/k8s/bbb-coturn.yaml b/labs/docker/k8s/bbb-coturn.yaml deleted file mode 100644 index f68eb0cca3..0000000000 --- a/labs/docker/k8s/bbb-coturn.yaml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-coturn - version: latest - name: bbb-coturn - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-coturn - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-coturn - version: latest - name: bbb-coturn - spec: - containers: - - env: - - name: PORT - value: "3478" - - name: SERVER_DOMAIN - value: bigbluebutton.rocket.chat - - name: SECRET - value: "54321" - - name: EXTERNAL_IP - value: "35.185.19.180" - - name: ENABLE_REST_API - value: "1" - image: fcecagno/bigbluebutton:bbb-coturn - imagePullPolicy: Always - name: bbb-coturn - ports: - - containerPort: 3478 - protocol: TCP - - containerPort: 3478 - protocol: UDP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-coturn - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 3478 - port: 3478 - selector: - app: bbb-coturn diff --git a/labs/docker/k8s/bbb-freeswitch-nginx.yaml b/labs/docker/k8s/bbb-freeswitch-nginx.yaml deleted file mode 100644 index d550783745..0000000000 --- a/labs/docker/k8s/bbb-freeswitch-nginx.yaml +++ /dev/null @@ -1,79 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-freeswitch-nginx - version: latest - name: bbb-freeswitch-nginx - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-freeswitch-nginx - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-freeswitch-nginx - version: latest - name: bbb-freeswitch-nginx - spec: - containers: - - env: - - name: SERVER_DOMAIN - value: bigbluebutton.rocket.chat - image: fcecagno/bigbluebutton:bbb-nginx - imagePullPolicy: Always - name: bbb-freeswitch-nginx - ports: - - containerPort: 80 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-freeswitch-nginx - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 80 - port: 80 - selector: - app: bbb-freeswitch-nginx - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: bbb-freeswitch-nginx - namespace: bigbluebutton - annotations: - kubernetes.io/ingress.class: "traefik" -spec: - rules: - - host: bigbluebutton.rocket.chat - http: - paths: - - path: /ws - backend: - serviceName: bbb-freeswitch-nginx - servicePort: 80 diff --git a/labs/docker/k8s/bbb-freeswitch.yaml b/labs/docker/k8s/bbb-freeswitch.yaml deleted file mode 100644 index 90fe646d55..0000000000 --- a/labs/docker/k8s/bbb-freeswitch.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-freeswitch - version: latest - name: bbb-freeswitch - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-freeswitch - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-freeswitch - version: latest - name: bbb-freeswitch - spec: - containers: - - image: fcecagno/bigbluebutton:bbb-freeswitch - imagePullPolicy: Always - name: bbb-freeswitch - ports: - - containerPort: 7443 - protocol: TCP - - containerPort: 8021 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-freeswitch - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 7443 - port: 7443 - - name: freeswitch-8021 - targetPort: 8021 - port: 8021 - selector: - app: bbb-freeswitch diff --git a/labs/docker/k8s/bbb-fsesl-akka.yaml b/labs/docker/k8s/bbb-fsesl-akka.yaml deleted file mode 100644 index b37ba7d94f..0000000000 --- a/labs/docker/k8s/bbb-fsesl-akka.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-fsesl-akka - version: latest - name: bbb-fsesl-akka - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-fsesl-akka - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-fsesl-akka - version: latest - name: bbb-fsesl-akka - spec: - containers: - - env: - - name: JAVA_OPTS - value: -Dredis.host=redis -Dfreeswitch.esl.host=bbb-freeswitch - image: fcecagno/bigbluebutton:bbb-fsesl-akka - imagePullPolicy: Always - name: bbb-fsesl-akka - command: ["wait-for-it.sh", "bbb-freeswitch:8021", "--timeout=60", "--strict", "--", "/usr/share/bbb-fsesl-akka/bin/bbb-fsesl-akka"] - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule diff --git a/labs/docker/k8s/bbb-html5.yaml b/labs/docker/k8s/bbb-html5.yaml deleted file mode 100644 index cf8fdafcf3..0000000000 --- a/labs/docker/k8s/bbb-html5.yaml +++ /dev/null @@ -1,91 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-html5 - version: latest - name: bbb-html5 - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-html5 - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-html5 - version: latest - name: bbb-html5 - spec: - containers: - - env: - - name: MONGO_URL - value: mongodb://mongo:27017/ - - name: MONGO_DB - value: bbbhtml5 - - name: METEOR_SETTINGS_MODIFIER - value: ".public.kurento.wsUrl = \"wss://bigbluebutton.rocket.chat/bbb-webrtc-sfu\" | .public.kurento.enableVideo = true | .public.kurento.enableScreensharing = true | .public.kurento.enableVideoStats = true | .public.kurento.enableListenOnly = true" - - name: REDIS_HOST - value: redis - - name: ROOT_URL - value: http://127.0.0.1/html5client - image: fcecagno/bigbluebutton:bbb-html5 - imagePullPolicy: Always - name: bbb-html5 - ports: - - containerPort: 3000 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-html5 - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 3000 - port: 3000 - selector: - app: bbb-html5 - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: bbb-html5 - namespace: bigbluebutton - annotations: - kubernetes.io/ingress.class: "traefik" -spec: - rules: - - host: bigbluebutton.rocket.chat - http: - paths: - - path: /html5client - backend: - serviceName: bbb-html5 - servicePort: 3000 - - path: /_timesync - backend: - serviceName: bbb-html5 - servicePort: 3000 diff --git a/labs/docker/k8s/bbb-kurento.yaml b/labs/docker/k8s/bbb-kurento.yaml deleted file mode 100644 index 7c3d6c8f60..0000000000 --- a/labs/docker/k8s/bbb-kurento.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-kurento - version: latest - name: bbb-kurento - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-kurento - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-kurento - version: latest - name: bbb-kurento - spec: - containers: - - env: - - name: STUN_IP - # TODO: how to get this IP? - value: "35.185.19.180" - - name: STUN_PORT - value: "3478" - image: fcecagno/bigbluebutton:bbb-kurento - imagePullPolicy: Always - name: bbb-kurento - ports: - - containerPort: 8888 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-kurento - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 8888 - port: 8888 - selector: - app: bbb-kurento - - - # volumes: - # - media-video:/var/kurento/recordings - # - media-screenshare:/var/kurento/screenshare diff --git a/labs/docker/k8s/bbb-web.yaml b/labs/docker/k8s/bbb-web.yaml deleted file mode 100644 index 24d6588fc3..0000000000 --- a/labs/docker/k8s/bbb-web.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-web - version: latest - name: bbb-web - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-web - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-web - version: latest - name: bbb-web - spec: - containers: - - env: - - name: SERVER_DOMAIN - value: bigbluebutton.rocket.chat - - name: SHARED_SECRET - value: "12345" - - name: TURN_SECRET - value: "54321" - - name: TURN_DOMAIN - value: bigbluebutton.rocket.chat - image: fcecagno/bigbluebutton:bbb-web - imagePullPolicy: Always - name: bbb-web - ports: - - containerPort: 8080 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-web - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 8080 - port: 8080 - selector: - app: bbb-web - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: bbb-web - namespace: bigbluebutton - annotations: - kubernetes.io/ingress.class: "traefik" -spec: - rules: - - host: bigbluebutton.rocket.chat - http: - paths: - - path: /bigbluebutton - backend: - serviceName: bbb-web - servicePort: 8080 diff --git a/labs/docker/k8s/bbb-webhooks.yaml b/labs/docker/k8s/bbb-webhooks.yaml deleted file mode 100644 index b1aff374d2..0000000000 --- a/labs/docker/k8s/bbb-webhooks.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-webhooks - version: latest - name: bbb-webhooks - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-webhooks - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-webhooks - version: latest - name: bbb-webhooks - spec: - containers: - - env: - - name: REDIS_HOST - value: redis - - name: SHARED_SECRET - value: "12345" - - name: SERVER_DOMAIN - value: bigbluebutton.rocket.chat - - name: BEARER_AUTH - value: "1" - image: fcecagno/bigbluebutton:bbb-webhooks - imagePullPolicy: Always - name: bbb-webhooks - ports: - - containerPort: 3005 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-webhooks - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 3005 - port: 3005 - selector: - app: bbb-webhooks - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: bbb-webhooks - namespace: bigbluebutton - annotations: - kubernetes.io/ingress.class: "traefik" -spec: - rules: - - host: bigbluebutton.rocket.chat - http: - paths: - - path: /bigbluebutton/api/hooks - backend: - serviceName: bbb-webhooks - servicePort: 3005 diff --git a/labs/docker/k8s/bbb-webrtc-sfu.yaml b/labs/docker/k8s/bbb-webrtc-sfu.yaml deleted file mode 100644 index d6cee0ec51..0000000000 --- a/labs/docker/k8s/bbb-webrtc-sfu.yaml +++ /dev/null @@ -1,87 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: bbb-webrtc-sfu - version: latest - name: bbb-webrtc-sfu - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: bbb-webrtc-sfu - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: bbb-webrtc-sfu - version: latest - name: bbb-webrtc-sfu - spec: - containers: - - env: - - name: KURENTO_NAME - value: kurento - - name: KURENTO_URL - value: ws://bbb-kurento:8888/kurento - - name: REDIS_HOST - value: redis - - name: FREESWITCH_IP - value: bbb-freeswitch - - name: LOG_LEVEL - value: debug - image: fcecagno/bigbluebutton:bbb-webrtc-sfu - imagePullPolicy: Always - name: bbb-webrtc-sfu - ports: - - containerPort: 3008 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: bbb-webrtc-sfu - namespace: bigbluebutton - annotations: - traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" -spec: - ports: - - name: http - targetPort: 3008 - port: 3008 - selector: - app: bbb-webrtc-sfu - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: bbb-webrtc-sfu - namespace: bigbluebutton - annotations: - kubernetes.io/ingress.class: "traefik" -spec: - rules: - - host: bigbluebutton.rocket.chat - http: - paths: - - path: /bbb-webrtc-sfu - backend: - serviceName: bbb-webrtc-sfu - servicePort: 3008 diff --git a/labs/docker/k8s/bigbluebutton-ns.yaml b/labs/docker/k8s/bigbluebutton-ns.yaml deleted file mode 100644 index d66b7579ed..0000000000 --- a/labs/docker/k8s/bigbluebutton-ns.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: bigbluebutton diff --git a/labs/docker/k8s/mongo.yaml b/labs/docker/k8s/mongo.yaml deleted file mode 100644 index 5a09cdd532..0000000000 --- a/labs/docker/k8s/mongo.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: mongo - version: latest - name: mongo - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: mongo - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: mongo - version: latest - name: mongo - spec: - containers: - - image: mongo:3.6 - imagePullPolicy: Always - name: mongo - ports: - - containerPort: 27017 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: mongo - namespace: bigbluebutton -spec: - ports: - - targetPort: 27017 - port: 27017 - selector: - app: mongo diff --git a/labs/docker/k8s/redis.yaml b/labs/docker/k8s/redis.yaml deleted file mode 100644 index fe12f4eb19..0000000000 --- a/labs/docker/k8s/redis.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - labels: - app: redis - version: latest - name: redis - namespace: bigbluebutton -spec: - replicas: 1 - selector: - matchLabels: - app: redis - version: latest - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - app: redis - version: latest - name: redis - spec: - containers: - - image: redis:latest - imagePullPolicy: Always - name: redis - ports: - - containerPort: 6379 - protocol: TCP - restartPolicy: Always - terminationGracePeriodSeconds: 30 - nodeSelector: - role: 'bigbluebutton' - tolerations: - - key: role - operator: Equal - value: 'bigbluebutton' - effect: NoSchedule - ---- -apiVersion: v1 -kind: Service -metadata: - name: redis - namespace: bigbluebutton -spec: - ports: - - targetPort: 6379 - port: 6379 - selector: - app: redis diff --git a/labs/docker/kurento/Dockerfile b/labs/docker/kurento/Dockerfile deleted file mode 100644 index f6619abf74..0000000000 --- a/labs/docker/kurento/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:16.04 - -# In order to build kurento dev, use: -# docker build --build-arg APT_KEY="http://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&search=0xFC8A16625AFA7A83" --build-arg APT_REPO="deb [arch=amd64] http://ubuntu.openvidu.io/dev xenial kms6" --build-arg CACHE_BUST="$(date +%s)" -t mconf/kurento:upstream-dev . - -ARG APT_KEY="https://ubuntu.bigbluebutton.org/repo/bigbluebutton.asc" -ARG APT_REPO="deb https://ubuntu.bigbluebutton.org/xenial-220-dev bigbluebutton-xenial main" -ARG CACHE_BUST=1 - -ENV DEBIAN_FRONTEND noninteractive - -RUN apt-get update \ - && apt-get -y dist-upgrade \ - && apt-get install -y software-properties-common curl wget apt-transport-https - -RUN wget "$APT_KEY" -O- | apt-key add - \ - && add-apt-repository "$APT_REPO" \ - && apt-get update \ - && apt-get -y install kurento-media-server bzip2 jq \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -RUN apt-get update \ - && apt-get install -y --download-only openh264-gst-plugins-bad-1.5 - -COPY ./docker-entrypoint.sh /usr/local/bin/ -COPY ./healthchecker.sh /healthchecker.sh - -ENV GST_DEBUG=Kurento*:5 -ENV PORT=8888 -# stun.l.google.com -ENV STUN_IP=64.233.186.127 -ENV STUN_PORT=19302 -ENV TURN_URL="" -ENV RTP_MIN_PORT=24577 -ENV RTP_MAX_PORT=32768 - -HEALTHCHECK --start-period=15s --interval=30s --timeout=3s --retries=1 CMD /healthchecker.sh - -ENTRYPOINT ["docker-entrypoint.sh"] -CMD ["/usr/bin/kurento-media-server"] diff --git a/labs/docker/kurento/docker-entrypoint.sh b/labs/docker/kurento/docker-entrypoint.sh deleted file mode 100755 index 82d3429101..0000000000 --- a/labs/docker/kurento/docker-entrypoint.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -e - -apt-get install -y openh264-gst-plugins-bad-1.5 - -rm -f /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini -# Generate WebRtcEndpoint configuration -echo "stunServerAddress=$STUN_IP" >> /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini -echo "stunServerPort=$STUN_PORT" >> /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini - -if [ "$TURN_URL" != "" ]; then - echo "turnURL=$TURN_URL" >> /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini -fi - -rm -f /etc/kurento/modules/kurento/BaseRtpEndpoint.conf.ini -# Generate BaseRtpEndpoint configuration -echo "minPort=$RTP_MIN_PORT" >> /etc/kurento/modules/kurento/BaseRtpEndpoint.conf.ini -echo "maxPort=$RTP_MAX_PORT" >> /etc/kurento/modules/kurento/BaseRtpEndpoint.conf.ini - -CONFIG=$(cat /etc/kurento/kurento.conf.json | sed '/^[ ]*\/\//d' | jq ".mediaServer.net.websocket.port = $PORT") -echo $CONFIG > /etc/kurento/kurento.conf.json - -# Remove ipv6 local loop until ipv6 is supported -cat /etc/hosts | sed '/::1/d' | tee /etc/hosts > /dev/null - -exec "$@" diff --git a/labs/docker/kurento/healthchecker.sh b/labs/docker/kurento/healthchecker.sh deleted file mode 100755 index f127ae41c1..0000000000 --- a/labs/docker/kurento/healthchecker.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -[[ "$(curl -w '%{http_code}' -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: 127.0.0.1:$PORT" -H "Origin: 127.0.0.1" http://127.0.0.1:$PORT/kurento)" == 500 ]] && exit 0 || exit 1 diff --git a/labs/docker/nginx/Dockerfile b/labs/docker/nginx/Dockerfile deleted file mode 100644 index 56fc11c419..0000000000 --- a/labs/docker/nginx/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM nginx - -RUN apt-get update && apt-get install -y wget - -ENV DOCKERIZE_VERSION v0.6.1 -RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ - && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz - -COPY ./nginx.conf.tmpl /etc/nginx/nginx.conf.tmpl - -CMD [ "dockerize", \ - "-template", "/etc/nginx/nginx.conf.tmpl:/etc/nginx/nginx.conf", \ - "nginx", "-g", "daemon off;" ] diff --git a/labs/docker/nginx/nginx.conf.tmpl b/labs/docker/nginx/nginx.conf.tmpl deleted file mode 100644 index 0210fc399b..0000000000 --- a/labs/docker/nginx/nginx.conf.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -user www-data; -worker_processes auto; -pid /run/nginx.pid; - -events { - worker_connections 768; -} - -http { - ## - # Basic Settings - ## - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - ## - # SSL Settings - ## - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE - ssl_prefer_server_ciphers on; - - ## - # Logging Settings - ## - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - ## - # Gzip Settings - ## - - gzip on; - gzip_disable "msie6"; - - ## - # Virtual Host Configs - ## - - server { - listen 80; - listen [::]:80; - server_name {{ .Env.SERVER_DOMAIN }}; - - access_log /var/log/nginx/bigbluebutton.access.log; - - location /ws { - proxy_pass https://bbb-freeswitch:7443; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_read_timeout 6h; - proxy_send_timeout 6h; - client_body_timeout 6h; - send_timeout 6h; - } - } -} diff --git a/labs/docker/sbt/Dockerfile b/labs/docker/sbt/Dockerfile deleted file mode 100644 index 99e285c61d..0000000000 --- a/labs/docker/sbt/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM openjdk:8 - -ARG SBT_VERSION=0.13.8 - -RUN curl -L -o sbt-$SBT_VERSION.deb https://dl.bintray.com/sbt/debian/sbt-$SBT_VERSION.deb \ - && dpkg -i sbt-$SBT_VERSION.deb \ - && rm sbt-$SBT_VERSION.deb \ - && apt-get update \ - && apt-get install sbt \ - && sbt sbtVersion - -RUN echo 'resolvers += "Artima Maven Repository" at "http://repo.artima.com/releases"' | tee -a ~/.sbt/0.13/global.sbt - -WORKDIR /root diff --git a/record-and-playback/core/Gemfile b/record-and-playback/core/Gemfile index 9e638aacdb..9b6b5a3c1b 100644 --- a/record-and-playback/core/Gemfile +++ b/record-and-playback/core/Gemfile @@ -26,7 +26,7 @@ gem 'journald-logger', '~> 3.0' gem 'jwt', '~> 2.2' gem 'locale', '~> 2.1' gem 'loofah', '~> 2.3' -gem 'nokogiri' +gem 'nokogiri', '~> 1.13', '>= 1.13.4' gem 'open4', '~> 1.3' gem 'rb-inotify', '~> 0.10' gem 'redis', '~> 4.1' diff --git a/record-and-playback/core/Gemfile.lock b/record-and-playback/core/Gemfile.lock index a869596fb0..8b62e5f3a3 100644 --- a/record-and-playback/core/Gemfile.lock +++ b/record-and-playback/core/Gemfile.lock @@ -2,55 +2,55 @@ GEM remote: https://rubygems.org/ specs: absolute_time (1.0.0) - activesupport (5.2.4.3) + activesupport (5.2.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - ast (2.4.0) + ast (2.4.2) bbbevents (1.2.0) activesupport (~> 5.0, >= 5.0.0.1) builder (3.2.4) - concurrent-ruby (1.1.6) + concurrent-ruby (1.1.10) crass (1.0.6) - fastimage (2.1.7) - ffi (1.12.1) - i18n (1.8.3) + fastimage (2.2.6) + ffi (1.15.5) + i18n (1.10.0) concurrent-ruby (~> 1.0) jaro_winkler (1.5.4) java_properties (0.0.4) - journald-logger (3.0.0) + journald-logger (3.1.0) journald-native (~> 1.0) - journald-native (1.0.11) - jwt (2.2.1) - locale (2.1.2) - loofah (2.4.0) + journald-native (1.0.12) + jwt (2.3.0) + locale (2.1.3) + loofah (2.16.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mini_portile2 (2.6.1) - minitest (5.14.1) - mono_logger (1.1.0) - multi_json (1.14.1) + mini_portile2 (2.8.0) + minitest (5.14.4) + mono_logger (1.1.1) + multi_json (1.15.0) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) - nokogiri (1.12.5) - mini_portile2 (~> 2.6.1) + nokogiri (1.13.4) + mini_portile2 (~> 2.8.0) racc (~> 1.4) open4 (1.3.4) optimist (3.0.1) - parallel (1.19.1) - parser (2.7.0.2) - ast (~> 2.4.0) + parallel (1.22.1) + parser (3.1.1.0) + ast (~> 2.4.1) racc (1.6.0) rack (2.2.3) - rack-protection (2.0.8.1) + rack-protection (2.2.0) rack - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) rb-inotify (0.10.1) ffi (~> 1.0) - redis (4.1.3) - redis-namespace (1.7.0) + redis (4.6.0) + redis-namespace (1.8.2) redis (>= 3.0.4) resque (2.0.0) mono_logger (~> 1.0) @@ -65,17 +65,17 @@ GEM rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 1.7) - ruby-progressbar (1.10.1) - ruby2_keywords (0.0.2) - rubyzip (2.0.0) - sinatra (2.0.8.1) + ruby-progressbar (1.11.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + sinatra (2.2.0) mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.8.1) + rack (~> 2.2) + rack-protection (= 2.2.0) tilt (~> 2.0) thread_safe (0.3.6) tilt (2.0.10) - tzinfo (1.2.7) + tzinfo (1.2.9) thread_safe (~> 0.1) unicode-display_width (1.6.1) vegas (0.1.11) @@ -95,7 +95,7 @@ DEPENDENCIES locale (~> 2.1) loofah (~> 2.3) minitest (~> 5.14.1) - nokogiri + nokogiri (~> 1.13, >= 1.13.4) open4 (~> 1.3) optimist rake (>= 12.3, < 14) diff --git a/record-and-playback/core/lib/recordandplayback.rb b/record-and-playback/core/lib/recordandplayback.rb index 8a4526fcb2..04410ee8cd 100644 --- a/record-and-playback/core/lib/recordandplayback.rb +++ b/record-and-playback/core/lib/recordandplayback.rb @@ -240,8 +240,16 @@ module BigBlueButton def self.read_props return @props if @props + filepathRecOverride = "/etc/bigbluebutton/recording/recording.yml" + hasOverride = File.file?(filepathRecOverride) + filepath = File.join(BigBlueButton.rap_scripts_path, 'bigbluebutton.yml') @props = YAML::load(File.open(filepath)) + if (hasOverride) + recOverrideProps = YAML::load(File.open(filepathRecOverride)) + @props = @props.merge(recOverrideProps) + end + @props end def self.create_redis_publisher diff --git a/record-and-playback/core/lib/recordandplayback/edl/video.rb b/record-and-playback/core/lib/recordandplayback/edl/video.rb index a6e6defdbe..fb86068f04 100644 --- a/record-and-playback/core/lib/recordandplayback/edl/video.rb +++ b/record-and-playback/core/lib/recordandplayback/edl/video.rb @@ -486,6 +486,18 @@ module BigBlueButton pad_name = "#{layout_area[:name]}_x#{tile_x}_y#{tile_y}" + tile_x += 1 + if tile_x >= tiles_h + tile_x = 0 + tile_y += 1 + end + + # Only create the video input if the seekpoint is before the end of the file + if seek >= this_videoinfo[:duration] + ffmpeg_filter << "color=c=white:s=#{tile_width}x#{tile_height}:r=#{layout[:framerate]}[#{pad_name}];" + next + end + # Apply the video start time offset to seek to the correct point. # Only actually apply the offset if we're already seeking so we # don't start seeking in a file where we've overridden the seek @@ -518,12 +530,6 @@ module BigBlueButton ffmpeg_filter << "color=c=white:s=#{tile_width}x#{tile_height}:r=#{layout[:framerate]}" ffmpeg_filter << "[#{pad_name}_pad];" ffmpeg_filter << "[#{pad_name}_movie][#{pad_name}_pad]concat=n=2:v=1:a=0[#{pad_name}];" - - tile_x += 1 - if tile_x >= tiles_h - tile_x = 0 - tile_y += 1 - end end # Create the video rows diff --git a/record-and-playback/core/lib/recordandplayback/generators/events.rb b/record-and-playback/core/lib/recordandplayback/generators/events.rb index f25c190e25..97beb67cdf 100755 --- a/record-and-playback/core/lib/recordandplayback/generators/events.rb +++ b/record-and-playback/core/lib/recordandplayback/generators/events.rb @@ -112,8 +112,60 @@ module BigBlueButton start_events end + def self.to_boolean(obj) + return obj.to_s.downcase == "true" + end + + def self.is_user_moderator(user_id, list_user_info) + user_role = list_user_info[user_id] + if !user_role.nil? + if user_role == "MODERATOR" + return true + else + return false + end + end + return false + end + + def self.get_id_from_filename(filename) + return filename.split("/")[-1].split("-")[1] + end + + def self.extract_filename_from_userId(userId, filenames_list) + filename_return = "" + filenames_list.each do |filename| + if !filename.match(userId).nil? + filename_return = filename + end + end + return filename_return + end + + def self.process_webcamsOnlyForModerator(list_user_info, active_videos, inactive_videos, webcamsOnlyForModerator) + + if webcamsOnlyForModerator + list_user_info.each do |user_id, user_role| + # If the user is a viewer: + if !BigBlueButton::Events.is_user_moderator(user_id, list_user_info) + filename = BigBlueButton::Events.extract_filename_from_userId(user_id, active_videos) + if filename != "" + active_videos.delete(filename) + inactive_videos << filename + end + end + end + else + # If the WebcamsOnlyForModerator is false, all previously inactive videos will become active + inactive_videos.each do |filename| + active_videos << filename + end + inactive_videos.clear + end + end + # Build a webcam EDL - def self.create_webcam_edl(events, archive_dir) + def self.create_webcam_edl(events, archive_dir, show_moderator_viewpoint) recording = events.at_xpath('/recording') meeting_id = recording['meeting_id'] event = events.at_xpath('/recording/event[position()=1]') @@ -125,57 +177,203 @@ module BigBlueButton videos = {} active_videos = [] + inactive_videos = [] video_edl = [] video_edl << { :timestamp => 0, :areas => { :webcam => [] } } - - events.xpath('/recording/event[@module="WEBCAM" or (@module="bbb-webrtc-sfu" and (@eventname="StartWebRTCShareEvent" or @eventname="StopWebRTCShareEvent"))]').each do |event| - timestamp = event['timestamp'].to_i - initial_timestamp - # Determine the video filename - case event['eventname'] - when 'StartWebcamShareEvent', 'StopWebcamShareEvent' - stream = event.at_xpath('stream').text - filename = "#{video_dir}/#{stream}.flv" - when 'StartWebRTCShareEvent', 'StopWebRTCShareEvent' - uri = event.at_xpath('filename').text - filename = "#{video_dir}/#{File.basename(uri)}" + list_user_info = {} + webcamsOnlyForModerator = false + if show_moderator_viewpoint + events.xpath('/recording/event[@module="WEBCAM" or (@module="bbb-webrtc-sfu" and (@eventname="StartWebRTCShareEvent" or @eventname="StopWebRTCShareEvent"))]').each do |event| + timestamp = event['timestamp'].to_i - initial_timestamp + # Determine the video filename + case event['eventname'] + when 'StartWebcamShareEvent', 'StopWebcamShareEvent' + stream = event.at_xpath('stream').text + filename = "#{video_dir}/#{stream}.flv" + when 'StartWebRTCShareEvent', 'StopWebRTCShareEvent' + uri = event.at_xpath('filename').text + filename = "#{video_dir}/#{File.basename(uri)}" + end + raise "Couldn't determine webcam filename" if filename.nil? + + # Add the video to the EDL + case event['eventname'] + when 'StartWebcamShareEvent', 'StartWebRTCShareEvent' + videos[filename] = { :timestamp => timestamp } + active_videos << filename + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp] + } + end + video_edl << edl_entry + when 'StopWebcamShareEvent', 'StopWebRTCShareEvent' + active_videos.delete(filename) + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp] + } + end + video_edl << edl_entry + end end - raise "Couldn't determine webcam filename" if filename.nil? + else + events.xpath('/recording/event[@module="WEBCAM" or (@module="bbb-webrtc-sfu" and (@eventname="StartWebRTCShareEvent" or @eventname="StopWebRTCShareEvent")) or (@module="PARTICIPANT" and (@eventname="ParticipantStatusChangeEvent" or @eventname="ParticipantJoinEvent")) or @eventname="WebcamsOnlyForModeratorEvent" or @eventname="MeetingConfigurationEvent"]').each do |event| + timestamp = event['timestamp'].to_i - initial_timestamp - # Add the video to the EDL - case event['eventname'] - when 'StartWebcamShareEvent', 'StartWebRTCShareEvent' - videos[filename] = { :timestamp => timestamp } - active_videos << filename - - edl_entry = { - :timestamp => timestamp, - :areas => { :webcam => [] } - } - active_videos.each do |filename| - edl_entry[:areas][:webcam] << { - :filename => filename, - :timestamp => timestamp - videos[filename][:timestamp] - } + # Determine the video filename if event is as the following + case event['eventname'] + when 'StartWebcamShareEvent', 'StopWebcamShareEvent' + stream = event.at_xpath('stream').text + filename = "#{video_dir}/#{stream}.flv" + when 'StartWebRTCShareEvent', 'StopWebRTCShareEvent' + uri = event.at_xpath('filename').text + filename = "#{video_dir}/#{File.basename(uri)}" end - video_edl << edl_entry - when 'StopWebcamShareEvent', 'StopWebRTCShareEvent' - active_videos.delete(filename) - edl_entry = { - :timestamp => timestamp, - :areas => { :webcam => [] } - } - active_videos.each do |filename| - edl_entry[:areas][:webcam] << { - :filename => filename, - :timestamp => timestamp - videos[filename][:timestamp] + # Add the video to the EDL + case event['eventname'] + when 'StartWebcamShareEvent', 'StartWebRTCShareEvent' + userId = BigBlueButton::Events.get_id_from_filename(filename) + is_in_forbidden_period = webcamsOnlyForModerator + + if (!is_in_forbidden_period) || (is_in_forbidden_period && BigBlueButton::Events.is_user_moderator(userId, list_user_info)) + + videos[filename] = { :timestamp => timestamp } + active_videos << filename + + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp], + :user_id => BigBlueButton::Events.get_id_from_filename(filename) + } + end + video_edl << edl_entry + elsif is_in_forbidden_period && !BigBlueButton::Events.is_user_moderator(userId, list_user_info) + inactive_videos << filename + videos[filename] = { :timestamp => timestamp } + end + when 'StopWebcamShareEvent', 'StopWebRTCShareEvent' + userId = BigBlueButton::Events.get_id_from_filename(filename) + is_in_forbidden_period = webcamsOnlyForModerator + + if (!is_in_forbidden_period) || (is_in_forbidden_period && BigBlueButton::Events.is_user_moderator(userId, list_user_info)) + active_videos.delete(filename) + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp], + :user_id => BigBlueButton::Events.get_id_from_filename(filename) + } + end + video_edl << edl_entry + elsif is_in_forbidden_period && !BigBlueButton::Events.is_user_moderator(userId, list_user_info) + inactive_videos.delete(filename) + end + when "ParticipantJoinEvent" + user_id = event.at_xpath('userId').text + list_user_info[user_id] = event.at_xpath('role').text + + when "ParticipantStatusChangeEvent" + is_in_forbidden_period = webcamsOnlyForModerator + userId = "" + filename_to_add = "" + + if event.at_xpath('status').text == "role" + userId = event.at_xpath('userId').text + + if is_in_forbidden_period && event.at_xpath('value').text == "MODERATOR" + filename_to_add = BigBlueButton::Events.extract_filename_from_userId(userId, inactive_videos) + if filename_to_add != "" + inactive_videos.delete(filename_to_add) + active_videos << filename_to_add + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp], + :user_id => userId + } + end + video_edl << edl_entry + end + elsif is_in_forbidden_period && event.at_xpath('value').text == "VIEWER" + filename_to_add = BigBlueButton::Events.extract_filename_from_userId(userId, active_videos) + if filename != "" + active_videos.delete(filename_to_add) + inactive_videos << filename_to_add + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } + } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp], + :user_id => userId + } + end + video_edl << edl_entry + end + end + user_id = event.at_xpath('userId').text + list_user_info[user_id] = event.at_xpath('value').text + end + + when "MeetingConfigurationEvent" + webcamsOnlyForModerator = BigBlueButton::Events.to_boolean(event.at_xpath('webcamsOnlyForModerator').text) + + when "WebcamsOnlyForModeratorEvent" + # Change active and inactive videos. + BigBlueButton::Events.process_webcamsOnlyForModerator(list_user_info, active_videos, inactive_videos, BigBlueButton::Events.to_boolean(event.at_xpath("webcamsOnlyForModerator").text)) + + edl_entry = { + :timestamp => timestamp, + :areas => { :webcam => [] } } + active_videos.each do |filename| + edl_entry[:areas][:webcam] << { + :filename => filename, + :timestamp => timestamp - videos[filename][:timestamp], + :user_id => userId + } + end + video_edl << edl_entry + + webcamsOnlyForModerator = BigBlueButton::Events.to_boolean(event.at_xpath('webcamsOnlyForModerator').text) end - video_edl << edl_entry end end diff --git a/record-and-playback/core/lib/recordandplayback/generators/video.rb b/record-and-playback/core/lib/recordandplayback/generators/video.rb index 76e8ecee2d..c7a0ac5a18 100755 --- a/record-and-playback/core/lib/recordandplayback/generators/video.rb +++ b/record-and-playback/core/lib/recordandplayback/generators/video.rb @@ -28,7 +28,7 @@ require File.expand_path('../../edl', __FILE__) module BigBlueButton - def BigBlueButton.process_webcam_videos(target_dir, raw_archive_dir, output_width, output_height, output_framerate, audio_offset, processed_audio_file, video_formats=['webm']) + def BigBlueButton.process_webcam_videos(target_dir, raw_archive_dir, output_width, output_height, output_framerate, audio_offset, processed_audio_file, video_formats=['webm'], show_moderator_viewpoint=false) BigBlueButton.logger.info("Processing webcam videos") # raw_archive_dir already contains meeting_id @@ -38,7 +38,7 @@ module BigBlueButton start_time = BigBlueButton::Events.first_event_timestamp(events) end_time = BigBlueButton::Events.last_event_timestamp(events) webcam_edl = BigBlueButton::Events.create_webcam_edl( - events, raw_archive_dir) + events, raw_archive_dir, show_moderator_viewpoint) user_video_edl = BigBlueButton::Events.edl_match_recording_marks_video( webcam_edl, events, start_time, end_time) BigBlueButton::EDL::Video.dump(user_video_edl) diff --git a/record-and-playback/core/scripts/bigbluebutton.yml b/record-and-playback/core/scripts/bigbluebutton.yml index 74a75217e6..3568e5eb67 100755 --- a/record-and-playback/core/scripts/bigbluebutton.yml +++ b/record-and-playback/core/scripts/bigbluebutton.yml @@ -40,6 +40,11 @@ anonymize_chat: false # meta param: meta_bbb-anonymize-chat-moderators (true/false) anonymize_chat_moderators: false +# By default, recordings assume the Viewer viewpoint (with all locks) +# so when webcamsOnlyForModerator=true, only moderators webcams are included in recordings. +# Use this option to ignore locks and assume Moderator viewpoint instead. +show_moderator_viewpoint: false + # Sequence of recording steps. Keys are the current step, values # are the next step(s). Examples: # current_step: next_step diff --git a/record-and-playback/core/scripts/post_events/post_events_analytics_callback.rb b/record-and-playback/core/scripts/post_events/post_events_analytics_callback.rb index 6751d4bd80..fc2094066a 100755 --- a/record-and-playback/core/scripts/post_events/post_events_analytics_callback.rb +++ b/record-and-playback/core/scripts/post_events/post_events_analytics_callback.rb @@ -152,8 +152,20 @@ begin # analytics_callback_url = metadata.key?("analytics-callback-url") ? metadata["analytics-callback-url"].value : nil unless analytics_callback_url.nil? BigBlueButton.logger.info("Processing events for analytics...") + filepathOverride = "/etc/bigbluebutton/bbb-web.properties" + hasOverride = File.file?(filepathOverride) bbb_props = JavaProperties::Properties.new("/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties") + + # If the file does exists: + if (hasOverride) + bbbOverrideProps = JavaProperties::Properties.new(filepathOverride) + # Override the props + bbbOverrideProps.each do |key, prop| + bbb_props[key]=prop + end + end + secret = bbb_props[:securitySalt] external_meeting_id = metadata.attributes['meetingId']&.content diff --git a/record-and-playback/presentation/scripts/caption/presentation b/record-and-playback/presentation/scripts/caption/presentation index 8f991b760e..af4546dcf4 100755 --- a/record-and-playback/presentation/scripts/caption/presentation +++ b/record-and-playback/presentation/scripts/caption/presentation @@ -47,6 +47,13 @@ presentation_props = File.open(File.expand_path('../presentation.yml', __dir__)) YAML.safe_load(pres_yml) end +filepathPresOverride = "/etc/bigbluebutton/recording/presentation.yml" +isThereOverride = File.file?(filepathPresOverride) +if (isThereOverride) + presOverrideProps = YAML::load(File.open(filepathPresOverride)) + presentation_props = presentation_props.merge(presOverrideProps) +end + logger = Journald::Logger.new('caption/presentation') logger.tag(record_id: recording_id) diff --git a/record-and-playback/presentation/scripts/process/presentation.rb b/record-and-playback/presentation/scripts/process/presentation.rb index 557947034d..aa64702af2 100755 --- a/record-and-playback/presentation/scripts/process/presentation.rb +++ b/record-and-playback/presentation/scripts/process/presentation.rb @@ -41,6 +41,13 @@ meeting_id = opts[:meeting_id] # This script lives in scripts/archive/steps while properties.yaml lives in scripts/ props = BigBlueButton.read_props presentation_props = YAML.safe_load(File.open('presentation.yml')) +filepathPresOverride = "/etc/bigbluebutton/recording/presentation.yml" +hasOverride = File.file?(filepathPresOverride) +if (hasOverride) + presOverrideProps = YAML::load(File.open(filepathPresOverride)) + presentation_props = presentation_props.merge(presOverrideProps) +end + presentation_props['audio_offset'] = 0 if presentation_props['audio_offset'].nil? presentation_props['include_deskshare'] = false if presentation_props['include_deskshare'].nil? @@ -218,7 +225,7 @@ unless FileTest.directory?(target_dir) webcam_framerate = 15 if webcam_framerate.nil? processed_audio_file = BigBlueButton::AudioProcessor.get_processed_audio_file(raw_archive_dir, "#{target_dir}/audio") - BigBlueButton.process_webcam_videos(target_dir, raw_archive_dir, webcam_width, webcam_height, webcam_framerate, presentation_props['audio_offset'], processed_audio_file, presentation_props['video_formats']) + BigBlueButton.process_webcam_videos(target_dir, raw_archive_dir, webcam_width, webcam_height, webcam_framerate, presentation_props['audio_offset'], processed_audio_file, presentation_props['video_formats'], props['show_moderator_viewpoint']) end if !Dir["#{raw_archive_dir}/deskshare/*"].empty? && presentation_props['include_deskshare'] diff --git a/record-and-playback/presentation/scripts/publish/presentation.rb b/record-and-playback/presentation/scripts/publish/presentation.rb index 68ecaeeae8..38ad1049e5 100755 --- a/record-and-playback/presentation/scripts/publish/presentation.rb +++ b/record-and-playback/presentation/scripts/publish/presentation.rb @@ -35,6 +35,12 @@ require 'json' # This script lives in scripts/archive/steps while properties.yaml lives in scripts/ bbb_props = BigBlueButton.read_props @presentation_props = YAML.safe_load(File.read('presentation.yml')) +filepathPresOverride = "/etc/bigbluebutton/recording/presentation.yml" +hasOverride = File.file?(filepathPresOverride) +if (hasOverride) + presOverrideProps = YAML::load(File.open(filepathPresOverride)) + $presentation_props = $presentation_props.merge(presOverrideProps) +end # There's a couple of places where stuff is mysteriously divided or multiplied # by 2. This is just here to call out how spooky that is. diff --git a/record-and-playback/screenshare/scripts/process/screenshare.rb b/record-and-playback/screenshare/scripts/process/screenshare.rb index 5716374dc8..a093b7765e 100644 --- a/record-and-playback/screenshare/scripts/process/screenshare.rb +++ b/record-and-playback/screenshare/scripts/process/screenshare.rb @@ -84,7 +84,7 @@ begin logger.info "Generating video events list" # Webcams - webcam_edl = BigBlueButton::Events.create_webcam_edl(events, raw_archive_dir) + webcam_edl = BigBlueButton::Events.create_webcam_edl(events, raw_archive_dir, props['show_moderator_viewpoint']) logger.debug "Webcam EDL:" BigBlueButton::EDL::Video.dump(webcam_edl)
{intl.formatMessage({= boundaryLeft && registeredOn <= boundaryRight) || (leftOn >= boundaryLeft && leftOn <= boundaryRight) || (boundaryLeft > registeredOn && boundaryRight < leftOn) - || (boundaryLeft >= registeredOn && leftOn === 0) ? ( - (function makeLineThrough() { - let roundedLeft = registeredOn >= boundaryLeft - && registeredOn <= boundaryRight ? 'rounded-l' : ''; - let roundedRight = leftOn >= boundaryLeft - && leftOn <= boundaryRight ? 'rounded-r' : ''; - let offsetLeft = 0; - let offsetRight = 0; - if (registeredOn >= boundaryLeft - && registeredOn <= boundaryRight) { - offsetLeft = ((registeredOn - boundaryLeft) * 100) - / interval; - } - if (leftOn >= boundaryLeft && leftOn <= boundaryRight) { - offsetRight = ((boundaryRight - leftOn) * 100) / interval; - } - let width = ''; - if (offsetLeft === 0 && offsetRight >= 99) { - width = 'w-1.5'; - } - if (offsetRight === 0 && offsetLeft >= 99) { - width = 'w-1.5'; - } - if (offsetLeft && offsetRight) { - const variation = offsetLeft - offsetRight; - if (variation > -1 && variation < 1) { - width = 'w-1.5'; - } - } - if (isRTL) { - const aux = roundedRight; - - if (roundedLeft !== '') roundedRight = 'rounded-r'; - else roundedRight = ''; - - if (aux !== '') roundedLeft = 'rounded-l'; - else roundedLeft = ''; - } - const redress = '(0.375rem / 2)'; - return ( -
- ); - })() - ) : null } + || (boundaryLeft >= registeredOn && leftOn === 0) + ? makeLineThrough(userPeriod, period) + : null } { userEmojisInPeriod.map((emoji) => { const offset = ((emoji.sentOn - period.start) * 100) / (interval); @@ -285,7 +294,12 @@ class StatusTable extends React.Component { defaultMessage: emojiConfigs[emoji.name].defaultMessage, })} > - +
); }) } diff --git a/bbb-learning-dashboard/src/components/UserDetails/component.jsx b/bbb-learning-dashboard/src/components/UserDetails/component.jsx index f8dffc78c0..1a363d8cbb 100644 --- a/bbb-learning-dashboard/src/components/UserDetails/component.jsx +++ b/bbb-learning-dashboard/src/components/UserDetails/component.jsx @@ -176,6 +176,11 @@ const UserDatailsComponent = (props) => { if (hasDraw) mostCommonAnswer = null; } + const capitalizeFirstLetter = (text) => ( + String.fromCharCode(text.charCodeAt(0) - 32) + + text.substring(1) + ); + return (
{question}
@@ -211,11 +216,11 @@ const UserDatailsComponent = (props) => {
{ mostCommonAnswer - ? `${String.fromCharCode(mostCommonAnswer.charCodeAt(0) - 32)}${mostCommonAnswer.substring(1)}` + ? capitalizeFirstLetter(mostCommonAnswer) : intl.formatMessage({ id: 'app.learningDashboard.usersTable.notAvailable', defaultMessage: 'N/A', @@ -233,7 +238,7 @@ const UserDatailsComponent = (props) => {
{category}
- { (function () { + { (function getAverage() { if (average >= 0 && category === 'Talk Time') return tsToHHmmss(average); if (average >= 0 && category !== 'Talk Time') return ; return ; diff --git a/bbb-pads.placeholder.sh b/bbb-pads.placeholder.sh index 5cf3e35883..47d3f38b91 100755 --- a/bbb-pads.placeholder.sh +++ b/bbb-pads.placeholder.sh @@ -1 +1 @@ -git clone --branch v1.0.2 --depth 1 https://github.com/bigbluebutton/bbb-pads bbb-pads +git clone --branch v1.2.0 --depth 1 https://github.com/bigbluebutton/bbb-pads bbb-pads diff --git a/bbb-playback.placeholder.sh b/bbb-playback.placeholder.sh index e82533670c..4b49187e9c 100755 --- a/bbb-playback.placeholder.sh +++ b/bbb-playback.placeholder.sh @@ -1 +1 @@ -git clone --branch v3.4.0 --depth 1 https://github.com/bigbluebutton/bbb-playback bbb-playback +git clone --branch v4.0.0 --depth 1 https://github.com/bigbluebutton/bbb-playback bbb-playback diff --git a/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_conference.xml b/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_conference.xml index 719ecb3e8c..1f59ea45bc 100644 --- a/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_conference.xml +++ b/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_conference.xml @@ -3,7 +3,7 @@ - + @@ -11,7 +11,7 @@ - + diff --git a/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_echo_to_conference.xml b/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_echo_to_conference.xml index 6711ba309e..3821189677 100644 --- a/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_echo_to_conference.xml +++ b/bbb-voice-conference/config/freeswitch/conf/dialplan/default/bbb_echo_to_conference.xml @@ -2,7 +2,7 @@ - + diff --git a/bbb-webrtc-sfu.placeholder.sh b/bbb-webrtc-sfu.placeholder.sh index e9fb3aa333..487232dfdc 100755 --- a/bbb-webrtc-sfu.placeholder.sh +++ b/bbb-webrtc-sfu.placeholder.sh @@ -1 +1 @@ -git clone --branch v2.8.0-alpha.1 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu +git clone --branch v2.8.1 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu diff --git a/bigbluebutton-config/bigbluebutton-release b/bigbluebutton-config/bigbluebutton-release index fc15447904..16547f44f6 100644 --- a/bigbluebutton-config/bigbluebutton-release +++ b/bigbluebutton-config/bigbluebutton-release @@ -1 +1 @@ -BIGBLUEBUTTON_RELEASE=2.5.0-beta.1 +BIGBLUEBUTTON_RELEASE=2.5.0-rc.2 diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf index 5a6d6286c8..c4df763d6a 100755 --- a/bigbluebutton-config/bin/bbb-conf +++ b/bigbluebutton-config/bin/bbb-conf @@ -658,8 +658,10 @@ fi if [[ $SECRET ]]; then need_root - if get_properties_value securitySalt "$BBB_WEB_ETC_CONFIG" > /dev/null ; then - change_var_salt "$BBB_WEB_ETC_CONFIG" securitySalt "$SECRET" + + echo "Assigning secret in $BBB_WEB_ETC_CONFIG" + if [ -f "$BBB_WEB_ETC_CONFIG" ] && grep "^securitySalt" "$BBB_WEB_ETC_CONFIG" > /dev/null ; then + change_var_value "$BBB_WEB_ETC_CONFIG" securitySalt "$SECRET" else echo "securitySalt=$SECRET" >> "$BBB_WEB_ETC_CONFIG" fi @@ -1296,19 +1298,6 @@ check_state() { done fi - stunServerAddress=$(cat /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini | sed -n '/^stunServerAddress/{s/.*=//;p}') - stunServerPort=$(cat /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini | sed -n '/^stunServerPort/{s/.*=//;p}') - if [ ! -z "$stunServerAddress" ]; then - if stunclient --mode full --localport 30000 $stunServerAddress $stunServerPort | grep -q "fail\|Unable\ to\ resolve"; then - echo - echo "#" - echo "# Warning: Failed to verify STUN server at $stunServerAddress:$stunServerPort with command" - echo "#" - echo "# stunclient --mode full --localport 30000 $stunServerAddress $stunServerPort" - echo "#" - fi - fi - BBB_LOG="/var/log/bigbluebutton" if [ "$(stat -c "%U %G" $BBB_LOG)" != "bigbluebutton bigbluebutton" ]; then echo @@ -1476,14 +1465,6 @@ if [ $CHECK ]; then done fi - stunServerAddress=$(cat /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini | sed -n '/^stunServerAddress/{s/.*=//;p}') - stunServerPort=$(cat /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini | sed -n '/^stunServerPort/{s/.*=//;p}') - if [ ! -z "$stunServerAddress" ]; then - echo - echo "/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini (STUN Server)" - echo " stun: $stunServerAddress:$stunServerPort" - fi - check_state echo @@ -1633,7 +1614,12 @@ if [ -n "$HOST" ]; then if [ -f "$BBB_WEB_ETC_CONFIG" ] && grep "bigbluebutton.web.serverURL" "$BBB_WEB_ETC_CONFIG" > /dev/null ; then change_var_value "$BBB_WEB_ETC_CONFIG" bigbluebutton.web.serverURL "$PROTOCOL://$HOST" else - echo "bigbluebutton.web.serverURL=$PROTOCOL://$HOST" > "$BBB_WEB_ETC_CONFIG" + echo "bigbluebutton.web.serverURL=$PROTOCOL://$HOST" >> "$BBB_WEB_ETC_CONFIG" + fi + + # Populate /etc/bigbluebutton/bbb-web.properites with the shared secret + if ! grep -q "^securitySalt" "$BBB_WEB_ETC_CONFIG"; then + echo "securitySalt=$(get_bbb_web_config_value securitySalt)" >> "$BBB_WEB_ETC_CONFIG" fi diff --git a/bigbluebutton-html5/.dockerignore b/bigbluebutton-html5/.dockerignore deleted file mode 100644 index bf9b07fdc2..0000000000 --- a/bigbluebutton-html5/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -Dockerfile -Dockerfile.dev diff --git a/bigbluebutton-html5/.meteor/packages b/bigbluebutton-html5/.meteor/packages index aa067a2e2a..137d6f4190 100644 --- a/bigbluebutton-html5/.meteor/packages +++ b/bigbluebutton-html5/.meteor/packages @@ -8,10 +8,10 @@ mobile-experience@1.1.0 mongo@1.14.6 reactive-var@1.0.11 -standard-minifier-css@1.7.4 +standard-minifier-css@1.8.1 standard-minifier-js@2.8.0 es5-shim@4.8.0 -ecmascript@0.16.1 +ecmascript@0.16.2 shell-server@0.5.0 static-html@1.3.2 diff --git a/bigbluebutton-html5/.meteor/release b/bigbluebutton-html5/.meteor/release index b1b0ccebfe..8e3f1708ae 100644 --- a/bigbluebutton-html5/.meteor/release +++ b/bigbluebutton-html5/.meteor/release @@ -1 +1 @@ -METEOR@2.6.1 +METEOR@2.7.1 diff --git a/bigbluebutton-html5/.meteor/versions b/bigbluebutton-html5/.meteor/versions index 212a60269f..bf1e9659b4 100644 --- a/bigbluebutton-html5/.meteor/versions +++ b/bigbluebutton-html5/.meteor/versions @@ -1,6 +1,6 @@ allow-deny@1.1.1 autoupdate@1.8.0 -babel-compiler@7.8.1 +babel-compiler@7.9.0 babel-runtime@1.5.0 base64@1.0.12 binary-heap@1.0.11 @@ -16,11 +16,11 @@ ddp-common@1.4.0 ddp-server@2.5.0 diff-sequence@1.1.1 dynamic-import@0.7.2 -ecmascript@0.16.1 +ecmascript@0.16.2 ecmascript-runtime@0.8.0 ecmascript-runtime-client@0.12.1 ecmascript-runtime-server@0.11.0 -ejson@1.1.1 +ejson@1.1.2 es5-shim@4.8.0 fetch@0.1.1 geojson-utils@1.0.10 @@ -39,13 +39,13 @@ meteortesting:browser-tests@1.3.5 meteortesting:mocha@2.0.3 meteortesting:mocha-core@8.1.2 minifier-css@1.6.0 -minifier-js@2.7.3 +minifier-js@2.7.4 minimongo@1.8.0 mobile-experience@1.1.0 mobile-status-bar@1.1.0 modern-browsers@0.1.7 modules@0.18.0 -modules-runtime@0.12.0 +modules-runtime@0.13.0 mongo@1.14.6 mongo-decimal@0.1.2 mongo-dev-server@1.1.0 @@ -54,7 +54,7 @@ npm-mongo@4.3.1 ordered-dict@1.1.0 promise@0.12.0 random@1.2.0 -react-fast-refresh@0.2.2 +react-fast-refresh@0.2.3 react-meteor-data@2.4.0 reactive-dict@1.3.0 reactive-var@1.0.11 @@ -66,12 +66,12 @@ session@1.2.0 shell-server@0.5.0 socket-stream-client@0.4.0 spacebars-compiler@1.3.0 -standard-minifier-css@1.7.4 +standard-minifier-css@1.8.1 standard-minifier-js@2.8.0 static-html@1.3.2 templating-tools@1.2.1 tracker@1.2.0 -typescript@4.4.1 +typescript@4.5.4 underscore@1.0.10 url@1.3.2 webapp@1.13.1 diff --git a/bigbluebutton-html5/Dockerfile b/bigbluebutton-html5/Dockerfile deleted file mode 100644 index 8e4b24cb17..0000000000 --- a/bigbluebutton-html5/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM node:8 - -RUN set -x \ - && curl -sL https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh \ - && useradd -m -G users -s /bin/bash meteor - -RUN apt-get update && apt-get -y install jq - -COPY . /source - -RUN cd /source \ - && mv docker-entrypoint.sh /usr/local/bin/ \ - && chown -R meteor:meteor . \ - && mkdir /app \ - && chown -R meteor:meteor /app - -USER meteor - -RUN cd /source \ - && meteor npm install \ - && meteor build --directory /app - -ENV NODE_ENV production - -RUN cd /app/bundle/programs/server \ - && npm install \ - && npm cache clear --force - -WORKDIR /app/bundle - -ENV MONGO_URL=mongodb://mongo:27017/html5client \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - METEOR_SETTINGS_MODIFIER=. - -EXPOSE 3000 - -CMD ["docker-entrypoint.sh"] diff --git a/bigbluebutton-html5/Dockerfile.dev b/bigbluebutton-html5/Dockerfile.dev deleted file mode 100644 index 692c200be7..0000000000 --- a/bigbluebutton-html5/Dockerfile.dev +++ /dev/null @@ -1,24 +0,0 @@ -FROM node:8 - -COPY . /source - -RUN set -x \ - && curl -sL https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh \ - && useradd -m -G users -s /bin/bash meteor \ - && chown -R meteor:meteor /source - -USER meteor - -RUN cd /source \ - && meteor npm install - -WORKDIR /source - -ENV MONGO_URL=mongodb://mongo:27017/html5client \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 - -EXPOSE 3000 - -CMD ["npm", "start"] - diff --git a/bigbluebutton-html5/docker-entrypoint.sh b/bigbluebutton-html5/docker-entrypoint.sh deleted file mode 100755 index a5a73cf32b..0000000000 --- a/bigbluebutton-html5/docker-entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -e - -export METEOR_SETTINGS=` jq "${METEOR_SETTINGS_MODIFIER}" ./programs/server/assets/app/config/settings.yml ` - -exec node main.js diff --git a/bigbluebutton-html5/imports/api/connection-status/server/methods/voidConnection.js b/bigbluebutton-html5/imports/api/connection-status/server/methods/voidConnection.js index 85297dbab7..7f369c5a3d 100644 --- a/bigbluebutton-html5/imports/api/connection-status/server/methods/voidConnection.js +++ b/bigbluebutton-html5/imports/api/connection-status/server/methods/voidConnection.js @@ -1,4 +1,9 @@ +import { PrometheusAgent, METRIC_NAMES } from '/imports/startup/server/prom-metrics/index.js' + // Round-trip time helper -export default function voidConnection() { +export default function voidConnection(previousRtt) { + if (previousRtt) { + PrometheusAgent.observe(METRIC_NAMES.METEOR_RTT, previousRtt/1000); + } return 0; } diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js index c82baeb2de..02702537eb 100755 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js @@ -139,10 +139,13 @@ export default function addMeeting(meeting) { const sanitizeTextInChat = original => SanitizeHTML(original, { allowedTags: ['a', 'b', 'br', 'i', 'img', 'li', 'small', 'span', 'strong', 'u', 'ul'], allowedAttributes: { - a: ['href', 'name', 'target'], + a: ['href', 'target'], img: ['src', 'width', 'height'], }, allowedSchemes: ['https'], + allowedSchemesByTag: { + a: ['https', 'mailto', 'tel'] + } }); const sanitizedWelcomeText = sanitizeTextInChat(welcomeMsg); @@ -153,14 +156,18 @@ export default function addMeeting(meeting) { const insertBlankTarget = (s, i) => `${s.substr(0, i)} target="_blank"${s.substr(i)}`; const linkWithoutTarget = new RegExp('', 'g'); - linkWithoutTarget.test(welcomeMsg); - if (linkWithoutTarget.lastIndex > 0) { - welcomeMsg = insertBlankTarget( - welcomeMsg, - linkWithoutTarget.lastIndex - 1, - ); - } + do { + linkWithoutTarget.test(welcomeMsg); + + if (linkWithoutTarget.lastIndex > 0) { + welcomeMsg = insertBlankTarget( + welcomeMsg, + linkWithoutTarget.lastIndex - 1, + ); + linkWithoutTarget.lastIndex = linkWithoutTarget.lastIndex - 1; + } + } while (linkWithoutTarget.lastIndex > 0); newMeeting.welcomeProp.welcomeMsg = welcomeMsg; diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js index c76f09a213..c28fec6133 100644 --- a/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js @@ -1,23 +1,26 @@ import { check } from 'meteor/check'; import Logger from '/imports/startup/server/logger'; import PresentationUploadToken from '/imports/api/presentation-upload-token'; +import Presentations from '/imports/api/presentations'; export default function handlePresentationUploadTokenPass({ body, header }, meetingId) { check(body, Object); const { userId } = header; - const { podId, authzToken, filename } = body; + const { podId, authzToken, filename, tmpPresId } = body; check(userId, String); check(podId, String); check(authzToken, String); check(filename, String); + check(tmpPresId, String) const selector = { meetingId, podId, userId, filename, + tmpPresId, }; const modifier = { @@ -26,6 +29,7 @@ export default function handlePresentationUploadTokenPass({ body, header }, meet userId, filename, authzToken, + tmpPresId, failed: false, used: false, }; diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/requestPresentationUploadToken.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/requestPresentationUploadToken.js index d7b04bd6da..bd5f094654 100644 --- a/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/requestPresentationUploadToken.js +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/requestPresentationUploadToken.js @@ -3,7 +3,7 @@ import { check } from 'meteor/check'; import { extractCredentials } from '/imports/api/common/server/helpers'; import Logger from '/imports/startup/server/logger'; -export default function requestPresentationUploadToken(podId, filename) { +export default function requestPresentationUploadToken(podId, filename, tmpPresId) { const REDIS_CONFIG = Meteor.settings.private.redis; const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; const EVENT_NAME = 'PresentationUploadTokenReqMsg'; @@ -15,10 +15,12 @@ export default function requestPresentationUploadToken(podId, filename) { check(requesterUserId, String); check(podId, String); check(filename, String); + check(tmpPresId, String); const payload = { podId, filename, + tmpPresId }; RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/publishers.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/publishers.js index d0f8668e5b..45efc75340 100644 --- a/bigbluebutton-html5/imports/api/presentation-upload-token/server/publishers.js +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/publishers.js @@ -4,7 +4,7 @@ import PresentationUploadToken from '/imports/api/presentation-upload-token'; import Logger from '/imports/startup/server/logger'; import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation'; -function presentationUploadToken(podId, filename) { +function presentationUploadToken(podId, filename, tmpPresId) { const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { @@ -16,12 +16,14 @@ function presentationUploadToken(podId, filename) { check(podId, String); check(filename, String); + check(tmpPresId, String); const selector = { meetingId, podId, userId, filename, + tmpPresId, }; Logger.debug('Publishing PresentationUploadToken', { meetingId, userId }); diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js index 4f2c33b659..d3566c3d85 100755 --- a/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js +++ b/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js @@ -34,6 +34,7 @@ export default function addPresentation(meetingId, podId, presentation) { id: String, name: String, current: Boolean, + temporaryPresentationId: String, pages: [ { id: String, diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js index 8079f53c83..77b5e8fd45 100644 --- a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js +++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js @@ -26,10 +26,10 @@ export default function addUserPersistentData(user) { locked: Boolean, avatar: String, clientType: String, + left: Boolean, effectiveConnectionType: null, }); - const { intId, extId, diff --git a/bigbluebutton-html5/imports/api/users/server/eventHandlers.js b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js index 15335c432c..fea9ed8ebf 100644 --- a/bigbluebutton-html5/imports/api/users/server/eventHandlers.js +++ b/bigbluebutton-html5/imports/api/users/server/eventHandlers.js @@ -1,6 +1,7 @@ import RedisPubSub from '/imports/startup/server/redis'; import handleRemoveUser from './handlers/removeUser'; import handleUserJoined from './handlers/userJoined'; +import handleUserLeftFlagUpdated from './handlers/userLeftFlagUpdated'; import handleValidateAuthToken from './handlers/validateAuthToken'; import handlePresenterAssigned from './handlers/presenterAssigned'; import handleEmojiStatus from './handlers/emojiStatus'; @@ -14,5 +15,6 @@ RedisPubSub.on('UserLeftMeetingEvtMsg', handleRemoveUser); RedisPubSub.on('ValidateAuthTokenRespMsg', handleValidateAuthToken); RedisPubSub.on('UserEmojiChangedEvtMsg', handleEmojiStatus); RedisPubSub.on('UserRoleChangedEvtMsg', handleChangeRole); +RedisPubSub.on('UserLeftFlagUpdatedEvtMsg', handleUserLeftFlagUpdated); RedisPubSub.on('UserPinStateChangedEvtMsg', handleUserPinChanged); RedisPubSub.on('UserInactivityInspectMsg', handleUserInactivityInspect); diff --git a/bigbluebutton-html5/imports/api/users/server/handlers/userLeftFlagUpdated.js b/bigbluebutton-html5/imports/api/users/server/handlers/userLeftFlagUpdated.js new file mode 100644 index 0000000000..328e2fc78b --- /dev/null +++ b/bigbluebutton-html5/imports/api/users/server/handlers/userLeftFlagUpdated.js @@ -0,0 +1,13 @@ +import { check } from 'meteor/check'; + +import userLeftFlag from '../modifiers/userLeftFlagUpdated'; + +export default function handleUserLeftFlag({ body }, meetingId) { + const user = body; + check(user, { + intId: String, + userLeftFlag: Boolean, + }); + + userLeftFlag(meetingId, user.intId, user.userLeftFlag); +} diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js index 31d790027e..b7312ed156 100755 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js @@ -62,6 +62,7 @@ export default function addUser(meetingId, userData) { inactivityCheck: false, responseDelay: 0, loggedOut: false, + left: false, ...flat(user), }; diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js index c8551f0d63..b5390ed728 100644 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/createDummyUser.js @@ -19,6 +19,7 @@ export default function createDummyUser(meetingId, userId, authToken) { authToken, clientType: 'HTML5', validated: null, + left: false, }; try { diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/userLeftFlagUpdated.js b/bigbluebutton-html5/imports/api/users/server/modifiers/userLeftFlagUpdated.js new file mode 100644 index 0000000000..ae157ec9bb --- /dev/null +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/userLeftFlagUpdated.js @@ -0,0 +1,24 @@ +import Logger from '/imports/startup/server/logger'; +import Users from '/imports/api/users'; + +export default function userLeftFlagUpdated(meetingId, userId, left) { + const selector = { + meetingId, + userId, + }; + + const modifier = { + $set: { + left, + }, + }; + + try { + const numberAffected = Users.update(selector, modifier); + if (numberAffected) { + Logger.info(`Updated user ${userId} with left flag as ${left}`); + } + } catch (err) { + Logger.error(`Changed user role: ${err}`); + } +} diff --git a/bigbluebutton-html5/imports/api/users/server/publishers.js b/bigbluebutton-html5/imports/api/users/server/publishers.js index 2307d4a3b6..c9dec9ec32 100644 --- a/bigbluebutton-html5/imports/api/users/server/publishers.js +++ b/bigbluebutton-html5/imports/api/users/server/publishers.js @@ -60,6 +60,7 @@ function users() { { meetingId }, ], intId: { $exists: true }, + left: false, }; const User = Users.findOne({ userId, meetingId }, { fields: { role: 1 } }); diff --git a/bigbluebutton-html5/imports/startup/server/index.js b/bigbluebutton-html5/imports/startup/server/index.js index eadeb94cd8..1d1c865ec8 100755 --- a/bigbluebutton-html5/imports/startup/server/index.js +++ b/bigbluebutton-html5/imports/startup/server/index.js @@ -4,7 +4,6 @@ import Langmap from 'langmap'; import fs from 'fs'; import Users from '/imports/api/users'; import './settings'; -import { lookup as lookupUserAgent } from 'useragent'; import { check } from 'meteor/check'; import Logger from './logger'; import Redis from './redis'; @@ -144,7 +143,8 @@ Meteor.startup(() => { Meteor.onMessage(event => { const { method } = event; if (method) { - PrometheusAgent.increment(METRIC_NAMES.METEOR_METHODS, { methodName: method }); + const methodName = method.includes('stream-cursor') ? 'stream-cursor' : method; + PrometheusAgent.increment(METRIC_NAMES.METEOR_METHODS, { methodName }); } }); @@ -303,20 +303,6 @@ WebApp.connectHandlers.use('/feedback', (req, res) => { })); }); -WebApp.connectHandlers.use('/useragent', (req, res) => { - const userAgent = req.headers['user-agent']; - let response = 'No user agent found in header'; - if (userAgent) { - response = lookupUserAgent(userAgent).toString(); - } - - Logger.info(`The requesting user agent is ${response}`); - - // res.setHeader('Content-Type', 'application/json'); - res.writeHead(200); - res.end(response); -}); - WebApp.connectHandlers.use('/guestWait', (req, res) => { if (!guestWaitHtml) { try { diff --git a/bigbluebutton-html5/imports/startup/server/logger.js b/bigbluebutton-html5/imports/startup/server/logger.js index 6896a7c6f6..7f7502502c 100755 --- a/bigbluebutton-html5/imports/startup/server/logger.js +++ b/bigbluebutton-html5/imports/startup/server/logger.js @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { createLogger, format, transports } from 'winston'; +import WinstonPromTransport from './prom-metrics/winstonPromTransport'; const LOG_CONFIG = Meteor?.settings?.private?.serverLog || {}; const { level } = LOG_CONFIG; @@ -20,6 +21,10 @@ const Logger = createLogger({ handleExceptions: true, level, }), + // export error logs to prometheus + new WinstonPromTransport({ + level: 'error', + }), ], }); diff --git a/bigbluebutton-html5/imports/startup/server/prom-metrics/metrics.js b/bigbluebutton-html5/imports/startup/server/prom-metrics/metrics.js index d5a7b7c83a..903cbe5230 100644 --- a/bigbluebutton-html5/imports/startup/server/prom-metrics/metrics.js +++ b/bigbluebutton-html5/imports/startup/server/prom-metrics/metrics.js @@ -1,34 +1,60 @@ const { Counter, + Gauge, + Histogram } = require('prom-client'); const METRICS_PREFIX = 'html5_' const METRIC_NAMES = { METEOR_METHODS: 'meteorMethods', + METEOR_ERRORS_TOTAL: 'meteorErrorsTotal', + METEOR_RTT: 'meteorRtt', + REDIS_MESSAGE_QUEUE: 'redisMessageQueue', + REDIS_PAYLOAD_SIZE: 'redisPayloadSize', + REDIS_PROCESSING_TIME: 'redisProcessingTime' } -const buildFrontendMetrics = () => { - return { - [METRIC_NAMES.METEOR_METHODS]: new Counter({ - name: `${METRICS_PREFIX}meteor_methods`, - help: 'Total number of meteor methods processed in html5', - labelNames: ['methodName', 'role', 'instanceId'], - }), - } -} - -const buildBackendMetrics = () => { - // TODO add relevant backend metrics - return {} -} - let METRICS; const buildMetrics = () => { if (METRICS == null) { - const isFrontend = (!process.env.BBB_HTML5_ROLE || process.env.BBB_HTML5_ROLE === 'frontend'); - const isBackend = (!process.env.BBB_HTML5_ROLE || process.env.BBB_HTML5_ROLE === 'backend'); - if (isFrontend) METRICS = buildFrontendMetrics(); - if (isBackend) METRICS = { ...METRICS, ...buildBackendMetrics()} + METRICS = { + [METRIC_NAMES.METEOR_METHODS]: new Counter({ + name: `${METRICS_PREFIX}meteor_methods`, + help: 'Total number of meteor methods processed in html5', + labelNames: ['methodName', 'role', 'instanceId'], + }), + + [METRIC_NAMES.METEOR_ERRORS_TOTAL]: new Counter({ + name: `${METRICS_PREFIX}meteor_errors_total`, + help: 'Total number of errors logs in meteor', + labelNames: ['errorMessage', 'role', 'instanceId'], + }), + + [METRIC_NAMES.METEOR_RTT]: new Histogram({ + name: `${METRICS_PREFIX}meteor_rtt_seconds`, + help: 'Round-trip time of meteor client-server connections in seconds', + buckets: [0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.75, 1, 1.5, 2, 2.5, 5], + labelNames: ['role', 'instanceId'], + }), + + [METRIC_NAMES.REDIS_MESSAGE_QUEUE]: new Gauge({ + name: `${METRICS_PREFIX}redis_message_queue`, + help: 'Message queue size in redis', + labelNames: ['meetingId', 'role', 'instanceId'], + }), + + [METRIC_NAMES.REDIS_PAYLOAD_SIZE]: new Histogram({ + name: `${METRICS_PREFIX}redis_payload_size`, + help: 'Redis events payload size', + labelNames: ['eventName', 'role', 'instanceId'], + }), + + [METRIC_NAMES.REDIS_PROCESSING_TIME]: new Histogram({ + name: `${METRICS_PREFIX}redis_processing_time`, + help: 'Redis events processing time in milliseconds', + labelNames: ['eventName', 'role', 'instanceId'], + }), + } } return METRICS; diff --git a/bigbluebutton-html5/imports/startup/server/prom-metrics/promAgent.js b/bigbluebutton-html5/imports/startup/server/prom-metrics/promAgent.js index 6c0ab53140..b7c668a808 100644 --- a/bigbluebutton-html5/imports/startup/server/prom-metrics/promAgent.js +++ b/bigbluebutton-html5/imports/startup/server/prom-metrics/promAgent.js @@ -81,6 +81,16 @@ class PrometheusScrapeAgent { metric.set(labelsObject, value) } } + + observe(metricName, value, labelsObject) { + if (!this.started) return; + + const metric = this.metrics[metricName]; + if (metric) { + labelsObject = { ...labelsObject, ...this.roleAndInstanceLabels }; + metric.observe(labelsObject, value) + } + } } export default PrometheusScrapeAgent; diff --git a/bigbluebutton-html5/imports/startup/server/prom-metrics/winstonPromTransport.js b/bigbluebutton-html5/imports/startup/server/prom-metrics/winstonPromTransport.js new file mode 100644 index 0000000000..44669b199a --- /dev/null +++ b/bigbluebutton-html5/imports/startup/server/prom-metrics/winstonPromTransport.js @@ -0,0 +1,19 @@ +const Transport = require('winston-transport'); +import { PrometheusAgent, METRIC_NAMES } from './index.js' + +module.exports = class WinstonPromTransport extends Transport { + constructor(opts) { + super(opts); + + } + + log(info, callback) { + setImmediate(() => { + this.emit('logged', info); + }); + + PrometheusAgent.increment(METRIC_NAMES.METEOR_ERRORS_TOTAL, { errorMessage: info.message }); + + callback(); + } +}; diff --git a/bigbluebutton-html5/imports/startup/server/redis.js b/bigbluebutton-html5/imports/startup/server/redis.js index c6035359a7..a80472b9b5 100755 --- a/bigbluebutton-html5/imports/startup/server/redis.js +++ b/bigbluebutton-html5/imports/startup/server/redis.js @@ -5,11 +5,13 @@ import { check } from 'meteor/check'; import Logger from './logger'; import Metrics from './metrics'; import queue from 'queue'; +import { PrometheusAgent, METRIC_NAMES } from './prom-metrics/index.js' // Fake meetingId used for messages that have no meetingId const NO_MEETING_ID = '_'; const { queueMetrics } = Meteor.settings.private.redis.metrics; +const { collectRedisMetrics: PROM_METRICS_ENABLED } = Meteor.settings.private.prometheus; const makeEnvelope = (channel, eventName, header, body, routing) => { const envelope = { @@ -78,6 +80,16 @@ class MeetingMessageQueue { } const queueLength = this.queue.length; + + if (PROM_METRICS_ENABLED) { + const dataLength = JSON.stringify(data).length; + const currentTimestamp = Date.now(); + const processTime = currentTimestamp - beginHandleTimestamp; + PrometheusAgent.observe(METRIC_NAMES.REDIS_PROCESSING_TIME, processTime, { eventName }); + PrometheusAgent.observe(METRIC_NAMES.REDIS_PAYLOAD_SIZE, dataLength, { eventName }); + meetingId && PrometheusAgent.set(METRIC_NAMES.REDIS_MESSAGE_QUEUE, queueLength, { meetingId }); + } + if (queueLength > 100) { Logger.warn(`Redis: MeetingMessageQueue for meetingId=${meetingId} has queue size=${queueLength} `); } diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx index 21d1704bc5..d0b5a69c7e 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx @@ -470,6 +470,7 @@ class BreakoutRoom extends PureComponent { .filter((user) => !stateUsersId.includes(user.userId)) .map((user) => ({ userId: user.userId, + extId: user.extId, userName: user.name, isModerator: user.role === ROLE_MODERATOR, room: 0, @@ -611,7 +612,8 @@ class BreakoutRoom extends PureComponent { } populateWithLastBreakouts(lastBreakouts) { - const { getBreakoutUserWasIn, users, intl } = this.props; + const { getBreakoutUserWasIn, intl } = this.props; + const { users } = this.state; const changedNames = []; lastBreakouts.forEach((breakout) => { diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx index 73ad4beaa7..afddce8b9b 100755 --- a/bigbluebutton-html5/imports/ui/components/app/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx @@ -44,6 +44,7 @@ import Settings from '/imports/ui/services/settings'; import LayoutService from '/imports/ui/components/layout/service'; import { registerTitleView } from '/imports/utils/dom-utils'; import GlobalStyles from '/imports/ui/stylesheets/styled-components/globalStyles'; +import MediaService from '/imports/ui/components/media/service'; const MOBILE_MEDIA = 'only screen and (max-width: 40em)'; const APP_CONFIG = Meteor.settings.public.app; @@ -156,6 +157,9 @@ class App extends Component { settingsLayout, isRTL, hidePresentation, + autoSwapLayout, + shouldShowScreenshare, + shouldShowExternalVideo, } = this.props; const { browserName } = browserInfo; const { osName } = deviceInfo; @@ -167,11 +171,18 @@ class App extends Component { value: isRTL, }); + const presentationOpen = !(autoSwapLayout || hidePresentation) + || shouldShowExternalVideo || shouldShowScreenshare; + layoutContextDispatch({ type: ACTIONS.SET_PRESENTATION_IS_OPEN, - value: !hidePresentation, + value: presentationOpen, }); + if (!presentationOpen && !MediaService.getSwapLayout()) { + MediaService.setSwapLayout(layoutContextDispatch); + } + Modal.setAppElement('#app'); const fontSize = isMobile() ? MOBILE_FONT_SIZE : DESKTOP_FONT_SIZE; diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx index e99676df35..7b4348e329 100755 --- a/bigbluebutton-html5/imports/ui/components/app/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx @@ -230,6 +230,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) Meteor.settings.public.presentation.restoreOnUpdate, ), hidePresentation: getFromUserSettings('bbb_hide_presentation', LAYOUT_CONFIG.hidePresentation), + autoSwapLayout: getFromUserSettings('bbb_auto_swap_layout', LAYOUT_CONFIG.autoSwapLayout), hideActionsBar: getFromUserSettings('bbb_hide_actions_bar', false), isModalOpen: !!getModal(), }; diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx index cfffb7bb9b..a6bdc71692 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -41,7 +41,7 @@ const handleLeaveAudio = () => { Storage.setItem('getEchoTest', true); } - Service.exitAudio(); + Service.forceExitAudio(); logger.info({ logCode: 'audiocontrols_leave_audio', extraInfo: { logType: 'user_action' }, diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/component.jsx index 38c491c434..e31800e0f9 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/component.jsx @@ -267,28 +267,7 @@ class AudioModal extends Component { disableActions: false, }); }).catch((err) => { - const { type } = err; - switch (type) { - case 'MEDIA_ERROR': - this.setState({ - content: 'help', - errCode: 0, - disableActions: false, - }); - break; - case 'CONNECTION_ERROR': - this.setState({ - errCode: 0, - disableActions: false, - }); - break; - default: - this.setState({ - errCode: 0, - disableActions: false, - }); - break; - } + this.handleJoinMicrophoneError(err); }); } @@ -342,7 +321,29 @@ class AudioModal extends Component { this.setState({ disableActions: false, }); - }).catch(this.handleGoToAudioOptions); + }).catch((err) => { + this.handleJoinMicrophoneError(err); + }); + } + + handleJoinMicrophoneError(err) { + const { type } = err; + switch (type) { + case 'MEDIA_ERROR': + this.setState({ + content: 'help', + errCode: 0, + disableActions: false, + }); + break; + case 'CONNECTION_ERROR': + default: + this.setState({ + errCode: 0, + disableActions: false, + }); + break; + } } setContent(content) { diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx index bf5cc39d88..cc15d5f3bd 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx @@ -14,6 +14,8 @@ import { screenshareHasEnded } from '/imports/ui/components/screenshare/service' import AudioManager from '/imports/ui/services/audio-manager'; import Settings from '/imports/ui/services/settings'; import BreakoutDropdown from '/imports/ui/components/breakout-room/breakout-dropdown/component'; +import Users from '/imports/api/users'; +import Auth from '/imports/ui/services/auth'; const intlMessages = defineMessages({ breakoutTitle: { @@ -282,7 +284,8 @@ class BreakoutRoom extends PureComponent { amIPresenter, intl, isUserInBreakoutRoom, - exitAudio, + forceExitAudio, + rejoinAudio, setBreakoutAudioTransferStatus, getBreakoutAudioTransferStatus, } = this.props; @@ -349,7 +352,7 @@ class BreakoutRoom extends PureComponent { this.getBreakoutURL(breakoutId); // leave main room's audio, // and stops video and screenshare when joining a breakout room - exitAudio(); + forceExitAudio(); logger.info({ logCode: 'breakoutroom_join', extraInfo: { logType: 'user_action' }, @@ -357,6 +360,31 @@ class BreakoutRoom extends PureComponent { VideoService.storeDeviceIds(); VideoService.exitVideo(); if (amIPresenter) screenshareHasEnded(); + + Tracker.autorun((c) => { + const selector = { + meetingId: breakoutId, + }; + + const query = Users.find(selector, { + fields: { + loggedOut: 1, + extId: 1, + }, + }); + + const observeLogOut = (user) => { + if (user?.loggedOut && user?.extId?.startsWith(Auth.userID)) { + rejoinAudio(); + c.stop(); + } + } + + query.observe({ + added: observeLogOut, + changed: observeLogOut, + }); + }); }} disabled={disable} /> diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/container.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/container.jsx index a1dfd2cd9f..55e63ec158 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/container.jsx @@ -7,6 +7,11 @@ import Service from './service'; import { layoutDispatch } from '../layout/context'; import Auth from '/imports/ui/services/auth'; import { UsersContext } from '/imports/ui/components/components-data/users-context/context'; +import { + didUserSelectedMicrophone, + didUserSelectedListenOnly, +} from '/imports/ui/components/audio/audio-modal/service'; +import { makeCall } from '/imports/ui/services/api'; const BreakoutContainer = (props) => { const layoutContextDispatch = layoutDispatch(); @@ -45,6 +50,30 @@ export default withTracker((props) => { getBreakoutAudioTransferStatus, } = AudioService; + const logUserCouldNotRejoinAudio = () => { + logger.warn({ + logCode: 'mainroom_audio_rejoin', + extraInfo: { logType: 'user_action' }, + }, 'leaving breakout room couldn\'t rejoin audio in the main room'); + }; + + const rejoinAudio = () => { + if (didUserSelectedMicrophone()) { + AudioManager.joinMicrophone().then(() => { + makeCall('toggleVoice', null, true).catch(() => { + AudioManager.forceExitAudio(); + logUserCouldNotRejoinAudio(); + }); + }).catch(() => { + logUserCouldNotRejoinAudio(); + }); + } else if (didUserSelectedListenOnly()) { + AudioManager.joinListenOnly().catch(() => { + logUserCouldNotRejoinAudio(); + }); + } + }; + return { ...props, breakoutRooms, @@ -61,7 +90,8 @@ export default withTracker((props) => { amIModerator: amIModerator(), isMeteorConnected, isUserInBreakoutRoom, - exitAudio: () => AudioManager.exitAudio(), + forceExitAudio: () => AudioManager.forceExitAudio(), + rejoinAudio, isReconnecting, setBreakoutAudioTransferStatus, getBreakoutAudioTransferStatus, diff --git a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx index e64baa02ea..006c6aea2b 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx @@ -68,8 +68,6 @@ const ChatAlert = (props) => { unreadMessagesByChat, intl, layoutContextDispatch, - chatsTracker, - notify, } = props; const [unreadMessagesCount, setUnreadMessagesCount] = useState(0); @@ -105,35 +103,6 @@ const ChatAlert = (props) => { } }, [pushAlertEnabled]); - useEffect(() => { - const keys = Object.keys(chatsTracker); - keys.forEach((key) => { - if (chatsTracker[key]?.shouldNotify) { - if (audioAlertEnabled) { - AudioService.playAlertSound(`${Meteor.settings.public.app.cdn - + Meteor.settings.public.app.basename - + Meteor.settings.public.app.instanceId}` - + '/resources/sounds/notify.mp3'); - } - if (pushAlertEnabled) { - notify( - key === 'MAIN-PUBLIC-GROUP-CHAT' - ? intl.formatMessage(intlMessages.publicChatMsg) - : intl.formatMessage(intlMessages.privateChatMsg), - 'info', - 'chat', - { autoClose: 3000 }, -
-
{chatsTracker[key].lastSender}
-
-
, - true, - ); - } - } - }); - }, [chatsTracker]); - useEffect(() => { if (pushAlertEnabled) { const alertsObject = unreadMessagesByChat; diff --git a/bigbluebutton-html5/imports/ui/components/chat/alert/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/alert/container.jsx index d7f832ab63..3420d560bb 100755 --- a/bigbluebutton-html5/imports/ui/components/chat/alert/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/alert/container.jsx @@ -1,7 +1,5 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import logger from '/imports/startup/client/logger'; -import Auth from '/imports/ui/services/auth'; import ChatAlert from './component'; import { layoutSelect, layoutSelectInput, layoutDispatch } from '../../layout/context'; import { PANELS } from '../../layout/enums'; @@ -18,15 +16,6 @@ const propTypes = { pushAlertEnabled: PropTypes.bool.isRequired, }; -// custom hook for getting previous value -function usePrevious(value) { - const ref = React.useRef(); - React.useEffect(() => { - ref.current = value; - }); - return ref.current; -} - const ChatAlertContainer = (props) => { const idChatOpen = layoutSelect((i) => i.idChatOpen); const sidebarContent = layoutSelectInput((i) => i.sidebarContent); @@ -65,47 +54,9 @@ const ChatAlertContainer = (props) => { }) : null; - const chatsTracker = {}; - - if (usingChatContext.chats) { - const chatsActive = Object.entries(usingChatContext.chats); - chatsActive.forEach((c) => { - try { - if (c[0] === idChat || (c[0] === 'MAIN-PUBLIC-GROUP-CHAT' && idChat === 'public')) { - chatsTracker[c[0]] = {}; - if (c[1]?.posJoinMessages || c[1]?.messageGroups) { - const m = Object.entries(c[1]?.posJoinMessages || c[1]?.messageGroups); - const sameUserCount = m.filter((message) => message[1]?.sender === Auth.userID).length; - if (m[m.length - 1] && m[m.length - 1][1]?.sender !== Auth.userID) { - chatsTracker[c[0]].lastSender = users[Auth.meetingID][c[1]?.lastSender]?.name; - chatsTracker[c[0]].content = m[m.length - 1][1]?.message; - chatsTracker[c[0]].count = m?.length - sameUserCount; - } - } - } - } catch (e) { - logger.error({ - logCode: 'chat_alert_component_error', - }, 'Error : ', e.error); - } - }); - - const prevTracker = usePrevious(chatsTracker); - - if (prevTracker) { - const keys = Object.keys(prevTracker); - keys.forEach((key) => { - if (chatsTracker[key]?.count > (prevTracker[key]?.count || 0)) { - chatsTracker[key].shouldNotify = true; - } - }); - } - } - return ( + this.itemRef = element} + > - {this.renderMessageItem()} - - ); + return this.renderMessageItem(); } } diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js index 103cf2e434..ff7f57e57f 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js @@ -101,6 +101,7 @@ const Meta = styled.div` flex: 1; flex-flow: row; line-height: 1.35; + align-items: baseline; `; const Name = styled.div` diff --git a/bigbluebutton-html5/imports/ui/components/common/menu/component.jsx b/bigbluebutton-html5/imports/ui/components/common/menu/component.jsx index efead5722e..93b1b51ded 100644 --- a/bigbluebutton-html5/imports/ui/components/common/menu/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/common/menu/component.jsx @@ -33,6 +33,15 @@ class BBBMenu extends React.Component { this.handleClose = this.handleClose.bind(this); } + componentDidUpdate() { + const { anchorEl } = this.state; + if (this.props.open === false && anchorEl) { + this.setState({ anchorEl: null }); + } else if (this.props.open === true && !anchorEl) { + this.setState({ anchorEl: this.anchorElRef }); + } + } + handleClick(event) { this.setState({ anchorEl: event.currentTarget }); }; @@ -129,6 +138,7 @@ class BBBMenu extends React.Component { this.handleClick(e); }} accessKey={this.props?.accessKey} + ref={(ref) => this.anchorElRef = ref} > {trigger}
diff --git a/bigbluebutton-html5/imports/ui/components/common/modal/confirmation/component.jsx b/bigbluebutton-html5/imports/ui/components/common/modal/confirmation/component.jsx index d5d995cafc..a5c54c4257 100644 --- a/bigbluebutton-html5/imports/ui/components/common/modal/confirmation/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/common/modal/confirmation/component.jsx @@ -71,7 +71,9 @@ class ConfirmationModal extends Component { - + + {description} + { hasCheckbox ? (
) : null} - {noRating && allowRedirectToLogoutURL() ? ( + {noRating ? ( this.setState({ dispatched: true })} label={intl.formatMessage(intlMessage.buttonOkay)} description={intl.formatMessage(intlMessage.confirmDesc)} /> ) : null} - - {!noRating && !dispatched ? ( + {!noRating ? ( ( - - -
- - -); +}) => { + const contentSplit = content.split(''); + const contentStyle = ` + + + `; + const contentWithStyle = [contentSplit[0], contentStyle, contentSplit[1]].join(''); + return ( + + + + ); +}; export default PadContent; diff --git a/bigbluebutton-html5/imports/ui/components/pads/content/styles.js b/bigbluebutton-html5/imports/ui/components/pads/content/styles.js index ed3e44ff76..15d604e381 100644 --- a/bigbluebutton-html5/imports/ui/components/pads/content/styles.js +++ b/bigbluebutton-html5/imports/ui/components/pads/content/styles.js @@ -1,7 +1,6 @@ import styled from 'styled-components'; import { colorGray, - colorGrayLightest, } from '/imports/ui/stylesheets/styled-components/palette'; const Wrapper = styled.div` @@ -11,36 +10,42 @@ const Wrapper = styled.div` width: 100%; `; -const Content = styled.div` - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 1.15rem; - color: ${colorGray}; - border-top: 1px solid ${colorGrayLightest}; - border-bottom: 1px solid ${colorGrayLightest}; - bottom: 0; - box-sizing: border-box; - display: flex; - overflow-x: hidden; - overflow-wrap: break-word; - overflow-y: auto; - padding-top: 1rem; - position: absolute; +const contentText = ` +font-family: Verdana, Arial, Helvetica, sans-serif; +font-size: 15px; +color: ${colorGray}; +bottom: 0; +box-sizing: border-box; +display: flex; +flex-direction: column; +overflow-x: hidden; +overflow-wrap: break-word; +word-break: break-all; +overflow-y: auto; +padding-top: 1rem; +position: absolute; +width: 100%; +top: 0; + + +[dir="ltr"] & { + padding-left: 1rem; + padding-right: .5rem; +} + +[dir="rtl"] & { + padding-left: .5rem; + padding-right: 1rem; +} +`; + +const Iframe = styled.iframe` + border-width: 0; width: 100%; - top: 0; - white-space: pre-wrap; - - [dir="ltr"] & { - padding-left: 1rem; - padding-right: .5rem; - } - - [dir="rtl"] & { - padding-left: .5rem; - padding-right: 1rem; - } `; export default { Wrapper, - Content, + Iframe, + contentText, }; diff --git a/bigbluebutton-html5/imports/ui/components/pads/service.js b/bigbluebutton-html5/imports/ui/components/pads/service.js index a552d829e9..56b0dc3679 100644 --- a/bigbluebutton-html5/imports/ui/components/pads/service.js +++ b/bigbluebutton-html5/imports/ui/components/pads/service.js @@ -1,9 +1,11 @@ +import _ from 'lodash'; import Pads, { PadsUpdates } from '/imports/api/pads'; import { makeCall } from '/imports/ui/services/api'; import Auth from '/imports/ui/services/auth'; import Settings from '/imports/ui/services/settings'; const PADS_CONFIG = Meteor.settings.public.pads; +const THROTTLE_TIMEOUT = 2000; const getLang = () => { const { locale } = Settings.application; @@ -38,6 +40,11 @@ const hasPad = (externalId) => { const createSession = (externalId) => makeCall('createSession', externalId); +const throttledCreateSession = _.throttle(createSession, THROTTLE_TIMEOUT, { + leading: true, + trailing: false, +}); + const buildPadURL = (padId) => { if (padId) { const params = getParams(); @@ -89,7 +96,7 @@ export default { getPadId, createGroup, hasPad, - createSession, + createSession: (externalId) => throttledCreateSession(externalId), buildPadURL, getRev, getPadTail, diff --git a/bigbluebutton-html5/imports/ui/components/poll/component.jsx b/bigbluebutton-html5/imports/ui/components/poll/component.jsx index c206dd35cd..308a1fa3c4 100644 --- a/bigbluebutton-html5/imports/ui/components/poll/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/poll/component.jsx @@ -353,9 +353,11 @@ class Poll extends Component { diff -= 1; } } else { + let index = optList.length-1; while (diff < 0) { - this.handleRemoveOption(); + this.handleRemoveOption(index); diff += 1; + index -=1; } } } diff --git a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx index 060b2a0338..cf70d130b6 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/component.jsx @@ -158,6 +158,8 @@ class Presentation extends PureComponent { intl, } = this.props; + const { presentationWidth, presentationHeight } = this.state; + const { numCameras: prevNumCameras, presentationBounds: prevPresentationBounds, @@ -235,7 +237,22 @@ class Presentation extends PureComponent { } } - if (presentationBounds !== prevPresentationBounds) this.onResize(); + if ((presentationBounds !== prevPresentationBounds) || + (!presentationWidth && !presentationHeight)) this.onResize(); + } else if (slidePosition) { + const { width: currWidth, height: currHeight } = slidePosition; + + layoutContextDispatch({ + type: ACTIONS.SET_PRESENTATION_CURRENT_SLIDE_SIZE, + value: { + width: currWidth, + height: currHeight, + }, + }); + layoutContextDispatch({ + type: ACTIONS.SET_PRESENTATION_NUM_CURRENT_SLIDE, + value: currentSlide.num, + }); } } @@ -734,7 +751,7 @@ class Presentation extends PureComponent { return ( { currentElement, currentGroup, fullscreenRef, - screenshotRef, + getScreenshotRef, handleToggleFullscreen, layoutContextDispatch, meetingName, @@ -199,7 +199,7 @@ const PresentationMenu = (props) => { }, }); - toPng(screenshotRef, { + toPng(getScreenshotRef(), { width: window.screen.width, height: window.screen.height, }).then((data) => { diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx index df0e99ed36..037aed3013 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx @@ -301,14 +301,23 @@ class PresentationUploader extends Component { } }); - if (!_.isEqual(prevProps.presentations, propPresentations) || presentations.length === 0) { - this.setState({ - presentations: Object.values({ - ...presentations, - ...propPresentations, - }), - }); - } + const presState = Object.values({ + ...propPresentations, + ...presentations, + }); + const presStateMapped = presState.map((presentation) => { + propPresentations.forEach((propPres) => { + if (propPres.id == presentation.id){ + presentation.isCurrent = propPres.isCurrent; + } + }) + return presentation; + }) + + this.setState({ + presentations: presStateMapped, + }) + } if (presentations.length > 0) { @@ -554,8 +563,8 @@ class PresentationUploader extends Component { const { presentations: propPresentations } = this.props; const ids = new Set(propPresentations.map((d) => d.ID)); const merged = [ - ...propPresentations, ...presentations.filter((d) => !ids.has(d.ID)), + ...propPresentations, ]; this.setState( { presentations: merged }, @@ -857,7 +866,6 @@ class PresentationUploader extends Component { keyValue={item.id} onChange={() => this.handleCurrentChange(item.id)} disabled={disableActions} - animations={animations} /> {isRemovable ? ( @@ -1039,7 +1047,7 @@ class PresentationUploader extends Component { let hasNewUpload = false; - presentations.map((item) => { + presentations.forEach((item) => { if (item.id.indexOf(item.filename) !== -1 && item.upload.progress === 0) hasNewUpload = true; }); diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js index df7b6c57eb..a5d8a73f92 100644 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js @@ -5,6 +5,7 @@ import Poll from '/imports/api/polls/'; import { makeCall } from '/imports/ui/services/api'; import logger from '/imports/startup/client/logger'; import _ from 'lodash'; +import { Random } from 'meteor/random' const CONVERSION_TIMEOUT = 300000; const TOKEN_TIMEOUT = 5000; @@ -67,7 +68,7 @@ const dispatchTogglePresentationDownloadable = (presentation, newState) => { const observePresentationConversion = ( meetingId, - filename, + tmpPresId, onConversion, ) => new Promise((resolve) => { const conversionTimeout = setTimeout(() => { @@ -88,7 +89,7 @@ const observePresentationConversion = ( query.observe({ added: (doc) => { - if (doc.name !== filename) return; + if (doc.temporaryPresentationId !== tmpPresId) return; if (doc.conversion.status === 'FILE_TOO_LARGE' || doc.conversion.status === 'UNSUPPORTED_DOCUMENT') { onConversion(doc.conversion); @@ -97,7 +98,7 @@ const observePresentationConversion = ( } }, changed: (newDoc) => { - if (newDoc.name !== filename) return; + if (newDoc.temporaryPresentationId !== tmpPresId) return; onConversion(newDoc.conversion); @@ -116,11 +117,12 @@ const observePresentationConversion = ( }); const requestPresentationUploadToken = ( + tmpPresId, podId, meetingId, filename, ) => new Promise((resolve, reject) => { - makeCall('requestPresentationUploadToken', podId, filename); + makeCall('requestPresentationUploadToken', podId, filename, tmpPresId); let computation = null; const timeout = setTimeout(() => { @@ -130,13 +132,13 @@ const requestPresentationUploadToken = ( Tracker.autorun((c) => { computation = c; - const sub = Meteor.subscribe('presentation-upload-token', podId, filename); + const sub = Meteor.subscribe('presentation-upload-token', podId, filename, tmpPresId); if (!sub.ready()) return; const PresentationToken = PresentationUploadToken.findOne({ podId, meetingId, - filename, + tmpPresId, used: false, }); @@ -163,12 +165,13 @@ const uploadAndConvertPresentation = ( onProgress, onConversion, ) => { + const tmpPresId = _.uniqueId(Random.id(20)) + const data = new FormData(); - data.append('presentation_name', file.name); - data.append('Filename', file.name); data.append('fileUpload', file); data.append('conference', meetingId); data.append('room', meetingId); + data.append('temporaryPresentationId', tmpPresId); // TODO: Currently the uploader is not related to a POD so the id is fixed to the default data.append('pod_id', podId); @@ -180,12 +183,12 @@ const uploadAndConvertPresentation = ( body: data, }; - return requestPresentationUploadToken(podId, meetingId, file.name) + return requestPresentationUploadToken(tmpPresId, podId, meetingId, file.name) .then((token) => { makeCall('setUsedToken', token); return futch(endpoint.replace('upload', `${token}/upload`), opts, onProgress); }) - .then(() => observePresentationConversion(meetingId, file.name, onConversion)) + .then(() => observePresentationConversion(meetingId, tmpPresId, onConversion)) // Trap the error so we can have parallel upload .catch((error) => { logger.debug({ @@ -194,7 +197,7 @@ const uploadAndConvertPresentation = ( error, }, }, 'Generic presentation upload exception catcher'); - observePresentationConversion(meetingId, file.name, onConversion); + observePresentationConversion(meetingId, tmpPresId, onConversion); onUpload({ error: true, done: true, status: error.code }); return Promise.resolve(); }); diff --git a/bigbluebutton-html5/imports/ui/components/reload-button/styles.js b/bigbluebutton-html5/imports/ui/components/reload-button/styles.js index ba23b2b939..882731a78b 100644 --- a/bigbluebutton-html5/imports/ui/components/reload-button/styles.js +++ b/bigbluebutton-html5/imports/ui/components/reload-button/styles.js @@ -3,21 +3,11 @@ import { colorTransparent } from '/imports/ui/stylesheets/styled-components/pale import Button from '/imports/ui/components/common/button/component'; const Wrapper = styled.div` - position: absolute; - right: auto; - left: 0; background-color: ${colorTransparent}; cursor: pointer; border: 0; z-index: 2; margin: 2px; - bottom: 0; - top: 0; - - [dir="rtl"] & { - right: 0; - left : auto; - } `; const ReloadButton = styled(Button)` diff --git a/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx b/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx index 63e7397a93..9cdb9c5299 100644 --- a/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx @@ -98,6 +98,22 @@ const intlMessages = defineMessages({ id: 'app.shortcut-help.previousSlideDesc', description: 'describes the previous slide shortcut', }, + togglePanKey: { + id: 'app.shortcut-help.togglePanKey', + description: 'describes the toggle pan shortcut key', + }, + toggleFullscreenKey: { + id: 'app.shortcut-help.toggleFullscreenKey', + description: 'describes the toggle full-screen shortcut key', + }, + nextSlideKey: { + id: 'app.shortcut-help.nextSlideKey', + description: 'describes the next slide shortcut key', + }, + previousSlideKey: { + id: 'app.shortcut-help.previousSlideKey', + description: 'describes the previous slide shortcut key', + }, }); const ShortcutHelpComponent = (props) => { @@ -143,28 +159,28 @@ const ShortcutHelpComponent = (props) => { shortcutItems.push((