Merge remote-tracking branch 'origin/master' into bug2822_boatcolors_merged_with_eol_changes

# Conflicts:
#	java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java
This commit is contained in:
Frank Mittag committed 2018-02-07 13:38:32 +01:00
commit 98abbf7cb4
34 files changed
+1200 -254

No files matched your search

@@ -81,6 +81,7 @@ Tack=Amura
SpeedBefore=Velocidad antes de maniobra
SpeedAfter=Velocidad después de maniobra
DirectionChange=Cambio de dirección en grados
DirectionChangeWithinMainCurve=Cambio de dirección con curva principal en grados
AbsoluteDirectionChange=Cambio absoluto de dirección en grados (positivo)
ToSide=Al lado (babor / estribor)
ManeuverLoss=Pérdida en maniobra
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=Promedio del ángulo absoluto de viento real
AbsoluteTrueWindAngle=Ángulo absoluto del viento real (TWA)
Wind=Viento
VMG=Velocity Made Good
MaxAngularVelocityInDegreesPerSecond=Velocidad máxima angular en grados
ManeuverEnteringAbsTWA=TWA absoluto antes de maniobra
ManeuverExitingAbsTWA=TWA absoluto tras maniobra
ManeuverSpeedDetailsRetrieverChain=Detalles de velocidad de maniobra
ManeuverSpeedDetails=Detalles de velocidad
SpeedSlope=Inclinación velocidad
ManeuverDirection=Dirección de maniobra
RatioToEnteringSpeed=Ratio por velocidad de entrada en maniobra
RatioToPreviousTWASpeed=Ratio por velocidad de TWA previo en maniobra
LowestRatioToEnteringSpeed=Ratio más baja por velocidad de entrada en maniobra
HighestRatioToEnteringSpeed=Ratio más alta por velocidad de entrada en maniobra
HighestRatioToEnteringSpeedMinusLowest=Ratio más alta por velocidad de entrada menos más baja en maniobra
EnteringManeuverSpeedMinusExitingSpeed=Velocidad de maniobra de entrada menos velocidad de salida
RatioBetweenManeuverEnteringAndExitingSpeed=Ratio entre velocidad de entrada y salida de maniobra
AvgTrendForTWAs=Promedio por TWA
MedianTrendForTWAs=Media por TWA
ManeuverDurationInSeconds=Duración de maniobra en segundos
AbsTWAAtManeuverClimax=TWA absoluto en clímax de maniobra
ManeuverEnteringSpeedInKnots=Velocidad de entrada de maniobra (kts)
ManeuverExitingSpeedInKnots=Velocidad de salida de maniobra (kts)
TackBeforeManeuver=Bordo antes de maniobra
ManeuverBoundariesRetrieverChain=Límites de maniobra
ManeuverBoundaries=Límites de maniobra
ManeuverStartSpeedDeviationRatioFromAvg=Ratio de desviación de velocidad de inicio de maniobra con velocidad media antes de maniobra
ManeuverStartCogDeviationFromAvgInDegrees=Desviación COG de inicio de maniobra con COG medio antes de maniobra en grados
ManeuverEndSpeedDeviationRatioFromAvg=Ratio de desviación de velocidad de fin de maniobra con velocidad media tras maniobra
ManeuverEndCogDeviationFromAvgInDegrees=Desviación COG de fin de maniobra con COG medio tras maniobra en grados
DurationToNextManeuverInSeconds=Duración de fin de maniobra actual hasta siguiente inicio de maniobra en segundos
DurationFromPreviousManeuverInSeconds=Duración de fin de maniobra anterior hasta siguiente inicio de maniobra actual en segundos
NextManeuverAtLeastOneSecondInFront=Siguiente inicio de maniobra es al menos un segundo después de fin de maniobra actual
PreviousManeuverAtLeastOneSecondBehind=Anterior fin de maniobra es al menos un segundo antes de inicio de maniobra actual
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=Duración entre velocidad estable con rumbo e inicio de curva principal en segundos
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=Ratio de velocidad entre velocidad estable con rumbo e inicio de curva principal
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=Diferencia de rumbo absoluto entre velocidad estable con rumbo e inicio de curva principal en grados
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Duración entre velocidad estable con rumbo y fin de curva principal en segundos
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Ratio de velocidad entre velocidad estable con rumbo y fin de curva principal
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Diferencia de rumbo absoluto entre velocidad estable con rumbo y fin de curva principal en grados
AbsTwaAtLowestRatioToEnteringSpeed=TWA absoluto en ratio más baja para velocidad de entrada
AbsTwaAtHighestRatioToEnteringSpeed=TWA absoluto en ratio más alta para velocidad de entrada
@@ -81,6 +81,7 @@ Tack=Virement
SpeedBefore=Vitesse avant la manœuvre
SpeedAfter=Vitesse après la manœuvre
DirectionChange=Changement de cap en degrés
DirectionChangeWithinMainCurve=Changement de cap sur la courbe principale en degrés
AbsoluteDirectionChange=Changement de cap absolu en degrés (positif)
ToSide=À bâbord/À tribord
ManeuverLoss=Perte suite à manœuvre
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=Angle du vent réel moyen
AbsoluteTrueWindAngle=Angle du vent réel (TWA)
Wind=Vent
VMG=Compromis Cap/Vitesse (VMG)
MaxAngularVelocityInDegreesPerSecond=Vitesse angulaire maximale en degrés/seconde
ManeuverEnteringAbsTWA=TWA absolu avant manœuvre
ManeuverExitingAbsTWA=TWA absolu après manœuvre
ManeuverSpeedDetailsRetrieverChain=Détails sur la vitesse lors de la manœuvre
ManeuverSpeedDetails=Détails sur la vitesse
SpeedSlope=Inclinaison en fonction de la vitesse
ManeuverDirection=Cap pendant la manœuvre
RatioToEnteringSpeed=Ratio de vitesse d''entrée lors de la manœuvre
RatioToPreviousTWASpeed=Ratio par rapport à la vitesse du précédent TWA lors de la manœuvre
LowestRatioToEnteringSpeed=Ratio le plus bas par rapport à la vitesse d''entrée lors de la manœuvre
HighestRatioToEnteringSpeed=Ratio le plus élevé par rapport à la vitesse d''entrée lors de la manœuvre
HighestRatioToEnteringSpeedMinusLowest=Ratio le plus élevé par rapport à la vitesse d''entrée moins ratio le plus bas
EnteringManeuverSpeedMinusExitingSpeed=Vitesse d''entrée de manœuvre moins vitesse de sortie
RatioBetweenManeuverEnteringAndExitingSpeed=Ratio de variation entre la vitesse d''entrée et de sortie de manœuvre
AvgTrendForTWAs=Moyenne par TWA
MedianTrendForTWAs=Médiane par TWA
ManeuverDurationInSeconds=Durée de la manœuvre en secondes
AbsTWAAtManeuverClimax=TWA absolu lors du point culminant de la manœuvre
ManeuverEnteringSpeedInKnots=Vitesse d''entrée de manœuvre (nds)
ManeuverExitingSpeedInKnots=Vitesse de sortie de manœuvre (nds)
TackBeforeManeuver=Virement avant manœuvre
ManeuverBoundariesRetrieverChain=Limites de manœuvre
ManeuverBoundaries=Limites de manœuvre
ManeuverStartSpeedDeviationRatioFromAvg=Ratio de variation de vitesse entre le début de la manœuvre et la vitesse moyenne avant manœuvre
ManeuverStartCogDeviationFromAvgInDegrees=Écart de route fond au début de la manœuvre avec route fond moyenne avant manœuvre en degrés
ManeuverEndSpeedDeviationRatioFromAvg=Ratio d''écart de vitesse à la fin de la manœuvre avec vitesse moyenne après manœuvre
ManeuverEndCogDeviationFromAvgInDegrees=Écart de route fond à la fin de la manœuvre avec route fond moyenne après manœuvre en degrés
DurationToNextManeuverInSeconds=Durée entre la fin de la manœuvre actuelle et le début de la prochaine manœuvre (en secondes)
DurationFromPreviousManeuverInSeconds=Durée entre la fin de la manœuvre précédente et le début de la manœuvre actuelle (en secondes)
NextManeuverAtLeastOneSecondInFront=La prochaine manœuvre débute au moins une seconde après la fin de la manœuvre actuelle
PreviousManeuverAtLeastOneSecondBehind=La manœuvre précédente se termine au moins une seconde avant le début de la manœuvre actuelle
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=Durée entre vitesse stable de la course et début de la courbe principale en secondes
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=Ratio de variation de vitesse entre vitesse stable de la course et début de la courbe principale
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=Écart de course absolu entre vitesse stable de la course et début de la courbe principale en degrés
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Durée entre vitesse stable de la course et fin de la courbe principale en secondes
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Ratio de variation de vitesse entre vitesse stable de la course et fin de la courbe principale
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Écart de course absolu entre vitesse stable de la course et fin de la courbe principale en degrés
AbsTwaAtLowestRatioToEnteringSpeed=TWA absolu au ratio le plus bas par rapport à la vitesse d''entrée
AbsTwaAtHighestRatioToEnteringSpeed=TWA absolu au ratio le plus élevé par rapport à la vitesse d''entrée
@@ -81,6 +81,7 @@ Tack=タック
SpeedBefore=マニューバー前の艇速
SpeedAfter=マニューバー後の艇速
DirectionChange=方向転換 (度)
DirectionChangeWithinMainCurve=主曲線内の方向転換 (度)
AbsoluteDirectionChange=方向転換 (度) の絶対値
ToSide=方向転換する側 (ポート/スターボード)
ManeuverLoss=マニューバーロス
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=平均絶対真風角度
AbsoluteTrueWindAngle=絶対真風角度 (TWA)
Wind=風
VMG=VMG (有効速度)
MaxAngularVelocityInDegreesPerSecond=最大角速度 (deg/s)
ManeuverEnteringAbsTWA=マニューバー前の絶対 TWA
ManeuverExitingAbsTWA=マニューバー後の絶対 TWA
ManeuverSpeedDetailsRetrieverChain=マニューバー速度詳細
ManeuverSpeedDetails=速度詳細
SpeedSlope=速度勾配
ManeuverDirection=マニューバー方向
RatioToEnteringSpeed=マニューバー内の進入速度との比率
RatioToPreviousTWASpeed=マニューバー内の前 TWA の速度との比率
LowestRatioToEnteringSpeed=マニューバー内の進入速度との最低比率
HighestRatioToEnteringSpeed=マニューバー内の進入速度との最高比率
HighestRatioToEnteringSpeedMinusLowest=マニューバー内の進入速度から最低速度を引いたものとの最高比率
EnteringManeuverSpeedMinusExitingSpeed=マニューバーの進入速度から脱出速度を引いたもの
RatioBetweenManeuverEnteringAndExitingSpeed=マニューバーの進入速度と脱出速度の比率
AvgTrendForTWAs=TWA 別の平均値
MedianTrendForTWAs=TWA 別の中央値
ManeuverDurationInSeconds=マニューバー持続時間 (秒)
AbsTWAAtManeuverClimax=マニューバー頂点の絶対 TWA
ManeuverEnteringSpeedInKnots=マニューバー進入速度 (kts)
ManeuverExitingSpeedInKnots=マニューバー脱出速度 (kts)
TackBeforeManeuver=マニューバー前のタック
ManeuverBoundariesRetrieverChain=マニューバー境界
ManeuverBoundaries=マニューバー境界
ManeuverStartSpeedDeviationRatioFromAvg=マニューバー前平均速度と比較したマニューバー開始時の速度差異比
ManeuverStartCogDeviationFromAvgInDegrees=マニューバー前平均 COG と比較したマニューバー開始時の COG 差異 (度)
ManeuverEndSpeedDeviationRatioFromAvg=マニューバー後平均速度と比較したマニューバー終了時の速度差異比
ManeuverEndCogDeviationFromAvgInDegrees=マニューバー後平均 COG と比較したマニューバー終了時の COG 差異 (度)
DurationToNextManeuverInSeconds=現マニューバー終了から次マニューバー開始までの時間 (秒)
DurationFromPreviousManeuverInSeconds=前マニューバー終了から現マニューバー開始までの時間 (秒)
NextManeuverAtLeastOneSecondInFront=次マニューバー開始は現マニューバー終了の少なくとも 1 秒後
PreviousManeuverAtLeastOneSecondBehind=前マニューバー終了は現マニューバー開始の少なくとも 1 秒前
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=コース安定速度と主曲線始点の間の時間 (秒)
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=コース安定速度と主曲線始点の速度比
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=コース安定速度と主曲線始点の絶対コース差異 (度)
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=コース安定速度と主曲線終点の間の時間 (秒)
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=コース安定速度と主曲線終点の速度比
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=コース安定速度と主曲線終点の絶対コース差異 (度)
AbsTwaAtLowestRatioToEnteringSpeed=進入速度との最低比率での絶対 TWA
AbsTwaAtHighestRatioToEnteringSpeed=進入速度との最高比率での絶対 TWA
@@ -81,6 +81,7 @@ Tack=Cambar
SpeedBefore=Velocidade antes de manobra
SpeedAfter=Velocidade depois de manobra
DirectionChange=Mudança de direção em graus
DirectionChangeWithinMainCurve=Mudança de direção na curva principal em graus
AbsoluteDirectionChange=Mudança absoluta de direção em graus (positiva)
ToSide=Até lado (bombordo/boreste)
ManeuverLoss=Perda de manobra
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=Ângulo de vento verdadeiro absoluto médio
AbsoluteTrueWindAngle=Ângulo de vento verdadeiro absoluto (TWA)
Wind=Vento
VMG=Velocidade diretamente na linha do vento real (VMG)
MaxAngularVelocityInDegreesPerSecond=Velocidade angular máxima em graus/s
ManeuverEnteringAbsTWA=TWA absoluto antes da manobra
ManeuverExitingAbsTWA=TWA absoluto após a manobra
ManeuverSpeedDetailsRetrieverChain=Detalhes da velocidade da manobra
ManeuverSpeedDetails=Detalhes da velocidade
SpeedSlope=Inclinação de velocidade
ManeuverDirection=Direção da manobra
RatioToEnteringSpeed=Proporção em relação à velocidade de entrada na manobra
RatioToPreviousTWASpeed=Proporção em relação à velocidade do TWA anterior na manobra
LowestRatioToEnteringSpeed=Proporção mínima em relação à velocidade de entrada na manobra
HighestRatioToEnteringSpeed=Proporção máxima em relação à velocidade de entrada na manobra
HighestRatioToEnteringSpeedMinusLowest=Proporção máxima em relação à velocidade de entrada menos a mínima na manobra
EnteringManeuverSpeedMinusExitingSpeed=Velocidade de entrada da manobra menos velocidade de saída
RatioBetweenManeuverEnteringAndExitingSpeed=Proporção entre velocidade de entrada e saída da manobra
AvgTrendForTWAs=Média por TWA
MedianTrendForTWAs=Mediana por TWA
ManeuverDurationInSeconds=Duração da manobra em segundos
AbsTWAAtManeuverClimax=TWA absoluto no ponto culminante da manobra
ManeuverEnteringSpeedInKnots=Velocidade de entrada da manobra (nós)
ManeuverExitingSpeedInKnots=Velocidade de saída da manobra (nós)
TackBeforeManeuver=Cambada antes da manobra
ManeuverBoundariesRetrieverChain=Limites da manobra
ManeuverBoundaries=Limites da manobra
ManeuverStartSpeedDeviationRatioFromAvg=Proporção de desvio de velocidade de início da manobra com velocidade média antes da manobra
ManeuverStartCogDeviationFromAvgInDegrees=Desvio de percurso no fundo de início da manobra com percurso médio no fundo antes da manobra em graus
ManeuverEndSpeedDeviationRatioFromAvg=Proporção de desvio de velocidade de fim da manobra com velocidade média após a manobra
ManeuverEndCogDeviationFromAvgInDegrees=Desvio de percurso no fundo de fim da manobra com percurso médio no fundo após a manobra em graus
DurationToNextManeuverInSeconds=Duração desde o fim da manobra atual até o início da próxima manobra em segundos
DurationFromPreviousManeuverInSeconds=Duração desde o fim da manobra anterior até o início da manobra atual em segundos
NextManeuverAtLeastOneSecondInFront=O início da manobra seguinte é pelo menos um segundo após o fim da manobra atual
PreviousManeuverAtLeastOneSecondBehind=O fim da manobra anterior é pelo menos um segundo antes do início da manobra atual
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=Duração entre velocidade estável com percurso e início da curva principal em segundos
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=Proporção de velocidade entre velocidade estável com percurso e início da curva principal
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=Diferença de percurso absoluto entre velocidade estável com percurso e início da curva principal em graus
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Duração entre velocidade estável com percurso e fim da curva principal em segundos
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Proporção de velocidade entre velocidade estável com percurso e fim da curva principal
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Diferença de percurso absoluto entre velocidade estável com percurso e fim da curva principal em graus
AbsTwaAtLowestRatioToEnteringSpeed=TWA absoluto na proporção mínima em relação a velocidade de entrada
AbsTwaAtHighestRatioToEnteringSpeed=TWA absoluto na proporção máxima em relação a velocidade de entrada
@@ -81,6 +81,7 @@ Tack=Оверштаг
SpeedBefore=Скорость до маневра
SpeedAfter=Скорость после маневра
DirectionChange=Изменение направления в градусах
DirectionChangeWithinMainCurve=Изменение направления в пределах основной кривой в градусах
AbsoluteDirectionChange=Абсолютное изменение направления в градусах (положительное)
ToSide=Борт (левый/правый)
ManeuverLoss=Потеря маневра
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=Средний абсолютный угол ист
AbsoluteTrueWindAngle=Абсолютный угол истинного ветра (TWA)
Wind=Ветер
VMG=Эффективная скорость лавирования (VMG)
MaxAngularVelocityInDegreesPerSecond=Максимальная угловая скорость (град./с)
ManeuverEnteringAbsTWA=Абсолютный TWA до маневра
ManeuverExitingAbsTWA=Абсолютный TWA после маневра
ManeuverSpeedDetailsRetrieverChain=Скорость маневра подробно
ManeuverSpeedDetails=Скорость подробно
SpeedSlope=Градиент скорости
ManeuverDirection=Направление маневра
RatioToEnteringSpeed=Отношение к входной скорости маневра
RatioToPreviousTWASpeed=Отношение к скорости предыдущего TWA в маневре
LowestRatioToEnteringSpeed=Наименьшее отношение к входной скорости маневра
HighestRatioToEnteringSpeed=Наибольшее отношение к входной скорости маневра
HighestRatioToEnteringSpeedMinusLowest=Разность наибольшего и наименьшего отношений к входной скорости маневра в маневре
EnteringManeuverSpeedMinusExitingSpeed=Разность входной и выходной скоростей маневра
RatioBetweenManeuverEnteringAndExitingSpeed=Отношение входной и выходной скоростей маневра
AvgTrendForTWAs=Среднее по TWA
MedianTrendForTWAs=Медиана по TWA
ManeuverDurationInSeconds=Длительность маневра в секундах
AbsTWAAtManeuverClimax=Абсолютный TWA в крайней точке маневра
ManeuverEnteringSpeedInKnots=Входная скорость маневра (уз.)
ManeuverExitingSpeedInKnots=Выходная скорость маневра (уз.)
TackBeforeManeuver=Галс до маневра
ManeuverBoundariesRetrieverChain=Границы маневра
ManeuverBoundaries=Границы маневра
ManeuverStartSpeedDeviationRatioFromAvg=Коэффициент отклонения скорости начала маневра со ср. скоростью до маневра
ManeuverStartCogDeviationFromAvgInDegrees=Отклонение COG начала маневра со ср. COG до маневра в градусах
ManeuverEndSpeedDeviationRatioFromAvg=Коэффициент отклонения скорости завершения маневра со ср. скоростью после маневра
ManeuverEndCogDeviationFromAvgInDegrees=Отклонение COG завершения маневра со ср. COG после маневра в градусах
DurationToNextManeuverInSeconds=Длительность от завершения текущего маневра до начала следующего маневра в секундах
DurationFromPreviousManeuverInSeconds=Длительность от завершения предыдущего маневра до начала текущего маневра в секундах
NextManeuverAtLeastOneSecondInFront=Начало следующего маневра не ранее одной секунды после завершения текущего маневра
PreviousManeuverAtLeastOneSecondBehind=Завершение предыдущего маневра не ранее одной секунды после начала текущего маневра
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=Длительность между стабильной скоростью с курсом и началом основной кривой в секундах
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=Соотношение скоростей между стабильной скоростью с курсом и основной кривой
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=Абс. разница курса между стабильной скоростью с курсом и началом основной кривой в градусах
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Длительность между стабильной скоростью с курсом и завершением основной кривой в секундах
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Соотношение скоростей между стабильной скоростью с курсом и завершением основной кривой
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Абс. разница курса между стабильной скоростью с курсом и завершением основной кривой в градусах
AbsTwaAtLowestRatioToEnteringSpeed=Абс. TWA при наименьшем отношении к входной скорости
AbsTwaAtHighestRatioToEnteringSpeed=Абс. TWA при наибольшем отношении к входной скорости
@@ -81,6 +81,7 @@ Tack=迎风转向
SpeedBefore=操作前的速度
SpeedAfter=操作后的速度
DirectionChange=风向变化角度
DirectionChangeWithinMainCurve=主曲线内的风向变化角度
AbsoluteDirectionChange=绝对风向变化角度(正向)
ToSide=至侧(左舷/右舷)
ManeuverLoss=操作损失
@@ -126,3 +127,42 @@ AverageAbsoluteTrueWindAngle=平均绝对实际风向角
AbsoluteTrueWindAngle=绝对实际风向角 (TWA)
Wind=风力
VMG=沿计划航线上的航速
MaxAngularVelocityInDegreesPerSecond=最大角速度 (deg/s)
ManeuverEnteringAbsTWA=操作前的绝对实际风向角
ManeuverExitingAbsTWA=操作后的绝对实际风向角
ManeuverSpeedDetailsRetrieverChain=操作速度详情
ManeuverSpeedDetails=速度详情
SpeedSlope=速度坡度
ManeuverDirection=操作方向
RatioToEnteringSpeed=操作内驶入速度的比率
RatioToPreviousTWASpeed=操作内先前实际风向角速度的比率
LowestRatioToEnteringSpeed=操作内驶入速度的最低比率
HighestRatioToEnteringSpeed=操作内驶入速度的最高比率
HighestRatioToEnteringSpeedMinusLowest=操作内驶入速度减去最低速度的最高比率
EnteringManeuverSpeedMinusExitingSpeed=驶入操作速度减去驶出速度
RatioBetweenManeuverEnteringAndExitingSpeed=操作驶入速度与驶出速度之间的比率
AvgTrendForTWAs=各实际风向角的平均值
MedianTrendForTWAs=各实际风向角的中值
ManeuverDurationInSeconds=操作持续时间(秒)
AbsTWAAtManeuverClimax=操作顶点的绝对实际风向角
ManeuverEnteringSpeedInKnots=操作驶入速度 (kts)
ManeuverExitingSpeedInKnots=操作驶出速度 (kts)
TackBeforeManeuver=操作前迎风转向
ManeuverBoundariesRetrieverChain=操作边界
ManeuverBoundaries=操作边界
ManeuverStartSpeedDeviationRatioFromAvg=操作前以平均速度开始操作的速度偏差率
ManeuverStartCogDeviationFromAvgInDegrees=操作前以平均对地航向开始操作的对地航向偏差角度
ManeuverEndSpeedDeviationRatioFromAvg=操作后以平均速度结束操作的速度偏差率
ManeuverEndCogDeviationFromAvgInDegrees=操作后以平均对地航向结束操作的对地航向偏差角度
DurationToNextManeuverInSeconds=自当前操作结束到下次操作开始的持续时间(秒)
DurationFromPreviousManeuverInSeconds=自先前操作结束到当前操作开始的持续时间(秒)
NextManeuverAtLeastOneSecondInFront=下次操作开始至少在当前操作结束后一秒
PreviousManeuverAtLeastOneSecondBehind=先前操作结束至少在当前操作开始前一秒
DurationBetweenStableSpeedWithCourseAndMainCurveBeginningInSeconds=场地内稳定速度与主曲线开始之间的持续时间(秒)
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveBeginning=场地内稳定速度与主曲线开始之间的速度比率
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveBeginningInDegrees=场地内稳定速度与主曲线开始之间的绝对场地差异角度
DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=场地内稳定速度与主曲线结束之间的持续时间(秒)
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=场地内稳定速度与主曲线结束之间的速度比率
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=场地内稳定速度与主曲线结束之间的绝对场地差异角度
AbsTwaAtLowestRatioToEnteringSpeed=最低比率下驶入速度的绝对实际风向角
AbsTwaAtHighestRatioToEnteringSpeed=最高比率下驶入速度的绝对实际风向角
@@ -60,6 +60,8 @@ import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerM
import com.sap.sailing.domain.racelogtracking.test.RaceLogTrackingTestHelper;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.Track;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
@@ -126,7 +128,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
Exception {
RaceColumn column = leaderboard.getRaceColumnByName(columnName);
exception.expect(NotDenotedForRaceLogTrackingException.class);
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
trackRace(column);
}
private void testSize(Track<?> track, int expected) {
@@ -198,7 +200,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1, boat1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
trackRace(column);
// now there is a tracked race
@@ -220,6 +222,23 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
raceLogFixTrackerManager.stop(/* preemptive */ false, /* willBeRemoved */ false);
addFixes3(race, comp1, dev1);
}
private void trackRace(RaceColumn column) throws NotDenotedForRaceLogTrackingException, Exception {
final RaceHandle raceHandle = adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// The following lines ensure that we received all necessary events from the TrackedRegatta
// When removing a listener we get a Future whose get method will block until all previously triggered events are processed.
final RaceListener raceListener = new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {
}
@Override
public void raceAdded(TrackedRace trackedRace) {
}
};
raceHandle.getTrackedRegatta().addRaceListener(raceListener);
raceHandle.getTrackedRegatta().removeRaceListener(raceListener).get();
}
/**
* See bug 4114: when the regatta is set to control the tracking times from start / finish times,
@@ -235,6 +254,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
adapter.denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, "race");
// start tracking
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// now there is a trackedrace
TrackedRace race = column.getTrackedRace(fleet);
assertNotNull(race);
@@ -254,7 +274,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
// now remove the tracked race and track again; again, the explicit tracking times in the race log must prevail
service.removeRace(regatta, race.getRace());
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
trackRace(column);
TrackedRace race2 = column.getTrackedRace(fleet);
assertEquals(explicitStartOfTracking, race2.getStartOfTracking());
assertEquals(explicitEndOfTracking, race2.getEndOfTracking());
@@ -278,8 +298,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(t(), t(), author, UUID.randomUUID(), comp1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
trackRace(column);
// now there is a trackedrace
TrackedRace race = column.getTrackedRace(fleet);
@@ -6,6 +6,7 @@ import java.util.List;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Future;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
@@ -622,10 +623,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
@Override
public void removeTrackedRace(RaceDefinition raceDefinition) {
}
@Override
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines,
WindStore windStore, long delayToLiveInMillis,
@@ -652,7 +649,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void removeRaceListener(RaceListener listener) {
public Future<Boolean> removeRaceListener(RaceListener listener) {
return null;
}
};
}
@@ -0,0 +1,122 @@
package com.sap.sailing.domain.tracking.impl;
import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.TrackedRace;
public class TrackedRegattaTest {
private final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
private final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
private Course course = new CourseImpl("course",
Arrays.asList(new Waypoint[] { new WaypointImpl(mark), new WaypointImpl(mark2) }));
private DynamicTrackedRegatta regatta;
@Before
public void setUp() {
regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* startDate */ null, /* endDate */null, null, null, "a", null));
}
@Test(expected = TimeoutException.class)
public void testBug4429() throws Exception {
final Phaser addPhaser = new Phaser(2);
final CyclicBarrier removeBarrier = new CyclicBarrier(2);
regatta.addRaceListener(new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {
try {
removeBarrier.await(1, TimeUnit.SECONDS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void raceAdded(TrackedRace trackedRace) {
try {
addPhaser.arriveAndAwaitAdvance();
addPhaser.arriveAndAwaitAdvance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
DynamicTrackedRace race1 = createRace("R1");
Thread thread1 = new Thread(() -> {
regatta.addTrackedRace(race1);
});
thread1.start();
// This ensures, that the add event is being processed but is not finished because
// this unblocks the first arriveAndAwaitAdvance() in raceAdded, but not the second.
// This way, the raceRemoved(...) call is expected to not be started because it has
// to wait for the raceAdded(...) call to have finished.
addPhaser.arriveAndAwaitAdvance();
Thread thread2 = new Thread(() -> {
regatta.removeTrackedRace(race1);
});
thread2.start();
// If the implementation ensures that the events are fired in order,
// the removeBarrier will run into a TimeoutException because the addBarrier
// is not solved and while the first event is processed the second one
// should not be started to be processed.
try {
removeBarrier.await(10, TimeUnit.MILLISECONDS);
// if this line is reached, the order of events is not correctly ensured
Assert.fail();
} finally {
addPhaser.forceTermination();
try {
// solved the barrier if one hangs at this point
// a TimeoutException can occur but we do not care about it
removeBarrier.await(10, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
thread1.join(1000);
thread2.join(1000);
}
}
private DynamicTrackedRace createRace(String name) {
RaceDefinition race1 = new RaceDefinitionImpl(name, course, boatClass, Collections.emptyList());
return new DynamicTrackedRaceImpl(regatta, race1, Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.tracking;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -134,10 +135,24 @@ public abstract class AbstractTrackedRegattaAndRaceObserver implements TrackedRe
* Called by {@link AbstractTrackedRegattaAndRaceObserver} when the {@link TrackedRegatta} was removed or the
* {@link TrackedRegatta} shouldn't be tracked anymore (this is e.g. the case in replication state).
*/
public synchronized void stop() {
trackedRegatta.removeRaceListener(raceListener);
knownTrackedRaces.keySet().forEach(this::remove);
knownTrackedRaces.clear();
public void stop() {
try {
// It's necessary that we wait for the returned future to be completed
// to ensure that all regular removals are correctly processed before
// manually removing the left over ones (see below).
// This is now necessary due to the fact that TrackedRegattaImpl fires events concurrently,
// which makes it possible to receive the removal of the TrackedRegatta before the removals
// for the contained TrackedRaces are received.
trackedRegatta.removeRaceListener(raceListener).get();
} catch (InterruptedException | ExecutionException e) {
log.log(Level.SEVERE, "Error while waiting for the raceListener to be removed", e);
}
// Depending on the code path (e.g. replication) it's possible that we still track some TrackedRace at this point.
// We need to ensure that all listeners are correctly stopped to not leak any instances.
synchronized (this) {
knownTrackedRaces.keySet().forEach(this::remove);
knownTrackedRaces.clear();
}
}
@Override
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.tracking;
import java.io.Serializable;
import java.util.concurrent.Future;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.Competitor;
@@ -89,10 +90,12 @@ public interface TrackedRegatta extends Serializable {
*/
void addRaceListener(RaceListener listener);
void removeRaceListener(RaceListener listener);
/**
* Removes the given listener and returns a {@link Future} that will be completed
* when it is guaranteed that no more events will be fired to the listener.
*/
Future<Boolean> removeRaceListener(RaceListener listener);
int getTotalPoints(Competitor competitor, TimePoint timePoint) throws NoWindException;
void removeTrackedRace(RaceDefinition raceDefinition);
}
@@ -6,10 +6,15 @@ import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,6 +54,24 @@ public class TrackedRegattaImpl implements TrackedRegatta {
private final Map<RaceDefinition, TrackedRace> trackedRaces;
private transient ConcurrentMap<RaceListener, RaceListener> raceListeners;
/**
* This {@link WorkQueue} is used to do all event related work. This ensures that e.g. events are fired in order.
* The following cases need to be handles through this queue:
* <ul>
* <li>Firing events when adding/removing {@link TrackedRace} instances (see {@link #enqueEvent}). The list of
* listeners to fire the event to need to be the list of listeners existing when enqueuing the event. This ensures
* that newly added listeners only receive events after the initial {@link TrackedRace} instances are delivered to
* this listener.</li>
* <li>Firing events for the already existing {@link TrackedRace} instances when adding a new listener (see
* {@link #addRaceListener(RaceListener)}). This ensures that all events are correctly fired to this listener that
* are triggered after the listener was added while suppressing inconsistent events before/while the initial
* {@link TrackedRace} instances are delivered to this listener.</li>
* <li>Completing the future returned by {@link #removeRaceListener(RaceListener)} to ensure that the receiver gets
* to know when it is guaranteed that no more event will be fired to the listener.
* </ul>
*/
private transient WorkQueue eventQueue;
public TrackedRegattaImpl(Regatta regatta) {
super();
@@ -56,11 +79,13 @@ public class TrackedRegattaImpl implements TrackedRegatta {
this.regatta = regatta;
this.trackedRaces = new HashMap<RaceDefinition, TrackedRace>();
raceListeners = new ConcurrentHashMap<RaceListener, RaceListener>();
eventQueue = new WorkQueue();
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
this.raceListeners = new ConcurrentHashMap<RaceListener, RaceListener>();
eventQueue = new WorkQueue();
}
@Override
@@ -110,28 +135,25 @@ public class TrackedRegattaImpl implements TrackedRegatta {
logger.info("adding tracked race for "+trackedRace.getRace()+" to tracked regatta "+getRegatta().getName()+
" with regatta hash code "+getRegatta().hashCode());
oldTrackedRace = trackedRaces.put(trackedRace.getRace(), trackedRace);
if (oldTrackedRace != trackedRace) {
notifyListenersAboutTrackedRaceAdded(trackedRace);
}
} finally {
unlockTrackedRacesAfterWrite();
}
if (oldTrackedRace != trackedRace) {
notifyListenersAboutTrackedRaceAdded(trackedRace);
}
}
protected void notifyListenersAboutTrackedRaceAdded(TrackedRace trackedRace) {
for (RaceListener listener : raceListeners.keySet()) {
listener.raceAdded(trackedRace);
}
enqueEvent(listener -> listener.raceAdded(trackedRace));
}
@Override
public void removeTrackedRace(RaceDefinition raceDefinition) {
lockTrackedRacesForWrite();
try {
trackedRaces.remove(raceDefinition);
} finally {
unlockTrackedRacesAfterWrite();
}
protected void enqueEvent(Consumer<RaceListener> fireEventCallback) {
final Set<RaceListener> listenersToInform = new HashSet<>(raceListeners.keySet());
eventQueue.addWork(() -> {
for (RaceListener listener : listenersToInform) {
fireEventCallback.accept(listener);
}
});
}
@Override
@@ -139,19 +161,14 @@ public class TrackedRegattaImpl implements TrackedRegatta {
lockTrackedRacesForWrite();
try {
trackedRaces.remove(trackedRace.getRace());
notifyListenersAboutTrackedRaceRemoved(trackedRace);
} finally {
unlockTrackedRacesAfterWrite();
}
// Fix for bug4414: put this into a separate thread to avoid deadlock caused by
// a synchronized RegattaListener.raceRemoved while holding the TrackedRegattaImpl.trackedRacesLock's write lock
// acquired in RacingEventServiceImpl.removeRace
new Thread(()->notifyListenersAboutTrackedRaceRemoved(trackedRace)).start();
}
protected void notifyListenersAboutTrackedRaceRemoved(TrackedRace trackedRace) {
for (RaceListener listener : raceListeners.keySet()) {
listener.raceRemoved(trackedRace);
}
enqueEvent(listener -> listener.raceRemoved(trackedRace));
}
@Override
@@ -216,27 +233,37 @@ public class TrackedRegattaImpl implements TrackedRegatta {
@Override
public void addRaceListener(RaceListener listener) {
final List<TrackedRace> trackedRacesCopy = new ArrayList<>();
lockTrackedRacesForRead();
try {
raceListeners.put(listener, listener);
final List<TrackedRace> trackedRacesCopy = new ArrayList<>();
Util.addAll(getTrackedRaces(), trackedRacesCopy);
eventQueue.addWork(() -> {
for (TrackedRace trackedRace : trackedRacesCopy) {
listener.raceAdded(trackedRace);
}
});
} finally {
unlockTrackedRacesAfterRead();
}
for (TrackedRace trackedRace : trackedRacesCopy) {
listener.raceAdded(trackedRace);
}
}
@Override
public void removeRaceListener(RaceListener listener) {
public Future<Boolean> removeRaceListener(RaceListener listener) {
final CompletableFuture<Boolean> result = new CompletableFuture<Boolean>();
lockTrackedRacesForRead();
try {
raceListeners.remove(listener);
if (raceListeners.remove(listener) != null) {
eventQueue.addWork(() -> {
result.complete(Boolean.TRUE);
});
} else {
result.complete(Boolean.TRUE);
}
} finally {
unlockTrackedRacesAfterRead();
}
return result;
}
@Override
@@ -0,0 +1,54 @@
package com.sap.sailing.domain.tracking.impl;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Queue that executes {@link Runnable} instances in order on a distinct {@link Thread}. The {@link WorkQueue} ensures
* that a Thread is started when the first {@link Runnable} is added via {@link #addWork(Runnable)} and that the
* {@link Thread} is terminated after executing the last available {@link Runnable}.
*/
public class WorkQueue {
private static final Logger LOG = Logger.getLogger(WorkQueue.class.getName());
private final LinkedBlockingQueue<Runnable> queue;
private Thread workThread;
public WorkQueue() {
queue = new LinkedBlockingQueue<>();
}
/**
* Adds the given {@link Runnable} to the {@link Queue} of work to be executed.
* Ensures that a Thread is started if there isn't one running yet.
*/
public synchronized void addWork(Runnable workToAdd) {
queue.add(workToAdd);
if (workThread == null) {
workThread = new Thread(this::doWork);
workThread.start();
}
}
private void doWork() {
while (true) {
final Runnable workToDo;
synchronized (this) {
workToDo = queue.poll();
if (workToDo == null) {
workThread = null;
break;
}
}
if (workToDo != null) {
try {
workToDo.run();
} catch (Exception e) {
LOG.log(Level.SEVERE, "Error while executing work in queue", e);
}
}
}
}
}
@@ -139,9 +139,9 @@ public class SimpleGridFileReadingTest {
// alternatively for the 4-6 day forecast: http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.oceanic/VP.004-007/
// validate graphically at http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.oceanic/VP.004-007/
final Formatter errorLog = new Formatter(System.err);
Files.copy(new URL("http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.oceanic/VP.001-003/ds.wdir.bin").openStream(),
Files.copy(new URL("http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.conus/VP.001-003/ds.wdir.bin").openStream(),
new File("resources/ds.wdir.bin").toPath(), StandardCopyOption.REPLACE_EXISTING);
Files.copy(new URL("http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.oceanic/VP.001-003/ds.wspd.bin").openStream(),
Files.copy(new URL("http://tgftp.nws.noaa.gov/SL.us008001/ST.expr/DF.gr2/DC.ndfd/AR.conus/VP.001-003/ds.wspd.bin").openStream(),
new File("resources/ds.wspd.bin").toPath(), StandardCopyOption.REPLACE_EXISTING);
FeatureDataset dataSetDirection = FeatureDatasetFactoryManager.open(FeatureType.ANY, "resources/ds.wdir.bin", /* task */ null, errorLog);
@@ -8,6 +8,7 @@ import java.util.Collections;
import java.util.List;
import java.util.NavigableSet;
import java.util.Set;
import java.util.concurrent.Future;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
@@ -321,10 +322,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
return null;
}
@Override
public void removeTrackedRace(RaceDefinition raceDefinition) {
}
@Override
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
@@ -350,7 +347,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void removeRaceListener(RaceListener listener) {
public Future<Boolean> removeRaceListener(RaceListener listener) {
return null;
}
};
}
@@ -29,7 +29,7 @@ playSpeedHelp=Utilice "1" para velocidad de reproducción normal, "2" para doble
playModeLive=En directo
playModeReplay=Modo de reproducción
timeDelay=Retraso
timeDelayHelp=Deje el campo vacío para reproducir arbitrariamente; indique una cantidad de segundos de retraso (p.ej., «60» para un minuto, o bien «0») previa a la transmisión de datos en directo.
timeDelayHelp=Deje el campo vacío para reproducir arbitrariamente; indique una cantidad de segundos de retraso (p.ej., "60" para un minuto, o bien "0") previa a la transmisión de datos en directo.
speedInKnots=Velocidad (nudos)
fromDeg=Desde (grados)
noRacesYet=Todavía no hay ninguna carrera.
@@ -141,7 +141,7 @@ delayMustBeNonNegative=El retraso debe ser mayor que cero.
chooseUpdateIntervalOfAtLeastOneSecond=Seleccione un intervalo de actualización de al menos un segundo
errorSettingWindForRace=Error al configurar viento para la carrera
errorFetchingWindInformationForRace=Error al obtener información de viento para la carrera
errorWhileTryingToSetWindSourceForRace=Error al intentar fijar el indicador «viento empieza a barlovento»
errorWhileTryingToSetWindSourceForRace=Error al intentar fijar el indicador "viento empieza a barlovento"
inEvent=en evento
to=a
toSide=a
@@ -233,6 +233,32 @@ hoverOverAPoint=Pase el cursor por encima de un punto para obtener detalles
noSelection=Ninguna selección
raceIsKnownToStartUpwind=La carrera empieza con ceñida
events=Eventos
pairingList=Lista de emparejamientos
pairingLists=Listas de emparejamientos
pairingListCreationInfo=Inicialmente se calculará un plantilla que contenga solo los números de competidores y que pueda aplicarse a otras clasificaciones. Si el recuento de competidores no es divisible por recuento de embarcaciones sin remanente, se introducirán marcadores de posición en blanco en la lista de emparejamientos. \ Además, si el recuento de competidores difiere del recuento de competidores registrado en la clasificación real, la lista de emparejamientos no podrá aplicarse a los registros de carrera. \ El recuento de flights, que se utiliza para generar una lista de emparejamientos, se fija con todos los flights de la clasificación que no son carreras de medalla.
setCompetitors=Fije el recuento de competidores:
seriesHint=Seleccione una o más series que deberían estar en una lista de emparejamientos:
amountOfFlightRepeats=Cantidad de repeticiones de flight
insertIntoRegatta=Insertar en regata
recalculate=Recalcular
csvExport=Exportar como CSV
printView=Imprimir vista preliminar
print=Imprimir
invalidCompetitorCount=Recuento de competidores no válido
invalidFlightMultiplier=Repeticiones de flight no válidas
invalidSeriesSelection=Selección de series no válida
flightsMustBeAMultipleOfMultiplier=Los flights deben ser múltiplos de multiplicador de flight
parameters=Parámetros
numberOfFlights=Cantidad de flights
numberOfFleets=Cantidad de carreras por flight
numberOfCompetitors=Cantidad de competidores
numberOfRaces=Número de carreras
quality=Calidad
pairingListTemplate=Plantilla de lista de emparejamientos
printHint=Imprime la versión aplicada
blockedApplyButton=Los competidores registrados difieren de los competidores de la lista de emparejamientos
multiplierInfo=Multiplica los flights y los crea uno junto a otro de modo que sea posible una competición con menos modificaciones de embarcación.
noPairingListAvailable=La función de impresión solo está disponible si ya se han aplicado las listas de emparejamientos a los registros de carrera de las clasificaciones seleccionadas.
settingsForComponent=Opciones para {0}
noEventsFound=No se han encontrado eventos
noEventSelected=Ningún evento seleccionado
@@ -351,6 +377,7 @@ replicatingFromMaster=Replicando desde el maestro {0}:{2}, puerto de mensajería
showWindSpeedSeries=Mostrar datos de velocidad del viento
showWindDirectionSeries=Mostrar datos de dirección del viento
fleet=Flota
boat=Bote
boatClass=Clase de bote
setDelayToLive=Fijar retraso en en directo.
pleaseEnterNonEmptyVenue=Indique un lugar de celebración.
@@ -524,7 +551,6 @@ additionalUrlSettings=Opciones de URL adicionales
restrictToSingleSelectedRace=Restringir a la carrera individual seleccionada
expandSelectedRace=Expandir carrera seleccionada
showRaceDetails=Permitir detalles de carrera
numberOfRaces=Número de carreras
numberOfRacesMustBeNonNegativeNumber=Indique el número de últimas carreras a visualizar
chooseTheWayYouSelectRaces=Elija la manera de seleccionar carreras
selectFromAllRaces=Seleccionar desde todas las carreras
@@ -1393,7 +1419,7 @@ racesQuickfinder=Carreras Quickfinder
profileQuickfinder=Perfil Quickfinder
statistics=Estadísticas
statisticsFor=Estadísticas para {0}
impressions=Impresiones
impressions=Instantáneas
notAvailableOnMobileMessage=Este contenido no está disponible para la versión móvil. ¿Desea pasar a la versión de escritorio?
gotoDesktop=Ir a la versión de escritorio
goBack=Volver
@@ -1454,6 +1480,7 @@ plainResultsPresenter=Presentador de resultados simples
resultsChart=Gráfico de resultados
tabbedResultsPresenter=Presentador de resultados por pestañas
polarResultsPresenter=Presentador de resultados de coordenadas polares
maneuverSpeedDetailsResultsPresenter=Presentador de resultados detallados de velocidad de maniobra
dataMiningRetrieval=Recuperación de datos
actionWatch=Observar
actionAnalyze=Analizar
@@ -1463,8 +1490,12 @@ doYouWantToCreateADefaultRegattaLeaderboard=¿Desea crear una tabla de clasifica
copyCourse=Copiar regata
copyCompetitors=Copiar competidores
smartphoneTracking=Rastreo de smartphone
flightsCount={0,number} vuelos
flightsCount[one]={0,number} vuelo
titelOfChooseNameDialog=Seleccione un nombre
ownPrefix=Prefijo propio
defaultName=Por defecto
exampleTextForName=Su nombre aparece como:
flightsCount={0,number} flights
flightsCount[one]={0,number} flight
viewQueryDefinition=Ver definición de consulta
queryDefinitionViewer=Visor de definición de consulta
groupAverageAscending=Promedio de grupo (ascendente)
@@ -1702,7 +1733,7 @@ headerLogo=Sailing Analytics
headerSearchPlaceholder=Buscar
mainEventShowAll=Mostrar todos los eventos
mainEventTitle=Últimos eventos de Sailing World
mainMediaSubtitle=Recomendamos perderse en las mejores y más recientes impresiones de su evento de navegación favorito.
mainMediaSubtitle=Recomendamos perderse en las mejores y más recientes instantáneas de su evento de navegación favorito.
mainMediaTitle=Fotógrafos amantes de la navegación
mainMediaVideosSubtitle=Sumérjase en el mundo de la navegación y revise los eventos más recientes para más vídeos.
mainMediaVideosTitle=Entradas de vídeo recientes
@@ -1873,6 +1904,26 @@ showEstimatedDuration=Mostrar duración estimada
estimatedDuration=Duración estimada:
countDown=Evento comienza en {0} {1}
countDownEnd=El evento comenzará en pocos segundos
maneuverSpeedDetails=Detalles de velocidad de maniobra
maneuverDirectionNormalization=Normalización de dirección de maniobra
maneuver=Maniobra
minManeuverDuration=Duración mínima de maniobra (s)
maxManeuverDuration=Duración máxima de maniobra (s)
minManeuverEnteringSpeedInKnots=Velocidad mínima de entrada de maniobra (kts)
maxManeuverEnteringSpeedInKnots=Velocidad máxima de entrada de maniobra (kts)
minManeuverExitingSpeedInKnots=Velocidad mínima de salida de maniobra (kts)
maxManeuverExitingSpeedInKnots=Velocidad máxima de salida de maniobra (kts)
minManeuverEnteringAbsTWA=TWA absoluto de velocidad mínima de entrada de maniobra
maxManeuverEnteringAbsTWA=TWA absoluto de velocidad máxima de entrada de maniobra
minManeuverExitingAbsTWA=TWA absoluto de velocidad mínima de salida de maniobra
maxManeuverExitingAbsTWA=TWA absoluto de velocidad máxima de salida de maniobra
maneuverDirectionEqualWeightingEnabled=Activar ponderación 50%-50% para la dirección de maniobra en agregaciones de "valor por TWA"
minValue=Valor mínimo
maxValue=Valor máximo
zeroTo360AxisLabeling=Etiqueta de eje 0-360°
exportStatisticsCurveToCsv=Curva estadística de exportación a CSV
csvCopiedToClipboard=Se ha copiado el contenido CSV al portapapeles. Péguelo donde quiera.
minDataCount=Registro de datos mínimo
moreLoginInformationHeadline=Ventajas de registrarse en SAP Sailing Analytics
moreLoginInformationIntroduction=Como usuario registrado de SAP Sailing Analytics dispone de acceso a la funcionalidad que no está disponible para usuarios anónimos. Simplemente regístrese para acceder a las funciones que se muestras más abajo.
moreLoginInformationSectionUserSettingsHeading=Opciones de usuario
@@ -1918,6 +1969,7 @@ currentStbdRudderRake=Inclinación del timón a estribor
currentStbdRudderRakeTooltip=La inclinación actual del timón a estribor
currentMastRotationInDegree=Rotación del mástil
currentMastRotationInDegreeTooltip=La rotación actual del mástil en grados
mainCurveAnalysis=Analizar solo curva principal
finishingTime=Hora de llegada
finishTimeString=Hora de fin
setFinishingAndFinishTime=Fijar hora de llegada y de fin
@@ -1969,3 +2021,15 @@ totalDurationFoiledInSeconds=Tiempo total con foils
totalDistanceFoiledInMeters=Distancia total con foils
totalDurationFoiledInSecondsTooltip=Tiempo total con foils, a lo largo de todas la clasificación
totalDistanceFoiledInMetersTooltip=Distancia total con foils, a lo largo de todas la clasificación
threeSixtyVideoHint=Se trata de un vídeo de 360º, la cámara se puede girar
processingMP4=MP4 se analiza (esto durará unos segundos)
resetStartTimeToDefault=Fijar en Por defecto
importFullExpeditionData=Importar datos de expedición completos
importCanceledNoCompetitorAdded=No se ha añadido ningún competidor. Se cancelará la importación.
importCanceledByUser=Importación cancelada
importFinished=Datos de importación finalizados
importFinishedMessage=Datos de expedición importados correctamente.
importFinishedGotoRaceboard=Abrir Raceboard
importFinishedGotoEvent=Abrir evento
chooseAName=Seleccione un nombre
unexpectedErrorDuringFileImport=Se ha producido un error inesperado durante la carga del fichero.
@@ -233,6 +233,32 @@ hoverOverAPoint=Placez le curseur sur un point pour obtenir des détails.
noSelection=Aucune sélection
raceIsKnownToStartUpwind=La course a commencé avec une portion de parcours au vent.
events=Manifestations
pairingList=Liste d''appariement
pairingLists=Listes d''appariement
pairingListCreationInfo=Tout d''abord, un modèle contenant uniquement le nombre de concurrents sera calculé. Il pourra être appliqué à d''autres palmarès. Si la division du nombre de concurrents par le nombre de bateaux ne permet pas d''obtenir un nombre entier, des caractères génériques vides seront ajoutés à la liste d''appariement. \ En outre, si le nombre de concurrents ne correspond pas au nombre de concurrents inscrits au palmarès actuel, la liste d''appariement ne pourra pas être appliquée aux journaux de course. \ Le nombre de flights, utilisé pour générer une liste d''appariement, est défini par tous les flights du palmarès, hors courses médaillées.
setCompetitors=Veuillez définir le nombre de concurrents :
seriesHint=Veuillez sélectionner une ou plusieurs séries à ajouter à une liste de paires :
amountOfFlightRepeats=Nombre de répétitions de flights
insertIntoRegatta=Ajouter à la régate
recalculate=Recalculer
csvExport=Exporter au format CSV
printView=Aperçu avant impression
print=Imprimer
invalidCompetitorCount=Nombre de concurrents non valide
invalidFlightMultiplier=Répétitions de flights non valides
invalidSeriesSelection=Sélection de séries non valide
flightsMustBeAMultipleOfMultiplier=Les flights doivent être un multiple du multiplicateur de flight.
parameters=Paramètres
numberOfFlights=Nombre de flights
numberOfFleets=Nombre de courses par flight
numberOfCompetitors=Nombre de concurrents
numberOfRaces=Nombre de courses
quality=Qualité
pairingListTemplate=Modèle de liste d''appariement
printHint=Imprime la version appliquée
blockedApplyButton=Le nombre de concurrents inscrits ne correspond pas au nombre de concurrents de la liste d''appariement.
multiplierInfo=Multipliez les flights et créez-les les uns après les autres pour obtenir une compétition avec le moins de bateaux possible.
noPairingListAvailable=La fonction d''impression est uniquement disponible lorsqu''une liste d''appariement a déjà été appliquée aux journaux de course des palmarès sélectionnés.
settingsForComponent=Options pour {0}
noEventsFound=Aucune manifestation trouvée
noEventSelected=Aucune manifestation sélectionnée
@@ -351,6 +377,7 @@ replicatingFromMaster=Réplication du serveur maître {0}:{2}, port de messageri
showWindSpeedSeries=Afficher données de vitesse du vent
showWindDirectionSeries=Afficher données de direction du vent
fleet=Flotte
boat=Bateau
boatClass=Catégorie de bateau
setDelayToLive=Définir décalage par rapport au direct
pleaseEnterNonEmptyVenue=Saisissez un lieu de manifestation.
@@ -524,7 +551,6 @@ additionalUrlSettings=Options d''URL supplémentaires
restrictToSingleSelectedRace=Limiter à la seule course sélectionnée
expandSelectedRace=Développer course sélectionnée
showRaceDetails=Autoriser détails de la course
numberOfRaces=Nombre de courses
numberOfRacesMustBeNonNegativeNumber=Saisissez le nombre de dernières courses à afficher.
chooseTheWayYouSelectRaces=Indiquez de quelle façon vous souhaitez sélectionner les courses
selectFromAllRaces=Sélectionner parmi toutes les courses
@@ -1454,6 +1480,7 @@ plainResultsPresenter=Visualiseur de résultats bruts
resultsChart=Graphique des résultats
tabbedResultsPresenter=Visualiseur de résultats avec onglets
polarResultsPresenter=Visualiseur de résultats polaires
maneuverSpeedDetailsResultsPresenter=Visualiseur des résultats : détails sur la vitesse lors de la manœuvre
dataMiningRetrieval=Récupération de données
actionWatch=Regarder
actionAnalyze=Analyser
@@ -1463,6 +1490,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=Voulez-vous créer un palmarès de r
copyCourse=Copier course
copyCompetitors=Copier concurrents
smartphoneTracking=Suivi smartphone
titelOfChooseNameDialog=Indiquer un nom
ownPrefix=Préfixe personnalisé
defaultName=Par défaut
exampleTextForName=Votre nom apparaît de la manière suivante :
flightsCount={0,number} départs de deux équipages
flightsCount[one]={0,number} départ de deux équipages
viewQueryDefinition=Afficher la définition de la requête
@@ -1873,6 +1904,26 @@ showEstimatedDuration=Afficher la durée estimée
estimatedDuration=Durée estimée :
countDown=La manifestation commence dans {0} {1}
countDownEnd=La manifestation commencera dans quelques secondes.
maneuverSpeedDetails=Détails sur la vitesse lors de la manœuvre
maneuverDirectionNormalization=Normalisation du cap pendant la manœuvre
maneuver=Manœuvre
minManeuverDuration=Durée min. de la manœuvre (s)
maxManeuverDuration=Durée max. de la manœuvre (s)
minManeuverEnteringSpeedInKnots=Vitesse min. d''entrée de manœuvre (nds)
maxManeuverEnteringSpeedInKnots=Vitesse max. d''entrée de manœuvre (nds)
minManeuverExitingSpeedInKnots=Vitesse min. de sortie de manœuvre (nds)
maxManeuverExitingSpeedInKnots=Vitesse max. de sortie de manœuvre (nds)
minManeuverEnteringAbsTWA=TWA absolu min. d''entrée de manœuvre
maxManeuverEnteringAbsTWA=TWA absolu max. d''entrée de manœuvre
minManeuverExitingAbsTWA=TWA absolu min. de sortie de manœuvre
maxManeuverExitingAbsTWA=TWA absolu max. de sortie de manœuvre
maneuverDirectionEqualWeightingEnabled=Activer pondération 50 %-50 % pour le cap pendant la manœuvre dans les agrégations "valeur par TWA"
minValue=Valeur min.
maxValue=Valeur max.
zeroTo360AxisLabeling=Étiquetage axe 0-360°
exportStatisticsCurveToCsv=Exporter la courbe des statistiques au format CSV
csvCopiedToClipboard=Le contenu du CSV a été copié dans le presse-papiers. Copiez-le où vous le souhaitez.
minDataCount=Nombre de données min.
moreLoginInformationHeadline=Avantages de SAP Sailing Analytics
moreLoginInformationIntroduction=Si vous êtes un utilisateur inscrit sur SAP Sailing Analytics, vous avez accès à des fonctionnalités qui ne sont pas disponibles pour les utilisateurs anonymes. Inscrivez-vous pour accéder à toutes les fonctionnalités indiquées ci-dessous.
moreLoginInformationSectionUserSettingsHeading=Options utilisateur
@@ -1918,6 +1969,7 @@ currentStbdRudderRake=Inclinaison du gouvernail tribord
currentStbdRudderRakeTooltip=Inclinaison actuelle du gouvernail tribord
currentMastRotationInDegree=Rotation du mât
currentMastRotationInDegreeTooltip=Rotation actuelle du mât en degrés
mainCurveAnalysis=Analyser uniquement la courbe principale
finishingTime=Heure d''arrivée du premier
finishTimeString=Heure de fermeture de la ligne d''arrivée
setFinishingAndFinishTime=Définir heure d''arrivée du premier et de fermeture de la ligne d''arrivée
@@ -1969,3 +2021,15 @@ totalDurationFoiledInSeconds=Temps total passé en planing
totalDistanceFoiledInMeters=Distance totale parcourue en planing
totalDurationFoiledInSecondsTooltip=Temps total passé en planing, sur la totalité du palmarès
totalDistanceFoiledInMetersTooltip=Distance totale parcourue en planing, sur la totalité du palmarès
threeSixtyVideoHint=Il s''agit d''une vidéo à 360°. Vous pouvez tourner la caméra.
processingMP4=Analyse du Mp4 en cours (patientez quelques secondes).
resetStartTimeToDefault=Act. valeur par défaut
importFullExpeditionData=Importer toutes les données d''Expedition
importCanceledNoCompetitorAdded=Aucun concurrent n''a été ajouté ! L''importation sera annulée.
importCanceledByUser=Importation annulée !
importFinished=Importation des données terminée
importFinishedMessage=Données d''Expedition correctement importées
importFinishedGotoRaceboard=Ouvrir tableau des courses
importFinishedGotoEvent=Ouvrir manifestation
chooseAName=Indiquer un nom
unexpectedErrorDuringFileImport=Une erreur inattendue s''est produite lors du chargement du fichier.
@@ -236,6 +236,32 @@ hoverOverAPoint=詳細についてはポイントをホバー
noSelection=未選択
raceIsKnownToStartUpwind=アップウィンドレグでレーススタート
events=イベント
pairingList=対戦表
pairingLists=対戦表
pairingListCreationInfo=まず最初に、競技者番号のみが含まれていて、他のリーダーボードに適用できるテンプレートが計算されます。競技者カウントが艇カウントで割り切れない場合、空のプレースホルダーが対戦表に入力されます。 \ また、競技者カウントが実際のリーダーボードにある登録済の競技者カウントと等しくない場合、対戦表をレースログに適用することはできません。 \ 対戦表を生成するために使用されるフライトのカウントは、リーダーボードの全フライト (非メダルレース) によって設定されます。
setCompetitors=競技者カウントを設定してください:
seriesHint=対戦表にあることが必要なシリーズを 1 つ以上選択してください:
amountOfFlightRepeats=フライト繰返回数
insertIntoRegatta=レガッタに挿入
recalculate=再計算
csvExport=エクスポート (CSV)
printView=印刷プレビュー
print=印刷
invalidCompetitorCount=競技者カウントが無効
invalidFlightMultiplier=フライト繰返回数が無効
invalidSeriesSelection=シリーズ選択が無効
flightsMustBeAMultipleOfMultiplier=フライト回数はフライト乗数の倍数であることが必要
parameters=パラメータ
numberOfFlights=フライト回数
numberOfFleets=フライト毎のレース回数
numberOfCompetitors=競技者数
numberOfRaces=レース数
quality=質
pairingListTemplate=対戦表テンプレート
printHint=適用バージョンを印刷
blockedApplyButton=登録されている競技者数が対戦表にある競技者数と同じでありません
multiplierInfo=複数のフライトを艇変更がより少なく競技が可能となるよう互いに隣り合わせに作成
noPairingListAvailable=印刷機能は選択したリーダーボードレースログに対戦表がすでに適用されている場合にのみ利用が可能です。
settingsForComponent={0} の設定
noEventsFound=イベントが見つかりませんでした
noEventSelected=イベントが選択されていません
@@ -354,6 +380,7 @@ replicatingFromMaster=マスタ {0}:{2}、メッセージングポート {3}:{1}
showWindSpeedSeries=風速データ表示
showWindDirectionSeries=風向データ表示
fleet=フリート
boat=艇
boatClass=艇種
setDelayToLive=ライブに遅延を設定
pleaseEnterNonEmptyVenue=開催地を入力してください。
@@ -527,7 +554,6 @@ additionalUrlSettings=追加 URL 設定
restrictToSingleSelectedRace=単一の選択レースに制限
expandSelectedRace=選択レースを拡大
showRaceDetails=レース詳細を許容
numberOfRaces=レース数
numberOfRacesMustBeNonNegativeNumber=表示する最終レース数を入力してください
chooseTheWayYouSelectRaces=レース選択方法の選択
selectFromAllRaces=全レースから選択
@@ -1457,6 +1483,7 @@ plainResultsPresenter=プレーン結果表示ツール
resultsChart=結果チャート
tabbedResultsPresenter=タブ結果表示ツール
polarResultsPresenter=ポーラー結果表示ツール
maneuverSpeedDetailsResultsPresenter=マニューバー速度詳細結果表示ツール
dataMiningRetrieval=データ取得
actionWatch=視聴
actionAnalyze=分析
@@ -1466,6 +1493,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=レガッタリーダーボードを
copyCourse=コースのコピー
copyCompetitors=競技者のコピー
smartphoneTracking=スマートフォン追跡
titelOfChooseNameDialog=名前を選択
ownPrefix=自身のプレフィクス
defaultName=デフォルト
exampleTextForName=名前は次のようになります:
flightsCount={0,number} フライト
flightsCount[one]={0,number} フライト
viewQueryDefinition=クエリ定義の表示
@@ -1876,6 +1907,26 @@ showEstimatedDuration=推定持続時間の表示
estimatedDuration=推定持続時間:
countDown=イベントは {0} {1} に開始
countDownEnd=このイベントはあと数秒で開始します
maneuverSpeedDetails=マニューバー速度詳細
maneuverDirectionNormalization=マニューバー方向正規化
maneuver=マニューバー
minManeuverDuration=マニューバー最小持続時間 (s)
maxManeuverDuration=マニューバー最大持続時間 (s)
minManeuverEnteringSpeedInKnots=マニューバー最小進入速度 (kts)
maxManeuverEnteringSpeedInKnots=マニューバー最大進入速度 (kts)
minManeuverExitingSpeedInKnots=マニューバー最小脱出速度 (kts)
maxManeuverExitingSpeedInKnots=マニューバー最大脱出速度 (kts)
minManeuverEnteringAbsTWA=マニューバー最小進入絶対 TWA
maxManeuverEnteringAbsTWA=マニューバー最大進入絶対 TWA
minManeuverExitingAbsTWA=マニューバー最小脱出絶対 TWA
maxManeuverExitingAbsTWA=マニューバー最大脱出絶対 TWA
maneuverDirectionEqualWeightingEnabled=マニューバー方向の 50%-50% 重み付けを有効化 ("TWA 別の値" の集約)
minValue=最小値
maxValue=最大値
zeroTo360AxisLabeling=0-360° 軸のラベリング
exportStatisticsCurveToCsv=統計曲線を CSV にエクスポート
csvCopiedToClipboard=CSV の内容がクリップボードにコピーされました。好きな場所にペーストしてください。
minDataCount=最小データカウント
moreLoginInformationHeadline=SAP Sailing Analytics にサインインする利点
moreLoginInformationIntroduction=SAP Sailing Analytics の登録ユーザーには、匿名ユーザーに許されていない機能へのアクセス権限があります。登録を行って、下記の機能にアクセスしてください。
moreLoginInformationSectionUserSettingsHeading=ユーザー設定
@@ -1888,7 +1939,7 @@ anniversaryUnitText=レース
anniversaryUnitText[one]=レース
anniversaryMajorCountdownTeaser=カウントダウン情報です。{1,number,#,###} 番目のレースまでもうわずか {0,number,#,###} レースです。
anniversaryMajorCountdownTeaser[one]=カウントダウン情報です。{1,number,#,###} 番目のレースまでもうわずか {0,number,#,###} レースです。
anniversaryMajorCountdownDescription=SAP では、www.sapsailing.com における {0,number,#,###} 番目のレースを祝うことにしています。どのレースがゴールテープを切るでしょうか。その記念レースの主催者には、義援目的で合計で 10,000 ユーロが贈呈されます。当選者はこの Web サイトで発表されます。引き続きご注目いただき、一緒にカウントダウンしていきましょう。
anniversaryMajorCountdownDescription=SAP では、www.sapsailing.com における {0,number,#,###} 番目のレースを祝うことにしています。どのレースがゴールテープを切るでしょうか。その記念レースの主催者には、義援目的で合計で 10,000 ユーロが贈呈されます。当選者はこの Web サイトで発表されます。引き続きご注目いただき、一緒にカウントダウンしていきましょう。
anniversaryRepdigitCountdownTeaser=カウントダウン情報です。{1,number,#,###} 番目のレースまでもうわずか {0,number,#,###} レースです。
anniversaryRepdigitCountdownTeaser[one]=カウントダウン情報です。{1,number,#,###} 番目のレースまでもうわずか {0,number,#,###} レースです。
anniversaryRepdigitCountdownDescription=SAP では、縁起のいい番号のレースを祝うことにしています。www.sapsailing.com における {0,number, #,###} 番目のレースは誰が行うことになるでしょうか。そのレースの参加者には、SAP から最上級のサマーフェスティバルが無料で提供されます。当選者はこの Web サイトで発表されます。引き続きご注目いただき、一緒にカウントダウンしていきましょう。
@@ -1921,6 +1972,7 @@ currentStbdRudderRake=右舷ラダー傾斜角
currentStbdRudderRakeTooltip=現在の右舷ラダー傾斜角
currentMastRotationInDegree=マスト回転
currentMastRotationInDegreeTooltip=現在のマスト回転 (度)
mainCurveAnalysis=主曲線のみ分析
finishingTime=フィニッシュ予定時刻
finishTimeString=フィニッシュ時刻
setFinishingAndFinishTime=フィニッシュ予定時刻とフィニッシュ時刻の設定
@@ -1972,3 +2024,15 @@ totalDurationFoiledInSeconds=合計フォイリング時間
totalDistanceFoiledInMeters=合計フォイリング距離
totalDurationFoiledInSecondsTooltip=合計フォイリング時間 (リーダーボード全体)
totalDistanceFoiledInMetersTooltip=合計フォイリング距離 (リーダーボード全体)
threeSixtyVideoHint=これは 360 度の動画であり、カメラを回転できます
processingMP4=Mp4 が解析されます (これには数秒かかります)
resetStartTimeToDefault=デフォルトに設定
importFullExpeditionData=Expedition データ全体をインポート
importCanceledNoCompetitorAdded=競技者が追加されませんでした。インポートは取り消されます。
importCanceledByUser=インポートが取り消されました
importFinished=データのインポートが終了
importFinishedMessage=Expedition データがインポートされました。
importFinishedGotoRaceboard=レースボードを開く
importFinishedGotoEvent=イベントを開く
chooseAName=名称を選択
unexpectedErrorDuringFileImport=ファイルのアップロード時に予期しないエラーが発生しました。
@@ -233,6 +233,32 @@ hoverOverAPoint=Passar com o mouse sobre um ponto para detalhes
noSelection=Nenhuma seleção
raceIsKnownToStartUpwind=A corrida começa com perna de contravento
events=Eventos
pairingList=Lista de pares
pairingLists=Listas de pares
pairingListCreationInfo=Primeiro será calculado um modelo que contém somente os números dos competidores e pode ser aplicado a outros painéis de classificação. Se a contagem de competidores não for divisível pela contagem de barcos sem restante, os caracteres de preenchimento em branco serão inseridos na lista de pares. \ Além disso, se a contagem de competidores for diferente da contagem de competidores registrados no painel de classificação real, a lista de pares não pode ser aplicada aos registros das corridas. \ A contagem dos voos, que é utilizada para gerar uma lista de pares, é definida por todos os voos do painel de classificação que não sejam corridas para medalha.
setCompetitors=Defina a contagem dos competidores:
seriesHint=Selecione uma ou mais séries que devam estar em uma lista de pares:
amountOfFlightRepeats=Número de repetições de voos
insertIntoRegatta=Inserir na regata
recalculate=Recalcular
csvExport=Exportar como CSV
printView=Visualizar impressão
print=Imprimir
invalidCompetitorCount=Contagem de competidores inválida
invalidFlightMultiplier=Repetições de voos inválidas
invalidSeriesSelection=Seleção de séries inválida
flightsMustBeAMultipleOfMultiplier=Os voos devem ser um múltiplo do multiplicador de voos
parameters=Parâmetros
numberOfFlights=Número de voos
numberOfFleets=Número de corridas por voo
numberOfCompetitors=Número de competidores
numberOfRaces=Número de corridas
quality=Qualidade
pairingListTemplate=Modelo da lista de pares
printHint=Imprime a versão aplicada
blockedApplyButton=Os competidores registrados são diferentes dos competidores da lista de pares!
multiplierInfo=Multiplica os voos e cria-os uns junto aos outros de modo que seja possível uma competição com menos mudanças de barco.
noPairingListAvailable=A função de impressão só está disponível caso já tenha sido aplicada uma lista de pares aos registros de corridas dos painéis de classificação selecionados.
settingsForComponent=Configurações para {0}
noEventsFound=Nenhum evento encontrado
noEventSelected=Nenhum evento selecionado
@@ -351,6 +377,7 @@ replicatingFromMaster=Replicando a partir do mestre {0}:{2}, porta de mensagens
showWindSpeedSeries=Visualizar dados de velocidade do vento
showWindDirectionSeries=Visualizar dados de direções do vento
fleet=Flotilha
boat=Barco
boatClass=Classe de barcos
setDelayToLive=Definir atraso ao vivo
pleaseEnterNonEmptyVenue=Insira um local.
@@ -524,7 +551,6 @@ additionalUrlSettings=Configurações de URL adicionais
restrictToSingleSelectedRace=Restringir a uma única corrida selecionada
expandSelectedRace=Expandir corrida selecionada
showRaceDetails=Permitir detalhes da corrida
numberOfRaces=Número de corridas
numberOfRacesMustBeNonNegativeNumber=Insira o número das últimas corridas a serem exibidas
chooseTheWayYouSelectRaces=Selecionar a forma de seleção das corridas
selectFromAllRaces=Selecionar a partir de todas as corridas
@@ -1454,6 +1480,7 @@ plainResultsPresenter=Apresentador de resultados simples
resultsChart=Diagrama de resultados
tabbedResultsPresenter=Apresentador de resultados por fichas
polarResultsPresenter=Apresentador de resultados da carta polar
maneuverSpeedDetailsResultsPresenter=Apresentador de resultados detalhados da velocidade da manobra
dataMiningRetrieval=Obtenção de dados
actionWatch=Ver
actionAnalyze=Analisar
@@ -1463,6 +1490,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=Você quer criar um painel de classi
copyCourse=Copiar percurso
copyCompetitors=Copiar competidores
smartphoneTracking=Rastreamento do Smartphone
titelOfChooseNameDialog=Selecionar um nome
ownPrefix=Prefixo próprio
defaultName=Padrão
exampleTextForName=Seu nome é parecido com:
flightsCount={0,number} voos
flightsCount[one]={0,number} voo
viewQueryDefinition=Ver definição da consulta
@@ -1873,6 +1904,26 @@ showEstimatedDuration=Exibir duração estimada
estimatedDuration=duração estimada:
countDown=O evento começa em {0} {1}
countDownEnd=O evento irá começar dentro de alguns segundos
maneuverSpeedDetails=Detalhes da velocidade da manobra
maneuverDirectionNormalization=Normalização da direção da manobra
maneuver=Manobra
minManeuverDuration=Duração mínima da manobra (s)
maxManeuverDuration=Duração máxima da manobra (s)
minManeuverEnteringSpeedInKnots=Velocidade mínima de entrada da manobra (nós)
maxManeuverEnteringSpeedInKnots=Velocidade máxima de entrada da manobra (nós)
minManeuverExitingSpeedInKnots=Velocidade mínima de saída da manobra (nós)
maxManeuverExitingSpeedInKnots=Velocidade máxima de saída da manobra (nós)
minManeuverEnteringAbsTWA=TWA absoluto mínimo de entrada da manobra
maxManeuverEnteringAbsTWA=TWA absoluto máximo de entrada da manobra
minManeuverExitingAbsTWA=TWA absoluto mínimo de saída da manobra
maxManeuverExitingAbsTWA=TWA absoluto máximo de saída da manobra
maneuverDirectionEqualWeightingEnabled=Permitir ponderação 50%-50% para mudança de direção em agregações "valor por TWA"
minValue=Valor mínimo
maxValue=Valor máximo
zeroTo360AxisLabeling=Etiquetagem de eixo 0-360°
exportStatisticsCurveToCsv=Exportar curva de estatística para CSV
csvCopiedToClipboard=O conteúdo CSV foi copiado para o clipboard. Cole-o onde quiser.
minDataCount=Contagem de dados mínimos
moreLoginInformationHeadline=Benefícios da conexão ao SAP Sailing Analytics
moreLoginInformationIntroduction=Como usuário registrado do SAP Sailing Analytics, você tem acesso a funções que não estão abertas para usuários anônimos. Registre-se simplesmente para ter acesso às funcionalidades exibidas embaixo.
moreLoginInformationSectionUserSettingsHeading=Configurações do usuário
@@ -1918,6 +1969,7 @@ currentStbdRudderRake=Inclinação leme boreste
currentStbdRudderRakeTooltip=A inclinação atual do leme para boreste
currentMastRotationInDegree=Rotação do mastro
currentMastRotationInDegreeTooltip=A rotação atual do mastro em graus
mainCurveAnalysis=Analisar somente curva principal
finishingTime=Hora de chegada
finishTimeString=Hora de conclusão
setFinishingAndFinishTime=Definir hora de chegada e conclusão
@@ -1969,3 +2021,15 @@ totalDurationFoiledInSeconds=Total de tempo com hidrofólio
totalDistanceFoiledInMeters=Total de distância com hidrofólio
totalDurationFoiledInSecondsTooltip=Total de tempo com hidrofólio, em todo o painel de classificação
totalDistanceFoiledInMetersTooltip=Total de distância com hidrofólio, em todo o painel de classificação
threeSixtyVideoHint=Este é um vídeo de 360°, a câmera pode ser virada
processingMP4=O Mp4 é analisado (isso demorará alguns segundos)
resetStartTimeToDefault=Definir como padrão
importFullExpeditionData=Importar todos os dados do Expedition
importCanceledNoCompetitorAdded=Nenhum competidor adicionado! A importação será cancelada.
importCanceledByUser=Importação cancelada!
importFinished=Importação de dados concluída
importFinishedMessage=Dados do Expedition importados com êxito.
importFinishedGotoRaceboard=Abrir painel de corridas
importFinishedGotoEvent=Abrir evento
chooseAName=Selecionar um nome
unexpectedErrorDuringFileImport=Ocorreu um erro inesperado durante o carregamento do arquivo.
@@ -236,6 +236,32 @@ hoverOverAPoint=Наведите указатель для просмотра п
noSelection=Ничего не выбрано
raceIsKnownToStartUpwind=Гонка начинается против ветра
events=События
pairingList=Список пар
pairingLists=Списки пар
pairingListCreationInfo=Первым будет рассчитан шаблон, который содержит только номера участников и может быть применен к другим таблицам лидеров. Если число участников не делится на число лодок без остатка, в списке пар будут пустые места. \ Если число участников не равно числу зарегистрированных участников в фактической таблице лидеров, список пар не может быть применен к журналам гонки. \ Для генерирования списка пар используется число всех флайтов таблицы лидеров, не являющихся гонками на медали.
setCompetitors=Укажите число участников:
seriesHint=Выберите не менее одной серии для списка пар:
amountOfFlightRepeats=Число повторов флайта
insertIntoRegatta=Вставить в регату
recalculate=Пересчитать
csvExport=Экспорт в CSV
printView=Просмотр перед печатью
print=Печать
invalidCompetitorCount=Недопустимое число участников
invalidFlightMultiplier=Недопустимое число повторов флайта
invalidSeriesSelection=Недопустимый выбор серий
flightsMustBeAMultipleOfMultiplier=Число флайтов должно быть кратно множителю флайтов
parameters=Параметры
numberOfFlights=Число флайтов
numberOfFleets=Число гонок на флайт
numberOfCompetitors=Число участников
numberOfRaces=Число гонок
quality=Качество
pairingListTemplate=Шаблон списка пар
printHint=Печать примененной версии
blockedApplyButton=Число зарегистрированных участников не равно числу участников из списка пар!
multiplierInfo=Планируйте флайты таким образом, чтобы обеспечить соревнования с минимально возможной переменой лодок
noPairingListAvailable=Функция печати доступна только после применения списка пар к журналам гонок выбранных таблиц лидеров.
settingsForComponent={0} — параметры
noEventsFound=События не найдены
noEventSelected=Не выбрано событие
@@ -354,6 +380,7 @@ replicatingFromMaster=Репликация с главного экземпля
showWindSpeedSeries=Показать данные о скорости ветра
showWindDirectionSeries=Показать данные о направлениях ветра
fleet=Флот
boat=Лодка
boatClass=Класс лодок
setDelayToLive=Установить задержку оперативных данных
pleaseEnterNonEmptyVenue=Введите место.
@@ -527,7 +554,6 @@ additionalUrlSettings=Дополнительные параметры URL-адр
restrictToSingleSelectedRace=Ограничить одной выбранной гонкой
expandSelectedRace=Развернуть выбранную гонку
showRaceDetails=Разрешить подробности гонки
numberOfRaces=Число гонок
numberOfRacesMustBeNonNegativeNumber=Введите число последних гонок для просмотра
chooseTheWayYouSelectRaces=Выберите способ выбора гонок
selectFromAllRaces=Выбрать из всех гонок
@@ -1457,6 +1483,7 @@ plainResultsPresenter=Презентатор простых результато
resultsChart=Диаграмма результатов
tabbedResultsPresenter=Презентатор результатов со вкладками
polarResultsPresenter=Полярный презентатор результатов
maneuverSpeedDetailsResultsPresenter=Демонстратор результатов детализации скорости маневра
dataMiningRetrieval=Извлечение данных
actionWatch=Смотреть
actionAnalyze=Анализировать
@@ -1466,6 +1493,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=Создать таблицу лид
copyCourse=Копировать курс
copyCompetitors=Копировать участников
smartphoneTracking=Отслеживание смартфона
titelOfChooseNameDialog=Выберите имя
ownPrefix=Префикс
defaultName=По умолчанию
exampleTextForName=Выше имя выглядит так:
flightsCount={0,number} полетов
flightsCount[one]={0,number} полет
viewQueryDefinition=Просмотреть определение запроса
@@ -1876,6 +1907,26 @@ showEstimatedDuration=Показать оценку длительности
estimatedDuration=оценка длительности:
countDown=Начало события в {0} {1}
countDownEnd=Событие начнется через несколько секунд
maneuverSpeedDetails=Скорость маневра подробно
maneuverDirectionNormalization=Нормализация направления маневра
maneuver=Маневр
minManeuverDuration=Мин. длительность маневра (с)
maxManeuverDuration=Макс. длительность маневра (с)
minManeuverEnteringSpeedInKnots=Мин. входная скорость маневра (уз.)
maxManeuverEnteringSpeedInKnots=Макс. входная скорость маневра (уз.)
minManeuverExitingSpeedInKnots=Мин. выходная скорость маневра (уз.)
maxManeuverExitingSpeedInKnots=Макс. выходная скорость маневра (уз.)
minManeuverEnteringAbsTWA=Мин. входной абс. TWA маневра
maxManeuverEnteringAbsTWA=Макс. входной абс. TWA маневра
minManeuverExitingAbsTWA=Мин. выходной абс. TWA маневра
maxManeuverExitingAbsTWA=Макс. выходной абс. TWA маневра
maneuverDirectionEqualWeightingEnabled=Включить взвешивание 50%-50% для направления маневра в агрегациях значений по TWA
minValue=Мин. значение
maxValue=Макс. значение
zeroTo360AxisLabeling=Маркировка оси 0–360°
exportStatisticsCurveToCsv=Экспортировать кривую статистики в CSV
csvCopiedToClipboard=Содержимое CSV скопировано в буфер обмена. Вставьте его в нужном месте.
minDataCount=Мин. число данных
moreLoginInformationHeadline=Преимущества регистрации в SAP Sailing Analytics
moreLoginInformationIntroduction=Зарегистрированные пользователи SAP Sailing Analytics имеют доступ к функциям, которые закрыты для анонимных пользователей. Зарегистрируйтесь, чтобы получить доступ к перечисленным ниже функциям.
moreLoginInformationSectionUserSettingsHeading=Настройки пользователя
@@ -1921,6 +1972,7 @@ currentStbdRudderRake=Скос задней кромки руля на прав
currentStbdRudderRakeTooltip=Текущий скос задней кромки руля на правый борт
currentMastRotationInDegree=Вращение мачты
currentMastRotationInDegreeTooltip=Текущее значение вращения мачты в градусах
mainCurveAnalysis=Анализировать только основную кривую
finishingTime=Время финиширования
finishTimeString=Время финиша
setFinishingAndFinishTime=Указать время финиширования и финиша
@@ -1972,3 +2024,15 @@ totalDurationFoiledInSeconds=Общее время в крыльевом реж
totalDistanceFoiledInMeters=Общая дистанция в крыльевом режиме
totalDurationFoiledInSecondsTooltip=Общее время в крыльевом режиме, по всей таблице лидеров
totalDistanceFoiledInMetersTooltip=Общая дистанция в крыльевом режиме, по всей таблице лидеров
threeSixtyVideoHint=Это панорамное видео, камеру можно повернуть
processingMP4=Анализ Mp4 (это займет несколько секунд)
resetStartTimeToDefault=Установить по умолчанию
importFullExpeditionData=Импортировать полные данные Expedition
importCanceledNoCompetitorAdded=Не добавлено ни одного участника! Импорт будет отменен.
importCanceledByUser=Импорт отменен!
importFinished=Импорт данных завершен
importFinishedMessage=Данные Expedition успешно импортированы.
importFinishedGotoRaceboard=Открыть таблицу гонки
importFinishedGotoEvent=Открыть событие
chooseAName=Выберите имя
unexpectedErrorDuringFileImport=При отправке файла возникла непредвиденная ошибка.
@@ -236,6 +236,32 @@ hoverOverAPoint=将鼠标移到得分,查看详情
noSelection=无选择
raceIsKnownToStartUpwind=比赛轮次从迎风航段开始
events=活动
pairingList=配对清单
pairingLists=配对清单
pairingListCreationInfo=首先,将计算仅包含参赛队数并且可以应用到其他积分榜的模板。如果参赛队数量无法被船只数量除尽,则在配对清单中输入空占位符。\ 此外,如果参赛队数量不等于实际积分榜中注册的参赛队数量,配对清单无法应用到比赛轮次日志。\ 用于生成配对清单的航程数由积分榜中不是奖牌轮的所有航程确定。
setCompetitors=请设置参赛队数量:
seriesHint=请选择一场或多场应位于配对清单的系列赛:
amountOfFlightRepeats=航程重复次数
insertIntoRegatta=插入比赛
recalculate=重新计算
csvExport=导出为 CSV
printView=打印预览
print=打印
invalidCompetitorCount=参赛队数量无效
invalidFlightMultiplier=航程重复无效
invalidSeriesSelection=系列赛选择无效
flightsMustBeAMultipleOfMultiplier=航程需要是航程乘数的倍数
parameters=参数
numberOfFlights=航程数
numberOfFleets=各航程的比赛轮次数
numberOfCompetitors=参赛队数
numberOfRaces=比赛轮次数
quality=质量
pairingListTemplate=配对清单模板
printHint=打印应用的版本
blockedApplyButton=注册的参赛队不等于配对清单中的参赛队!
multiplierInfo=多个航程,彼此相邻,这样就可以减少船只更换情况进行比赛
noPairingListAvailable=打印功能仅在配对清单可应用于选择的积分榜比赛轮次日志时可用。
settingsForComponent={0}设置
noEventsFound=未找到活动
noEventSelected=未选择活动
@@ -354,6 +380,7 @@ replicatingFromMaster=正在从主服务器{0}:{2}、消息传送端口{3}:{
showWindSpeedSeries=显示风速数据
showWindDirectionSeries=显示风向数据
fleet=船队
boat=船只
boatClass=船只级别
setDelayToLive=设置实况延迟
pleaseEnterNonEmptyVenue=请输入场地。
@@ -527,7 +554,6 @@ additionalUrlSettings=附加 URL 设置
restrictToSingleSelectedRace=限制为单个选择的比赛轮次
expandSelectedRace=展开选择的比赛轮次
showRaceDetails=允许比赛轮次详情
numberOfRaces=比赛轮次数
numberOfRacesMustBeNonNegativeNumber=请输入要显示的最后比赛轮次的数量
chooseTheWayYouSelectRaces=选择选取比赛轮次的方式
selectFromAllRaces=从所有比赛轮次中选择
@@ -1457,6 +1483,7 @@ plainResultsPresenter=纯结果展示区
resultsChart=结果记录
tabbedResultsPresenter=选项卡式结果展示区
polarResultsPresenter=极坐标结果展示区
maneuverSpeedDetailsResultsPresenter=操作速度详细结果展示区
dataMiningRetrieval=数据检索
actionWatch=观看
actionAnalyze=分析
@@ -1466,6 +1493,10 @@ doYouWantToCreateADefaultRegattaLeaderboard=是否确认默认的比赛积分榜
copyCourse=复制场地
copyCompetitors=复制参赛队
smartphoneTracking=智能手机跟踪
titelOfChooseNameDialog=选择名称
ownPrefix=自己的前缀
defaultName=默认值
exampleTextForName=名称如下所示:
flightsCount={0,number} 个航程
flightsCount[one]={0,number} 个航程
viewQueryDefinition=查看查询定义
@@ -1876,6 +1907,26 @@ showEstimatedDuration=显示预计持续时间
estimatedDuration=预计持续时间:
countDown=活动于{0} {1}开始
countDownEnd=活动将在数秒后开始
maneuverSpeedDetails=操作速度详情
maneuverDirectionNormalization=操作方向规范化
maneuver=操作
minManeuverDuration=最短操作持续时间 (s)
maxManeuverDuration=最长操作持续时间 (s)
minManeuverEnteringSpeedInKnots=最小操作驶入速度 (kts)
maxManeuverEnteringSpeedInKnots=最大操作驶入速度 (kts)
minManeuverExitingSpeedInKnots=最小操作驶出速度 (kts)
maxManeuverExitingSpeedInKnots=最大操作驶出速度 (kts)
minManeuverEnteringAbsTWA=最小操作驶入绝对实际风向角
maxManeuverEnteringAbsTWA=最大操作驶入绝对实际风向角
minManeuverExitingAbsTWA=最小操作驶出绝对实际风向角
maxManeuverExitingAbsTWA=最大操作驶出绝对实际风向角
maneuverDirectionEqualWeightingEnabled=以“各实际风向角的值”汇总为操作方向启用 50%-50% 加权
minValue=最小值
maxValue=最大值
zeroTo360AxisLabeling=0-360° 轴标签
exportStatisticsCurveToCsv=将统计曲线导出到 CSV
csvCopiedToClipboard=CSV 内容已复制到剪贴板。将其粘贴在需要的任何地方。
minDataCount=最小数据数
moreLoginInformationHeadline=注册 SAP Sailing Analytics 的优势
moreLoginInformationIntroduction=作为 SAP Sailing Analytics 的注册用户,您可以访问尚未对匿名用户开放的功能。注册即可访问以下显示的功能。
moreLoginInformationSectionUserSettingsHeading=用户设置
@@ -1921,6 +1972,7 @@ currentStbdRudderRake=右舵倾斜度
currentStbdRudderRakeTooltip=当前右舵倾斜度
currentMastRotationInDegree=桅杆旋转度
currentMastRotationInDegreeTooltip=当前桅杆旋转度数
mainCurveAnalysis=仅分析主曲线
finishingTime=结束时间
finishTimeString=终点线时间
setFinishingAndFinishTime=设置结束和终点线时间
@@ -1972,3 +2024,15 @@ totalDurationFoiledInSeconds=水翼腾空总时间
totalDistanceFoiledInMeters=水翼腾空总距离
totalDurationFoiledInSecondsTooltip=水翼腾空总时间(在整个积分榜中)
totalDistanceFoiledInMetersTooltip=水翼腾空总距离(在整个积分榜中)
threeSixtyVideoHint=这是 360° 视频,相机可以转动
processingMP4=分析 Mp4(将需要几秒钟)
resetStartTimeToDefault=设为默认值
importFullExpeditionData=导入全部导航图数据
importCanceledNoCompetitorAdded=未添加参赛队!导入将被取消。
importCanceledByUser=导入已取消!
importFinished=已完成数据导入
importFinishedMessage=已成功导入导航图数据。
importFinishedGotoRaceboard=打开比赛板
importFinishedGotoEvent=打开活动
chooseAName=选择名称
unexpectedErrorDuringFileImport=文件上传期间发生意外错误。
@@ -19,6 +19,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.shiro.SecurityUtils;
import org.mp4parser.IsoFile;
import org.mp4parser.boxes.UserBox;
import org.mp4parser.boxes.iso14496.part12.MovieBox;
@@ -36,13 +37,11 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.VideoMetadataDTO;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
import com.sap.sailing.domain.common.security.Permission.Mode;
import com.sap.sailing.gwt.ui.client.MediaService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.User;
public class MediaServiceImpl extends RemoteServiceServlet implements MediaService {
@@ -51,19 +50,14 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
private static final int METADATA_CONNECTION_TIMEOUT = 10000;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
private ServiceTracker<RacingEventService, RacingEventService> racingEventServiceTracker;
private ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private static final int REQUIRED_SIZE = 1000000;
private static final long serialVersionUID = -8917349579281305977L;
public MediaServiceImpl() {
super();
BundleContext context = Activator.getDefault();
securityServiceTracker = new ServiceTracker<>(context, SecurityService.class, /* customizer */ null);
securityServiceTracker.open();
racingEventServiceTracker = new ServiceTracker<RacingEventService, RacingEventService>(context,
RacingEventService.class.getName(), null);
racingEventServiceTracker.open();
@@ -89,19 +83,7 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
}
private void ensureUserCanManageMedia() {
SecurityService service = securityServiceTracker.getService();
if (service == null) {
throw new IllegalStateException("SecurityService not initialized");
}
User user = service.getCurrentUser();
if (user == null) {
throw new IllegalStateException("User is missing permission to MANAGER_MEDIA");
}
boolean hasPermission = user.hasPermission(Permission.MANAGE_MEDIA.getStringPermission(),
SailingPermissionsForRoleProvider.INSTANCE);
if (!hasPermission) {
throw new IllegalStateException("User is missing permission to MANAGER_MEDIA");
}
SecurityUtils.getSubject().checkPermission(Permission.MANAGE_MEDIA.getStringPermissionForObjects(Mode.UPDATE));
}
@Override
@@ -6,6 +6,7 @@ import java.io.StringWriter;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
@@ -16,6 +17,8 @@ import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
@@ -51,6 +54,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMa
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.OpenEndedDeviceMappingFinder;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
@@ -62,7 +66,9 @@ import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CompetitorWithBoatImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.DeviceIdentifier;
@@ -113,6 +119,7 @@ import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseJsonSe
import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer;
import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer;
import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorWithBoatJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.FlatGPSFixJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.MarkJsonSerializerWithPosition;
import com.sap.sse.InvalidDateException;
@@ -1086,6 +1093,117 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
}
/**
* @return the actual or anticipated start order for the race identified by {@code raceColumnName}, {@code fleetName}.
* Those competitors for which a start mark passing is already known are sorted by those start mark passings. All other
* boats are ordered by their geometric distance from the start line or the windward distance from the start mark
* if the start for some reason is defined by a single mark. See {@link #compareDistanceFromStartLine(Competitor, Competitor)}.
*/
@GET
@Produces("application/json;charset=UTF-8")
@Path("{leaderboardName}/startorder")
public Response getStartOrder(@PathParam("leaderboardName") String leaderboardName,
@QueryParam(RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME) String raceColumnName,
@QueryParam(RaceLogServletConstants.PARAMS_RACE_FLEET_NAME) String fleetName) {
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.")
.type(MediaType.TEXT_PLAIN).build();
}
RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
if (raceColumn == null) {
return Response
.status(Status.NOT_FOUND)
.entity("Could not find a race column '" + StringEscapeUtils.escapeHtml(raceColumnName) + "' in leaderboard '"
+ StringEscapeUtils.escapeHtml(leaderboardName) + "'.").type(MediaType.TEXT_PLAIN).build();
}
Fleet fleet = raceColumn.getFleetByName(fleetName);
if (fleet == null) {
return Response
.status(Status.NOT_FOUND)
.entity("Could not find a fleet '" + StringEscapeUtils.escapeHtml(fleetName) + "' in raceColumn '"
+ StringEscapeUtils.escapeHtml(raceColumnName) + "'.").type(MediaType.TEXT_PLAIN).build();
}
final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a tracked race for raceColumn '" + StringEscapeUtils.escapeHtml(raceColumnName)
+ " and fleet '" + StringEscapeUtils.escapeHtml(fleetName) + "'.").type(MediaType.TEXT_PLAIN)
.build();
};
Course course = trackedRace.getRace().getCourse();
final List<Competitor> competitors = new ArrayList<>();
final Waypoint firstWaypoint = course.getFirstWaypoint();
final TimePoint timeToUseForStart;
if (trackedRace.getStartOfRace() != null) {
timeToUseForStart = trackedRace.getStartOfRace();
} else {
timeToUseForStart = MillisecondsTimePoint.now();
}
if (firstWaypoint != null) {
final List<Position> startWaypointMarkPositions =
StreamSupport.stream(firstWaypoint.getMarks().spliterator(), /* parallel */ false).
map(mark->trackedRace.getTrack(mark)).filter(markTrack->markTrack!=null).
map(markTrack->markTrack.getEstimatedPosition(timeToUseForStart, /* extrapolate */ false)).
collect(Collectors.toList());
Util.addAll(trackedRace.getRace().getCompetitors(), competitors);
competitors.sort((a, b)->{
final MarkPassing aStartMarkPassing = trackedRace.getMarkPassing(a, firstWaypoint);
final MarkPassing bStartMarkPassing = trackedRace.getMarkPassing(b, firstWaypoint);
final int result;
if (aStartMarkPassing == null) {
if (bStartMarkPassing == null) {
result = compareDistanceFromStartLine(trackedRace, startWaypointMarkPositions, timeToUseForStart, a, b);
} else {
result = 1; // b consider less than a because it has a start mark passing and therefore is assumed to have started before a
}
} else if (bStartMarkPassing == null) {
result = -1; // a consider less than b because it has a start mark passing and therefore is assumed to have started before b
} else {
// both have a start mark passing; compare time points
result = aStartMarkPassing.getTimePoint().compareTo(bStartMarkPassing.getTimePoint());
}
return result;
});
}
CompetitorWithBoatJsonSerializer serializer = new CompetitorWithBoatJsonSerializer();
JSONArray result = new JSONArray();
for (final Competitor c : competitors) {
Boat boat = trackedRace.getBoatOfCompetitor(c);
JSONObject jsonCompetitor = serializer.serialize(new CompetitorWithBoatImpl(c, (DynamicBoat) boat));
result.add(jsonCompetitor);
}
String json = result.toJSONString();
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
}
private int compareDistanceFromStartLine(TrackedRace trackedRace, Iterable<Position> startWaypointMarkPositions,
TimePoint timeToUseForStart, Competitor a, Competitor b) {
final Position aPos = trackedRace.getTrack(a).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
final Position bPos = trackedRace.getTrack(b).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
final Distance aDist = aPos==null?null:getDistanceFromStartWaypoint(aPos, startWaypointMarkPositions);
final Distance bDist = bPos==null?null:getDistanceFromStartWaypoint(bPos, startWaypointMarkPositions);
return Comparator.<Distance>nullsLast(Comparator.naturalOrder()).compare(aDist, bDist);
}
private Distance getDistanceFromStartWaypoint(Position pos, Iterable<Position> startWaypointMarkPositions) {
final Distance result;
if (Util.isEmpty(startWaypointMarkPositions)) {
result = null;
} else if (Util.size(startWaypointMarkPositions) == 1) {
// single mark start; strange, but possible:
result = startWaypointMarkPositions.iterator().next().getDistance(pos);
} else {
final Position first = Util.get(startWaypointMarkPositions, 0);
final Position second = Util.get(startWaypointMarkPositions, 1);
result = pos.getDistanceToLine(first, second).abs();
}
return result;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{leaderboardName}/marks/{markId}")
@@ -3,7 +3,6 @@ package com.sap.sailing.server.gateway.jaxrs.api;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -14,8 +13,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
@@ -46,13 +43,11 @@ import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorWithBoatImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.SpeedWithBearing;
@@ -68,7 +63,6 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -1074,103 +1068,6 @@ public class RegattasResource extends AbstractSailingServerResource {
return response;
}
/**
* @return the actual or anticipated start order for the race identified by {@coode regattaName} and {@code raceName}.
* Those competitors for which a start mark passing is already known are sorted by those start mark passings. All other
* boats are ordered by their geometric distance from the start line or the windward distance from the start mark
* if the start for some reason is defined by a single mark. See {@link #compareDistanceFromStartLine(Competitor, Competitor)}.
*/
@GET
@Produces("application/json;charset=UTF-8")
@Path("{regattaname}/races/{racename}/startorder")
public Response getStartOrder(@PathParam("regattaname") String regattaName, @PathParam("racename") String raceName) {
Response response;
Regatta regatta = findRegattaByName(regattaName);
if (regatta == null) {
response = Response.status(Status.NOT_FOUND)
.entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
.build();
} else {
RaceDefinition race = findRaceByName(regatta, raceName);
if (race == null) {
response = Response.status(Status.NOT_FOUND)
.entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
.build();
} else {
final TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
Course course = trackedRace.getRace().getCourse();
final List<Competitor> competitors = new ArrayList<>();
final Waypoint firstWaypoint = course.getFirstWaypoint();
final TimePoint timeToUseForStart;
if (trackedRace.getStartOfRace() != null) {
timeToUseForStart = trackedRace.getStartOfRace();
} else {
timeToUseForStart = MillisecondsTimePoint.now();
}
if (firstWaypoint != null) {
final List<Position> startWaypointMarkPositions =
StreamSupport.stream(firstWaypoint.getMarks().spliterator(), /* parallel */ false).
map(mark->trackedRace.getTrack(mark)).filter(markTrack->markTrack!=null).
map(markTrack->markTrack.getEstimatedPosition(timeToUseForStart, /* extrapolate */ false)).
collect(Collectors.toList());
Util.addAll(trackedRace.getRace().getCompetitors(), competitors);
competitors.sort((a, b)->{
final MarkPassing aStartMarkPassing = trackedRace.getMarkPassing(a, firstWaypoint);
final MarkPassing bStartMarkPassing = trackedRace.getMarkPassing(b, firstWaypoint);
final int result;
if (aStartMarkPassing == null) {
if (bStartMarkPassing == null) {
result = compareDistanceFromStartLine(trackedRace, startWaypointMarkPositions, timeToUseForStart, a, b);
} else {
result = 1; // b consider less than a because it has a start mark passing and therefore is assumed to have started before a
}
} else if (bStartMarkPassing == null) {
result = -1; // a consider less than b because it has a start mark passing and therefore is assumed to have started before b
} else {
// both have a start mark passing; compare time points
result = aStartMarkPassing.getTimePoint().compareTo(bStartMarkPassing.getTimePoint());
}
return result;
});
}
CompetitorWithBoatJsonSerializer serializer = new CompetitorWithBoatJsonSerializer();
JSONArray result = new JSONArray();
for (final Competitor c : competitors) {
Boat boat = trackedRace.getBoatOfCompetitor(c);
JSONObject jsonCompetitor = serializer.serialize(new CompetitorWithBoatImpl(c, (DynamicBoat) boat));
result.add(jsonCompetitor);
}
String json = result.toJSONString();
return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build();
}
}
return response;
}
private int compareDistanceFromStartLine(TrackedRace trackedRace, Iterable<Position> startWaypointMarkPositions,
TimePoint timeToUseForStart, Competitor a, Competitor b) {
final Position aPos = trackedRace.getTrack(a).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
final Position bPos = trackedRace.getTrack(b).getEstimatedPosition(timeToUseForStart, /* extrapolate */ true);
final Distance aDist = aPos==null?null:getDistanceFromStartWaypoint(aPos, startWaypointMarkPositions);
final Distance bDist = bPos==null?null:getDistanceFromStartWaypoint(bPos, startWaypointMarkPositions);
return Comparator.<Distance>nullsLast(Comparator.naturalOrder()).compare(aDist, bDist);
}
private Distance getDistanceFromStartWaypoint(Position pos, Iterable<Position> startWaypointMarkPositions) {
final Distance result;
if (Util.isEmpty(startWaypointMarkPositions)) {
result = null;
} else if (Util.size(startWaypointMarkPositions) == 1) {
// single mark start; strange, but possible:
result = startWaypointMarkPositions.iterator().next().getDistance(pos);
} else {
final Position first = Util.get(startWaypointMarkPositions, 0);
final Position second = Util.get(startWaypointMarkPositions, 1);
result = pos.getDistanceToLine(first, second).abs();
}
return result;
}
@GET
@Produces("application/json;charset=UTF-8")
@Path("{regattaname}/races")
@@ -185,6 +185,10 @@ name to make sure you get to the event you're interested in.
<td><a href="leaderboardRaceMarksGetDoc.html">/api/v1/leaderboards/{name}/marks</a></td>
<td>Gets the marks of a race (from the RaceLog and if possible the TrackedRace)</td>
</tr>
<tr>
<td><a href="leaderboardRaceStartorderGetDoc.html">/api/v1/leaderboards/{name}/startorder</a></td>
<td>Gets the order in which competitors have started or are expected to start for a race</td>
</tr>
<tr>
<td><a href="leaderboardRaceSetTrackingTimes.html">/api/v1/leaderboards/{name}/settrackingtimes</a></td>
<td>Modifies the race's tracking interval</td>
@@ -217,10 +221,6 @@ name to make sure you get to the event you're interested in.
<td><a href="competitorTeamImagePostDoc.html">/api/v1/competitors/{id}/team/image</a></td>
<td>Sets the team image</td>
</tr>
<tr>
<td><a href="startorderGetDoc.html">/api/v1/regattas/{regattaname}/races/{racename}/startorder</a></td>
<td>Gets the order in which competitors have started or are expected to start</td>
</tr>
<tr>
<td><a href="maneuversGetDoc.html">/api/v1/regattas/{regattaname}/races/{racename}/maneuvers</a></td>
<td>Gets all maneuvers performed by all competitors of a race</td>
@@ -9,10 +9,10 @@
</head>
<body>
<h1>SAP Sailing Analytics Webservices API Version 1.0</h1>
<h2>URL: /api/v1/regattas/{regattaname}/races/{racename}/startorder</h2>
<h2>URL: /api/v1/leaderboards/{name}/startorder?race_column={name}&amp;fleet={name}</h2>
<b>Description:</b>
<p>Gets the order in which competitors have started or are expected to start. The output
<p>Gets the order in which competitors have started or are expected to start for a race. The output
is a JSON array that contains the race competitors in the order in which they have passed
the start waypoint or are expected to do so. Those competitors for which a start mark
passing is already known are sorted by those start mark passings. All other
@@ -31,7 +31,8 @@
</tr>
<tr>
<td>Mandatory parameters:</td>
<td>None</td>
<td>race_column
<br/>fleet</td>
</tr>
<tr>
<td>Optional parameters:</td>
@@ -43,7 +44,7 @@
</tr>
<tr>
<td>Example:</td>
<td><a href="https://dev.sapsailing.com/sailingserver/api/v1/regattas/ESS%202016%20Cardiff/races/Race%2016/startorder">https://dev.sapsailing.com/sailingserver/api/v1/regattas/ESS%202016%20Cardiff/races/Race%2016/startorder</a></td>
<td><a href="https://dev.sapsailing.com/sailingserver/api/v1/leaderboards/ESS%202016%20Cardiff/startorder?race_column=R1&fleet=Default">https://dev.sapsailing.com/sailingserver/api/v1/leaderboards/ESS%202016%20Cardiff/startorder?race_column=R1&fleet=Default</a></td>
</tr>
</table>
<div style="height: 1em;"></div>
@@ -41,6 +41,8 @@ import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
@@ -88,14 +90,28 @@ public class StatisticsTest {
regatta.addTrackedRace(trackedRace);
}
private TrackedRaceStatisticsCacheImpl getStatisticsCacheWithRegattaAdded() {
private TrackedRaceStatisticsCacheImpl getStatisticsCacheWithRegattaAdded() throws Exception {
TrackedRaceStatisticsCacheImpl trackedRaceStatisticsCache = new TrackedRaceStatisticsCacheImpl();
trackedRaceStatisticsCache.regattaAdded(regatta);
// The following lines ensure that we received all necessary events from the TrackedRegatta
// When removing a listener we get a Future whose get method will block until all previously triggered events are processed.
RaceListener raceListener = new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {
}
@Override
public void raceAdded(TrackedRace trackedRace) {
}
};
regatta.addRaceListener(raceListener);
regatta.removeRaceListener(raceListener).get();
return trackedRaceStatisticsCache;
}
@Test
public void testTrackedRaceStatisticsCacheWithoutFixes() {
public void testTrackedRaceStatisticsCacheWithoutFixes() throws Exception {
TrackedRaceStatisticsCacheImpl trackedRaceStatisticsCache = getStatisticsCacheWithRegattaAdded();
TrackedRaceStatistics statisticsForRace = trackedRaceStatisticsCache.getStatisticsWaitingForLatest(trackedRace);
@@ -105,7 +121,7 @@ public class StatisticsTest {
}
@Test
public void testTrackedRaceStatisticsCacheWithFixes() {
public void testTrackedRaceStatisticsCacheWithFixes() throws Exception {
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295970, 8.638958), new MillisecondsTimePoint(START_OF_RACE),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
@@ -165,5 +181,4 @@ public class StatisticsTest {
double distanceInMeters = statisticsForRace.getDistanceTraveled().getMeters();
assertTrue(distanceInMeters > 53 && distanceInMeters < 57);
}
}
@@ -9,9 +9,6 @@
<feature url="features/target-jms/com.sap.sailing.target.jms_1.0.0.jar" id="com.sap.sailing.target.jms" version="1.0.0">
<category name="RaceAnalysisTarget"/>
</feature>
<feature url="features/target-jsp/com.sap.sailing.target.jsp_1.0.0.jar" id="com.sap.sailing.target.jsp" version="1.0.0">
<category name="RaceAnalysisTarget"/>
</feature>
<feature url="features/target-jackson/com.sap.sailing.target.jackson_1.0.0.jar" id="com.sap.sailing.target.jackson" version="1.0.0">
<category name="RaceAnalysisTarget"/>
</feature>
@@ -7,7 +7,7 @@
<unit id="com.sap.sailing.target.shiro.feature.group" version="1.0.0"/>
<unit id="com.sap.sailing.target.test.feature.group" version="1.0.0"/>
<unit id="com.sap.sailing.target.jackson.feature.group" version="1.0.0"/>
<repository location="http://p2.sapsailing.com/p2/sailing/"/>
<repository location="https://p2.sapsailing.com/p2/sailing/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="slicer" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.jetty.bundles.f.feature.group" version="9.2.2.201407241931"/>
@@ -17,8 +17,6 @@ import com.sap.sse.common.NamedWithID;
import com.sap.sse.common.WithID;
import com.sap.sse.security.shared.Account;
import com.sap.sse.security.shared.Account.AccountType;
import com.sap.sse.security.shared.PermissionsForRoleProvider;
import com.sap.sse.security.shared.WildcardPermission;
public class User implements NamedWithID {
private static final long serialVersionUID = 1788215575606546042L;
@@ -271,21 +269,4 @@ public class User implements NamedWithID {
return validationSecret;
}
public boolean hasPermission(String stringPermission, PermissionsForRoleProvider provider) {
WildcardPermission requested = new WildcardPermission(stringPermission);
for (String permission : getPermissions()) {
if (new WildcardPermission(permission).implies(requested)) {
return true;
}
}
for (String role : getRoles()) {
for (String permission : provider.getPermissions(role)) {
if (new WildcardPermission(permission).implies(requested)) {
return true;
}
}
}
return false;
}
}
@@ -52,6 +52,7 @@ public class UniqueIPsPerReferrer {
private static final Logger logger = Logger.getLogger(UniqueIPsPerReferrer.class.getName());
private static final String HOSTNAME_FILE_EXTENSION = ".ips";
private static final String UNIQUE_SUFFIX = ".unique";
private static final String MONTH_AND_YEAR_TOTALS_SUFFIX = "_totals";
private static final char YEAR_MONTH_SEPARATOR = '_';
private final File CACHE;
private final File VISITED_FILES;
@@ -160,6 +161,8 @@ public class UniqueIPsPerReferrer {
private void computePerMonthPerYearPerEventAndTotals() throws IOException, ParseException {
final Map<String, Writer> monthFileWritersPerFileBaseName = new HashMap<>();
final Map<String, Writer> yearFileWritersPerFileBaseName = new HashMap<>();
final Map<String, Writer> monthTotalsFileWritersPerFileBaseName = new HashMap<>();
final Map<String, Writer> yearTotalsFileWritersPerFileBaseName = new HashMap<>();
final Writer eventTotalsWriter = new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(EVENTTOTALS)));
final Writer totalsWriter = new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(TOTALS)));
for (final File perHostnameFile : getAllHostnameFiles()) {
@@ -170,16 +173,22 @@ public class UniqueIPsPerReferrer {
String line;
while ((line=r.readLine()) != null) {
final PerHostnameEntry entry = new PerHostnameEntry(line);
final String combinedLine = hostname+" "+line+"\n";
if (entry.getYear() != 0) {
final String monthFileBasename = String.format("%04d"+YEAR_MONTH_SEPARATOR+"%02d", entry.getYear(), entry.getZeroBasedMonth()+1);
final Writer monthFileWriter = getFileWriter(monthFileBasename, monthFileWritersPerFileBaseName, this::getMonthFileCompressed, /* gzipCompressed */ true, /* append */ false);
final String combinedLine = hostname+" "+line+"\n";
monthFileWriter.write(combinedLine);
final String monthTotalsFileBasename = monthFileBasename+MONTH_AND_YEAR_TOTALS_SUFFIX;
final Writer monthTotalsFileWriter = getFileWriter(monthTotalsFileBasename, monthTotalsFileWritersPerFileBaseName, this::getMonthFileCompressed, /* gzipCompressed */ true, /* append */ false);
monthTotalsFileWriter.write(line+"\n");
final String yearFileBasename = String.format("%04d", entry.getYear());
final Writer yearFileWriter = getFileWriter(yearFileBasename, yearFileWritersPerFileBaseName, this::getYearFileCompressed, /* gzipCompressed */ true, /* append */ false);
yearFileWriter.write(combinedLine);
final String yearTotalsFileBasename = yearFileBasename+MONTH_AND_YEAR_TOTALS_SUFFIX;
final Writer yearTotalsFileWriter = getFileWriter(yearTotalsFileBasename, yearTotalsFileWritersPerFileBaseName, this::getYearFileCompressed, /* gzipCompressed */ true, /* append */ false);
yearTotalsFileWriter.write(line+"\n");
}
eventTotalsWriter.write(hostname+" "+line+"\n");
eventTotalsWriter.write(combinedLine);
totalsWriter.write(line+"\n");
}
} finally {
@@ -192,6 +201,12 @@ public class UniqueIPsPerReferrer {
for (final Writer yearFileWriter : yearFileWritersPerFileBaseName.values()) {
yearFileWriter.close();
}
for (final Writer monthTotalsFileWriter : monthTotalsFileWritersPerFileBaseName.values()) {
monthTotalsFileWriter.close();
}
for (final Writer yearTotalsFileWriter : yearTotalsFileWritersPerFileBaseName.values()) {
yearTotalsFileWriter.close();
}
eventTotalsWriter.close();
totalsWriter.close();
}
@@ -249,9 +264,21 @@ public class UniqueIPsPerReferrer {
}
private void countTotalHits() throws IOException {
logger.info("Counting total number of unique visitors");
final FileWriter totalsCountWriter = new FileWriter(TOTALS_UNIQUE);
final Set<String> uniqueTotalLines = readDistinctLinesFromGzippedFile(TOTALS);
logger.info("Counting total numbers of unique visitors for all, months, and years");
countUniqueTotals(TOTALS, TOTALS_UNIQUE);
for (final File monthGzippedTotals : MONTHS.listFiles((dir, filename)->filename.endsWith(MONTH_AND_YEAR_TOTALS_SUFFIX+GZIP_EXTENSION))) {
countUniqueTotals(monthGzippedTotals, new File(monthGzippedTotals.getParentFile(),
monthGzippedTotals.getName().substring(0, monthGzippedTotals.getName().length()-GZIP_EXTENSION.length())+UNIQUE_SUFFIX));
}
for (final File yearGzippedTotals : YEARS.listFiles((dir, filename)->filename.endsWith(MONTH_AND_YEAR_TOTALS_SUFFIX+GZIP_EXTENSION))) {
countUniqueTotals(yearGzippedTotals, new File(yearGzippedTotals.getParentFile(),
yearGzippedTotals.getName().substring(0, yearGzippedTotals.getName().length()-GZIP_EXTENSION.length())+UNIQUE_SUFFIX));
}
}
private void countUniqueTotals(File gzippedEntriesWithoutHostname, File uniqueCount) throws IOException {
final FileWriter totalsCountWriter = new FileWriter(uniqueCount);
final Set<String> uniqueTotalLines = readDistinctLinesFromGzippedFile(gzippedEntriesWithoutHostname);
totalsCountWriter.write(uniqueTotalLines.size()+"\n");
totalsCountWriter.close();
}
+7 -7
View File
@@ -12,13 +12,13 @@
The edit dialog (open with the pencil) should always be closed if a warning (yellow or red) will be displayed. In case of a red warning, the publish button is always disabled.
One device will be called **A** and the other **B**, so they are have unique names while testing.
One device will be called **A** and the other **B**, so they have unique names while testing.
## While starting
### Test 1
* devices open the penalty fragment
* device A give Omar Air OSC, device B set DNS for Omar Air
* device A give Omar Air OCS, device B set DNS for Omar Air
* device A closes the penalty view (without publishing)
* device B should see a red warning sign (without active publish button) after the automatic refresh
@@ -32,7 +32,7 @@ One device will be called **A** and the other **B**, so they are have unique nam
### Test 4
* both devices open the penalty fragment
* device A give Omar Air OSC, device B set for Alinghi the value DNS
* device A gives Omar Air OCS, device B sets DNS for Alinghi
* device A closes the penalty view (without publishing)
* device B should see both entries in the list after refresh
@@ -42,20 +42,20 @@ One device will be called **A** and the other **B**, so they are have unique nam
### Test 6
* same as [test 4](#test-scenarios_while-starting_test-4), but after refresh device B should publish the merged result
* after the refresh device A also see both entries
* after the refresh device A also sees both entries
## While finishing
### Test 7
* both devices open result list
* device A add Omar Air, Alinghi and LR BAR into the list
* device A adds Omar Air, Alinghi and LR BAR into the list
* device A closes the result list
* after refresh device B see the three competitors in the result list
### Test 8
* both devices open result list
* both devices add Omar Air to the result list
* device A set the penalty to OSC and closes the result list
* device A sets the penalty to OCS and closes the result list
* device B should see after the refresh a yellow warning sign
### Test 9
@@ -68,7 +68,7 @@ One device will be called **A** and the other **B**, so they are have unique nam
### Test 10
* both devices open result list
* both devices add Omar Air to the result list
* device A changes to penalty view and set the value to DNF and changes back to result list
* device A changes to penalty view and sets the value to DNF and changes back to result list
* device B should see a yellow warning sign after refresh
### Test 11
@@ -1,38 +1,48 @@
This page descrips how to manage the media content like images for the events at www.sapsailing.com, providing a guidance based on user's best experience. For information about where to get media content itself, please refer to the [[media|wiki/events/Sailing-events-media-content]] page.
This page descrips how to manage the media content like images and videos for the events on www.sapsailing.com, providing a guidance based on user's best experiences. For information about where to get media content itself, please refer to the [[media|wiki/events/Sailing-events-media-content]] page.
[[_TOC_]]
# Images
## Image types and their impact
There are four image types which can be added to an event carrying different roles:
There are four image types which can be added to an event where they carry different roles:
* **logo:** the sailing event or league logo which gets displayed e.g. in the upper left corner next to the name of the sailing event.
* **stage:** used as a banner for the sailing event and gets displayed e.g. on the landing page.
* **teaser:** used to give a preview about the sailing event and gets displayed e.g. in the event overview where all events are grouped by years.
* **galery:** representing the images which are displayed under the _media_ tab of each event.
* **Logo:** the sailing event or league logo which gets displayed e.g. in the upper left corner next to the name of the sailing event.
* **Stage:** used as a banner for the sailing event and gets displayed e.g. on the landing page.
* **Teaser:** used to give a preview about the sailing event and gets displayed e.g. in the event overview where all events are grouped by years.
* **Gallery:** representing the images which are displayed under the _media_ tab of each event.
## Scale guidelines for several purposes
For performance reasons, images should be scaled before uploading them. The following image resolutions showed up as good manner:
* **logo:** about 150 x 150 pixel (file size < 100 kB); take a .png file with transparent background!
* **teaser:** about 640 x 480 pixel (file size < 100 kB)
* **stage:** about 1800 x 500 pixel (file size < 500 kB)
* **gallery:** about 1400 x 1000 pixel (file size < 350 kB)
* **logo.png:** about 150 x 150 pixel (file size < 100 kB)
* **teaser.jpeg:** about 640 x 480 pixel (file size < 100 kB)
* **stage.jpeg:** about 1800 x 500 pixel (file size < 500 kB)
* **gallery.jpeg:** about 1400 x 1000 pixel (file size < 350 kB)
Note: the _logo_ requires the .png file format with transparent background. _Teaser_, _stage_ and _gallery_ images require the .jpg (.jpeg) file format.
## S3 folder structure
Before uploading the images an appropirate folder needs to be created at the S3 storage. For a good contribution please stick to the following naming conventions:
Before uploading the images an appropirate folder needs to be created at the S3 storage. For a good contribution please stick to the following conventions:
Build a event root folder for the event. Please add preceding number for providing a well grouped events order.
**pattern:** `event year`/`league name`/`event name with preceding number`/
e.g. `2017`/`1. Segel-Bundesliga`/`01 Prien am Chiemsee`/
Access the S3 folder of the corresponding event year. Create an event root folder and set its name to the name of the league or series of events (see **figure 1**).
![An exemplary event overview for 2017](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/year-and-event.jpeg)
**Figure 1: An exemplary event overview for 2017**
Add a folder for the _logo_, _stage_ and _teaser_ images
**pattern:** `{event root folder}`/`Images_Homepage`/
e.g. `2017`/`1. Segel-Bundesliga`/`01 Prien am Chiemsee`/`Images_Homepage`/
Within this folder add a new subfolder, set its name to the event's name and add a preceding number which indicates the order of it (see **figure 2**).
![folder structure](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/folder-structure.jpeg)
**Figure 2: folder structure with preceding event numbers within an event series**
Add a folder for the _galery_ images
**pattern:** `{event root folder}`/`Images_Photos`/
According to this description result in following folder structure:
**pattern:** `~`/`event year`/`series name`/`event name with preceding number`/
e.g. `~`/`2017`/`1. Segel-Bundesliga`/`01 Prien am Chiemsee`/
Access the corresponding event folder and create two subfolders: _Images\_Homepage_ and _Images\_Photos_. The first one is for the _stage_, _teaser_ and _logo_ images. The second one will carry _gallery_ images.
**pattern:** `~`/`event year`/`series name`/`event name with preceding number`/`Images_Homepage`/
e.g. `2017`/`1. Segel-Bundesliga`/`01 Prien am Chiemsee`/`Images_Homepage`/
**pattern:** `~`/`event year`/`series name`/`event name with preceding number`/`Images_Photos`/
e.g. `2017`/`1. Segel-Bundesliga`/`01 Prien am Chiemsee`/`Images_Photos`/
## Image manipulation with GIMP
@@ -43,7 +53,63 @@ The following guide is based on the tool [GIMP](https://www.gimp.org/) and its [
3. Add -> Add a watermark -> leave defaults -> insert copyright information -> Ok
4. Add images -> ... -> Apply
## Exemplary instructions
1. Access the administration console _eventname(-master?)_.sapsailing.com/gwt/AdminConsle.html and login with your user credentials.
2. Select the corresponding event and click at the _edit_ button (see **figure 3**)
![Events overview on admin console](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/events-overview-admin-console.JPG)
**Figure 3: the edit button on the admin console**
3. By selecting the _Images_ tab the possibilities to add the four image types like described [above](https://wiki.sapsailing.com/preview#images_image-types-and-their-impact) show up (see **figure 4**).
![The four image types](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/edit-media-content.JPG)
**Figure 4: the four image types**
4. Click on the desired _add `image type` button_ and insert the _Image URL_ according to the memory location of the image. Usually, no further settings are required.
# Videos
A guidance about how to synchronize races with livestream videos can be found [here](https://wiki.sapsailing.com/wiki/howto/eventmanagers/linking-race-videos).
## Video types and their impact
We distinguish between _highlight_, _livestream_ and _gallery_ videos and a special _featured_ option.
* **Highlight:** most event organizers provide highlight videos of their sailing events which summarize the best moments of the event. Such videos belong to the _highlight_ category.
* **Livestream:** some event organizers record livestreams of the races during the event. This videos belong to the _livestream_ category and can be linked to the _Race Analytics_ solution.
* **Gallery:** Some times interviews with sailors or other insights of the sailing event are provided by the organizers. These videos belong to the _gallery_ category.
* **Featured:** is a special option for an event video. This tag can be additionally added to one of the three categories _highlight_, _livestream_ and _gallery_. A video with the _featured_ tag is presented at the event's page instead of the _stage image_.
Note: Always define the most populare video to be _featured_ e.g. the current livestream during the event. Never define more than _one_ featured video.
## Exemplary instructions
1. Access the administration console _eventname(-master?)_.sapsailing.com/gwt/AdminConsle.html and login with your user credentials.
2. Select the corresponding event and click at the _edit_ button (see **figure 5**).
![Events overview on admin console](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/events-overview-admin-console.JPG)
**Figure 5: the edit button on the admin console**
3. By selecting the _Videos_ tab the possibilities to add the three video types like described [above](https://wiki.sapsailing.com/wiki/howto/eventmanagers/Manage-media-content#videos_video-types-and-their-impact) show up (see **figure 6**).
![Figure 6: the three video types](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/edit-media-content-video.JPG)
**Figure 6: the three video types**
4. Click on the desired _add_ `video type` _button_ and set the _Video URL_, the _Mime Type_, the _Title_ and the _Laguage_ of the video (see **figure 7**).
![insert a video](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/add-video.JPG)
**Figure 7: link a video with _Video URL_, _Mime Type_, _Title_ and _Language_**
5. In the case you want to set a _featured_ video, select the _Enter tags for the video_ input field and enter _Featured_ (a small popup supports your input). When you're done, you'll need to click the _Add button_ next to the text box that attaches this tag to the video (see **figure 8**).
![Add a featured video](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/add-featured-video.JPG)
**Figure 8: add a featured video**
# Competitor logos
The competitors of the sailing events can be equipped with their club flags. The following steps provide an exemplary guidance about how to add a club flag to its corresponding competitor. All available clubflags are located at the S3 storage under the folder `~`/`clubflags`/.
## Required file format
* **File format:** .png with transparent background
* **File resolution:** about 100 x 50 pixel (file size < 25 kB)
* **Storage location:** `~`/`clubflags`/`country`/
e.g. `~`/`clubflags`/`germany`/`clubflag1.png`
## Exemplary instructions
1. Access the administration console _eventname(-master?)_.sapsailing.com/gwt/AdminConsle.html and login with your user credentials.
2. Select _Tracked races_ and click on the _Competitors_ tab (see **figure 9**).
3. Select the competitor, click on the _Edit_ button (see **figure 9**) and insert the Flag image URL of the corresponding club flag.
![Select the competitors tab within the admin console](https://s3-eu-west-1.amazonaws.com/media.sapsailing.com/wiki/how%20to/media%20content/clubflag-selection.JPG)
**Figure 9: competitors tab of the admin console**
+2
View File
@@ -200,6 +200,8 @@ To reach your multi instance via "ssv.sapsailing.com", perform the following ste
Notice the overwritten health check port that is now pointing directly to the instance with its `SERVER_PORT` 8888.
BE CAREFUL please use for a live-server and live-master-server the traffic port for Health Checks.
2. Add the "SL Multi-Instance Sailing Server" instance to the target group.
<img src="/wiki/images/amazon/TargetGroup_3.png"/>