Merge remote-tracking branch 'origin/master' into bug2610_lifecycle
# Conflicts: # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerActivity.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceTimePanel.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/TimePanel.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java # java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java
@@ -33,3 +33,4 @@ out/
|
||||
local.properties
|
||||
git.xml
|
||||
mobile/github-advrecyclerview_lib/bin
|
||||
captures
|
||||
@@ -0,0 +1,75 @@
|
||||
## Server Landscape
|
||||
|
||||
### Interconnect AWS regions
|
||||
|
||||
For being able to serve low latency connection to the american continent we run several replica server in front of an ELB in AWS region US-East (N.Virginia).
|
||||
|
||||
Our Master and eventual further replicas needed in EU region are deployed in AWS region EU-West (Ireland) for low latency connections towards RabbitMQ and MongoDB.
|
||||
|
||||
Two interconnect the two AWS regions and subnets, I established a site2site VPN tunnel between us-east-1c and eu-west-1c region. The global VPC routes are used to route the traffic for the private subnets (172.16.0.0 in EU and 172.30.0.0 in US-East) towards the according VPN gateway instance, which then tunnels it to the other region. The result is that both regions can communicate internally with each other, so we don't need to tunnel via reverse SSH tunnels or even more worse, open ports (like MongoDB) to the public.
|
||||
|
||||
See [here](http://aws.amazon.com/articles/0639686206802544) for the basic tunnel setup, which is established.
|
||||
|
||||
Simply make sure here, to use the according availibility zones to the instances between the regions can interact with each other. All required internal subnets are configured to the "SAP Sailing analytics" and the "DB/Messaging" Security Group in both regions.
|
||||
|
||||
The VPN setup can be easily expanded to further regions like APJ.
|
||||
|
||||
### Load balancers and Route53
|
||||
|
||||
This setup requires two ELB's; one in each region. Put instances behind the according ELB in your region as usual.
|
||||
The only difference here is, that Route53 entries differ a little bit from the usual standard. There are event subdomain entries (crw2016) for different geo-based locations set, which will handle and forward requests to the "best" load balancer which is set up in each region. See [here](https://wiki.sapsailing.com/wiki/amazon-ec2#amazon-ec2-for-sap-sailing-analytics_howto_using-latency-based-dns-across-regions) for the basic setup of latency-based or geo-based Route53 entries.
|
||||
|
||||
### Technical event meta information
|
||||
```
|
||||
MONGODB_NAME=crw2016
|
||||
SERVER_NAME=CRW2016
|
||||
REPLICATION_CHANNEL=crw2016
|
||||
EVENT=56f62045-de57-4c5e-be6c-a2339d9c9ece
|
||||
```
|
||||
|
||||
### Instances used
|
||||
|
||||
**EU-West Ireland**
|
||||
|
||||
- ELB Load Balancer
|
||||
- External DNS: `CRW2016-EU-554516968.eu-west-1.elb.amazonaws.com`
|
||||
|
||||
- Master 1 (Live)
|
||||
- Internal DNS: `ip-172-31-21-180.eu-west-1.compute.internal`
|
||||
- External DNS: `ec2-52-50-179-44.eu-west-1.compute.amazonaws.com`
|
||||
|
||||
**US-East N. Virginia**
|
||||
|
||||
- ELB Load Balancer
|
||||
- External DNS: `CRW2016-US-EAST-1076258956.us-east-1.elb.amazonaws.com`
|
||||
|
||||
- Replica 1
|
||||
- Internal DNS: `ip-172-30-2-176.ec2.internal`
|
||||
- External DNS: `ec2-52-90-229-141.compute-1.amazonaws.com`
|
||||
|
||||
### Starting up further masters
|
||||
|
||||
```
|
||||
MONGODB_NAME=crw2016
|
||||
REPLICATION_CHANNEL=crw2016
|
||||
SERVER_NAME=CRW2016
|
||||
USE_ENVIRONMENT=live-master-server
|
||||
MEMORY=25600m
|
||||
INSTALL_FROM_RELEASE=build-201604090936
|
||||
SERVER_STARTUP_NOTIFY=steffen.tobias.wagner@sap.com
|
||||
EVENT=56f62045-de57-4c5e-be6c-a2339d9c9ece
|
||||
```
|
||||
|
||||
### Starting up further replicas
|
||||
|
||||
```
|
||||
INSTALL_FROM_RELEASE=build-201604090936
|
||||
USE_ENVIRONMENT=live-replica-server
|
||||
REPLICATE_MASTER_SERVLET_HOST=172.31.21.180
|
||||
REPLICATE_MASTER_EXCHANGE_NAME=crw2016
|
||||
REPLICATE_ON_START=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl,com.sap.sailing.polars.impl.PolarDataServiceImpl
|
||||
SERVER_NAME=CRW2016
|
||||
MONGODB_NAME=crw2016-replica
|
||||
EVENT_ID=56f62045-de57-4c5e-be6c-a2339d9c9ece
|
||||
SERVER_STARTUP_NOTIFY=steffen.tobias.wagner@sap.com
|
||||
```
|
||||
@@ -6,7 +6,8 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0-alpha1'
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/bin/sh
|
||||
ANDROID_RELEASE_BRANCH=android-xmake-release
|
||||
RELEASE_BRANCH=rel-1.4
|
||||
APP_MANIFESTS="mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml mobile/com.sap.sailing.buoy.positioning/AndroidManifest.xml mobile/com.sap.sailing.racecommittee.app/AndroidManifest.xml"
|
||||
GIT_REMOTE=origin
|
||||
UPDATE_ANDROID_MANIFEST_VERSIONS=1
|
||||
UPDATE_POM_VERSIONS=1
|
||||
PERFORM_GIT_OPERATIONS=1
|
||||
|
||||
increment_version_code() {
|
||||
MANIFEST=$1
|
||||
echo "Incrementing version code and version name for $MANIFEST"
|
||||
OLD_VERSION_CODE=`grep 'android:versionCode="[0-9]*"' $MANIFEST | sed -e 's/^.*android:versionCode="\([0-9]*\)".*$/\1/'`
|
||||
NEW_VERSION_CODE=$(($OLD_VERSION_CODE + 1))
|
||||
echo $MANIFEST: OLD_VERSION_CODE is $OLD_VERSION_CODE, NEW_VERSION_CODE is $NEW_VERSION_CODE
|
||||
OLD_MINOR_VERSION=`grep 'android:versionName="[0-9]*\.[0-9]*"' $MANIFEST | sed -e 's/^.*android:versionName="\([0-9]*\)\.\([0-9]*\)".*$/\2/'`
|
||||
NEW_MINOR_VERSION=$((OLD_MINOR_VERSION + 1))
|
||||
echo $MANIFEST: OLD_MINOR_VERSION is $OLD_MINOR_VERSION, NEW_MINOR_VERSION is $NEW_MINOR_VERSION
|
||||
sed --in-place -e "s/android:versionCode=\"$OLD_VERSION_CODE\"/android:versionCode=\"$NEW_VERSION_CODE\"/" -e "s/android:versionName=\"\([0-9]*\)\.$OLD_MINOR_VERSION\"/android:versionName=\"\1.$NEW_MINOR_VERSION\"/" "$MANIFEST"
|
||||
}
|
||||
|
||||
upgrade_pom_and_manifest_versions() {
|
||||
POM=$1
|
||||
NEW_POM_VERSION=$2
|
||||
POM_WITH_PARENT_SPEC_REMOVED="${POM}.parentspecremoved"
|
||||
PARENT_SPEC="${POM}.parentspec"
|
||||
RESTORED_POM_WITH_NEW_VERSION_AND_PARENT_SPEC="${POM}.restored"
|
||||
POM_BACKUP="${POM}.bak"
|
||||
cp "$POM" "$POM_BACKUP"
|
||||
# find the area to remove
|
||||
snip_area_start_line=`grep -n SNIP_MARKER_START pom.xml | sed -e 's/^\([0-9]*\):.*$/\1/'`
|
||||
snip_area_end_line=`grep -n SNIP_MARKER_END pom.xml | sed -e 's/^\([0-9]*\):.*$/\1/'`
|
||||
sed -e "$snip_area_start_line,$snip_area_end_line d" <"$POM" >"$POM_WITH_PARENT_SPEC_REMOVED"
|
||||
sed -e "1,$((snip_area_start_line - 1)) d" -e "$((snip_area_end_line + 1)),$ d" <"$POM" >"$PARENT_SPEC"
|
||||
cp "$POM_WITH_PARENT_SPEC_REMOVED" "$POM"
|
||||
echo mvn -Dtycho.mode=maven org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion=$NEW_POM_VERSION
|
||||
mvn -Dtycho.mode=maven org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion=$NEW_POM_VERSION
|
||||
sed --in-place -e 's/$/\\/' "$PARENT_SPEC"
|
||||
cat "$POM" | sed -e "$snip_area_start_line i \\`cat "$PARENT_SPEC"`" | sed -e "$snip_area_start_line,$snip_area_end_line s/\\\\$//" >"$RESTORED_POM_WITH_NEW_VERSION_AND_PARENT_SPEC"
|
||||
cp "$RESTORED_POM_WITH_NEW_VERSION_AND_PARENT_SPEC" "$POM"
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "buildAndUpdateProduct [-m -p -g -r <git-remote>] CR-Id: <TheJCWBCRId>"
|
||||
echo ""
|
||||
echo "Request a new Java Correction Workbench (JCWB) Correction Request ID at:"
|
||||
echo " https://css.wdf.sap.corp/sap(bD1lbiZjPTAwMQ==)/bc/bsp/spn/jcwb/default.htm?newCMForProject=sapsailingcapture#"
|
||||
echo "See more usage details in the sapsailing.com wiki at:"
|
||||
echo " https://wiki.sapsailing.com/wiki/building-and-deploying#building-deploying-stopping-and-starting-server-instances_app-build-process-for-ios-and-android_xmake-build-for-android-apps"
|
||||
echo "-m Disable upgrading the AndroidManifest.xml versionCode and versionName"
|
||||
echo "-p Disable upgrading the pom.xml and MANIFEST.MF versions"
|
||||
echo "-g Disable the final git push operation to refs/for/$RELEASE_BRANCH"
|
||||
echo "-r The git remote; defaults to origin"
|
||||
echo ""
|
||||
echo "Example: $0 CR-Id: 012003146900000486712016"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
options='mpgr:'
|
||||
while getopts $options option
|
||||
do
|
||||
case $option in
|
||||
m) UPDATE_ANDROID_MANIFEST_VERSIONS=0;;
|
||||
p) UPDATE_POM_VERSIONS=0;;
|
||||
g) PERFORM_GIT_OPERATIONS=0;;
|
||||
r) GIT_REMOTE=$OPTARG;;
|
||||
\?) echo "Invalid option"
|
||||
exit 4;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# change directory to the git root, assuming this script is in the configuration/ subfolder
|
||||
GIT_DIR="`dirname \"$0\"`/.."
|
||||
echo GIT_DIR: $GIT_DIR
|
||||
JCWB_CHANGE_REQUEST_ID_GIT_TAG=$*
|
||||
echo "Releasing based on Java Correction Workbench (JCWB) Correction Request ID tag $JCWB_CHANGE_REQUEST_ID_GIT_TAG"
|
||||
cd "$GIT_DIR"
|
||||
|
||||
git fetch $GIT_REMOTE
|
||||
git checkout $ANDROID_RELEASE_BRANCH
|
||||
git merge -m "Merging $GIT_REMOTE/$ANDROID_RELEASE_BRANCH" $GIT_REMOTE/$ANDROID_RELEASE_BRANCH
|
||||
git fetch $GIT_REMOTE $RELEASE_BRANCH:$RELEASE_BRANCH
|
||||
git merge -m "Merging $RELEASE_BRANCH into $ANDROID_RELEASE_BRANCH, probably incorporating version setting to -SNAPSHOT" $GIT_REMOTE/$RELEASE_BRANCH
|
||||
git push $GIT_REMOTE $ANDROID_RELEASE_BRANCH:$ANDROID_RELEASE_BRANCH
|
||||
|
||||
# Patch the AndroidManifest.xml files to upgrade the android:versionCode sequential counter relevant for the PlayStore
|
||||
# and the android:versionName which is what the user sees and which we expect to follow a major.minor version scheme,
|
||||
# where this script increments the minor version by one
|
||||
if [ "$UPDATE_ANDROID_MANIFEST_VERSIONS" = "1" ]; then
|
||||
for m in $APP_MANIFESTS; do
|
||||
increment_version_code $m
|
||||
done
|
||||
fi
|
||||
|
||||
# Determine the version in the root pom.xml; if a -SNAPSHOT version, simply remove the -SNAPSHOT;
|
||||
# otherwise, increment micro version by one and use the Tycho version plugin to update;
|
||||
# For this to work, the <parent> specification needs to be removed from the top-level pom which later
|
||||
# needs to be re-activated before committing everything
|
||||
OLD_POM_VERSION=`head -n 15 pom.xml | grep '<version>.*</version>' | sed -e 's/^.*<version>\(.*\)<\/version>.*$/\1/'`
|
||||
echo $OLD_POM_VERSION | grep -q -- "-SNAPSHOT"
|
||||
if [ "$?" = "0" ]; then
|
||||
# found a -SNAPSHOT identifier; assuming this was for the next release already; simply remove -SNAPSHOT
|
||||
NEW_POM_VERSION=`echo $OLD_POM_VERSION | sed -e 's/-SNAPSHOT//'`
|
||||
else
|
||||
# no -SNAPSHOT found; increment the micro version by one
|
||||
NEW_POM_VERSION=`echo $OLD_POM_VERSION | (IFS=. read major minor micro; echo ${major}.${minor}.$(($micro + 1)) )`
|
||||
fi
|
||||
echo OLD_POM_VERSION is $OLD_POM_VERSION, NEW_POM_VERSION is $NEW_POM_VERSION
|
||||
if [ "$UPDATE_POM_VERSIONS" = "1" ]; then
|
||||
upgrade_pom_and_manifest_versions pom.xml $NEW_POM_VERSION
|
||||
fi
|
||||
|
||||
# Now commit the version changes and amend the commit using the change request ID tag:
|
||||
git commit -a -m "Upgraded Android apps from version $OLD_POM_VERSION to $NEW_POM_VERSION"
|
||||
git commit --amend -m "`git show -s --pretty=format:%s%n%n%b`
|
||||
$JCWB_CHANGE_REQUEST_ID_GIT_TAG"
|
||||
if [ "$PERFORM_GIT_OPERATIONS" = "1" ]; then
|
||||
git push $GIT_REMOTE $ANDROID_RELEASE_BRANCH:refs/for/$RELEASE_BRANCH
|
||||
fi
|
||||
@@ -28,6 +28,7 @@ SAP is at the center of today’s technology revolution, developing innovations
|
||||
* [[Amazon EC2|wiki/amazon-ec2]]
|
||||
* [[SSL / HTTPS Support|wiki/ssl-support]]
|
||||
* [[EC2 Backup Strategy|wiki/amazon-ec2-backup-strategy]]
|
||||
* [[EC2 mail relaying|wiki/mail-relaying]]
|
||||
* [[TracTrac|wiki/tractrac-lifecycle]]
|
||||
* [[Analytics on a stick|wiki/analytics-on-a-stick]]
|
||||
* [[Operating Igtimi WindBots/windbot-operations]]
|
||||
@@ -72,6 +73,7 @@ SAP is at the center of today’s technology revolution, developing innovations
|
||||
* [[Travemünder Woche 2014 event page|wiki/tw2014]]
|
||||
* [[505 worlds Kiel 2014 event page|wiki/505-worlds-kiel-2014]]
|
||||
* [[Kieler Woche event page|wiki/kieler-woche-2015]]
|
||||
* [[Charleston Race Week 2016|wiki/Charleston-Race-Week-2016]]
|
||||
* Lean DI Support
|
||||
* [[Setting up internal Jenkins on SAP Monsoon|wiki/setting-up-jenkins-on-sap-monsoon]]
|
||||
|
||||
|
||||
@@ -283,7 +283,6 @@
|
||||
7F44095B19F65B5B0021BF22 /* CoreData.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 7F44095919F65B5B0021BF22 /* CoreData.xcdatamodeld */; };
|
||||
7F4D2F541A1C8EE50038E7D1 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7F4D2F531A1C8EE50038E7D1 /* Images.xcassets */; };
|
||||
7F4EEDBA1A6D2BAC0026F711 /* CheckIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F4EEDB91A6D2BAC0026F711 /* CheckIn.swift */; };
|
||||
7F72C73A1A2DC51900F48EE8 /* SplashScreenDummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F72C7391A2DC51900F48EE8 /* SplashScreenDummy.swift */; };
|
||||
7F83F15619F154F000C53328 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F83F15519F154F000C53328 /* AppDelegate.swift */; };
|
||||
7F83F15819F154F000C53328 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F83F15719F154F000C53328 /* HomeViewController.swift */; };
|
||||
7F83F15B19F154F000C53328 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F83F15919F154F000C53328 /* Main.storyboard */; };
|
||||
@@ -317,6 +316,7 @@
|
||||
7FED45CA1A25F5910022505F /* event1.json in Resources */ = {isa = PBXBuildFile; fileRef = 7FED45C41A25F5900022505F /* event1.json */; };
|
||||
7FED45CC1A25F5910022505F /* leaderboard1.json in Resources */ = {isa = PBXBuildFile; fileRef = 7FED45C61A25F5900022505F /* leaderboard1.json */; };
|
||||
9E95C3D61C723AB30016632B /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E95C3D51C723AB30016632B /* Constants.swift */; };
|
||||
9ECBDDAE1C9C4F0300F76AEB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9ECBDDAD1C9C4F0300F76AEB /* LaunchScreen.storyboard */; };
|
||||
C8603D4A1C528832002B2F28 /* Acknowledgements.markdown in Sources */ = {isa = PBXBuildFile; fileRef = C8603D491C528832002B2F28 /* Acknowledgements.markdown */; };
|
||||
C8603D511C52892A002B2F28 /* Acknowledgements.markdown in Resources */ = {isa = PBXBuildFile; fileRef = C8603D491C528832002B2F28 /* Acknowledgements.markdown */; };
|
||||
C8A4400B1C18153600DF70A0 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = C8A4400A1C18153600DF70A0 /* Settings.bundle */; };
|
||||
@@ -647,7 +647,6 @@
|
||||
7F44095A19F65B5B0021BF22 /* CoreData.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = CoreData.xcdatamodel; sourceTree = "<group>"; };
|
||||
7F4D2F531A1C8EE50038E7D1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
7F4EEDB91A6D2BAC0026F711 /* CheckIn.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckIn.swift; sourceTree = "<group>"; };
|
||||
7F72C7391A2DC51900F48EE8 /* SplashScreenDummy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashScreenDummy.swift; sourceTree = "<group>"; };
|
||||
7F83F15019F154F000C53328 /* SAPTracker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SAPTracker.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7F83F15419F154F000C53328 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
7F83F15519F154F000C53328 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -686,6 +685,7 @@
|
||||
7FED45C41A25F5900022505F /* event1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = event1.json; sourceTree = "<group>"; };
|
||||
7FED45C61A25F5900022505F /* leaderboard1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = leaderboard1.json; sourceTree = "<group>"; };
|
||||
9E95C3D51C723AB30016632B /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
9ECBDDAD1C9C4F0300F76AEB /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
C8603D491C528832002B2F28 /* Acknowledgements.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Acknowledgements.markdown; sourceTree = "<group>"; };
|
||||
C8A4400A1C18153600DF70A0 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||
C8B31F771B68DAD400C8A809 /* Pods.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Pods.xcodeproj; path = Pods/Pods.xcodeproj; sourceTree = "<group>"; };
|
||||
@@ -1059,6 +1059,7 @@
|
||||
7F72C73F1A2DEA2100F48EE8 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9ECBDDAD1C9C4F0300F76AEB /* LaunchScreen.storyboard */,
|
||||
7F83F15919F154F000C53328 /* Main.storyboard */,
|
||||
7F4D2F531A1C8EE50038E7D1 /* Images.xcassets */,
|
||||
7F87CA9D1A2CCE8B0076C617 /* OpenSans-Bold.ttf */,
|
||||
@@ -1077,7 +1078,6 @@
|
||||
7FD9D3021A1236080058FEAD /* Extensions.swift */,
|
||||
7F87CAA51A2CD6BA0076C617 /* Appearance.h */,
|
||||
7F87CAA61A2CD6BA0076C617 /* Appearance.m */,
|
||||
7F72C7391A2DC51900F48EE8 /* SplashScreenDummy.swift */,
|
||||
9E95C3D51C723AB30016632B /* Constants.swift */,
|
||||
);
|
||||
name = Helpers;
|
||||
@@ -1219,7 +1219,6 @@
|
||||
TargetAttributes = {
|
||||
7F83F14F19F154F000C53328 = {
|
||||
CreatedOnToolsVersion = 6.0.1;
|
||||
DevelopmentTeam = RRE8EFVCE3;
|
||||
};
|
||||
7F83F16419F154F000C53328 = {
|
||||
CreatedOnToolsVersion = 6.0.1;
|
||||
@@ -1517,6 +1516,7 @@
|
||||
7F14A1501A13B9A6001C1ECB /* CW.png in Resources */,
|
||||
7F14A1141A13B9A6001C1ECB /* _northern-cyprus.png in Resources */,
|
||||
7F14A13E1A13B9A6001C1ECB /* BW.png in Resources */,
|
||||
9ECBDDAE1C9C4F0300F76AEB /* LaunchScreen.storyboard in Resources */,
|
||||
7F14A1481A13B9A6001C1ECB /* CK.png in Resources */,
|
||||
7F14A11B1A13B9A6001C1ECB /* _unknown.png in Resources */,
|
||||
7F14A19B1A13B9A6001C1ECB /* LI.png in Resources */,
|
||||
@@ -1617,7 +1617,6 @@
|
||||
7F06590419F8094C0077FF95 /* DeviceUDIDManager.swift in Sources */,
|
||||
7F3AA7C81A1CD7D700F8861F /* SendGPSFixController.swift in Sources */,
|
||||
7FCDB6641A1636610075D7D9 /* LeaderBoard.swift in Sources */,
|
||||
7F72C73A1A2DC51900F48EE8 /* SplashScreenDummy.swift in Sources */,
|
||||
C8603D4A1C528832002B2F28 /* Acknowledgements.markdown in Sources */,
|
||||
7F8B8D411A373B0200C34B88 /* SpeedViewController.swift in Sources */,
|
||||
9E95C3D61C723AB30016632B /* Constants.swift in Sources */,
|
||||
@@ -1789,9 +1788,9 @@
|
||||
baseConfigurationReference = EA431711E588F5A2B31A62AC /* Pods.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
INFOPLIST_FILE = SAPTracker/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1801,7 +1800,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = SAPTracker/bridge.h;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1810,9 +1809,9 @@
|
||||
baseConfigurationReference = CF98F25F363113C51C7CB1F3 /* Pods.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
INFOPLIST_FILE = SAPTracker/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1822,7 +1821,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = SAPTracker/bridge.h;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ public class APIManager: NSObject {
|
||||
|
||||
// set up reachability
|
||||
let operationQueue = manager!.operationQueue
|
||||
manager!.reachabilityManager.setReachabilityStatusChangeBlock({(AFNetworkReachabilityStatus status) -> Void in
|
||||
manager!.reachabilityManager.setReachabilityStatusChangeBlock({(status) -> Void in
|
||||
switch (status) {
|
||||
case AFNetworkReachabilityStatus.ReachableViaWWAN, AFNetworkReachabilityStatus.ReachableViaWiFi:
|
||||
operationQueue?.suspended = false
|
||||
@@ -106,7 +106,7 @@ public class APIManager: NSObject {
|
||||
}
|
||||
|
||||
public func teamImage(competitorId: String!, result: (imageUrl: String?) -> Void) {
|
||||
getTeam(competitorId, success: { (AFHTTPRequestOperation operation, AnyObject teamResponseObject) -> Void in
|
||||
getTeam(competitorId, success: { (operation, teamResponseObject) -> Void in
|
||||
|
||||
if let team = teamResponseObject as? [String: AnyObject],
|
||||
let imageUrl = team["imageUri"] as? String {
|
||||
@@ -115,7 +115,7 @@ public class APIManager: NSObject {
|
||||
result(imageUrl: nil)
|
||||
}
|
||||
|
||||
}, failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
}, failure: { (operation, error) -> Void in
|
||||
// No image & that's ok
|
||||
result(imageUrl: nil)
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ class AboutViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var versionDescriptionLabel: UILabel!
|
||||
@IBOutlet weak var versionLabel: UILabel!
|
||||
@IBOutlet weak var textView: UITextView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad();
|
||||
@@ -21,7 +22,16 @@ class AboutViewController: UIViewController {
|
||||
} else {
|
||||
versionLabel.text = "-"
|
||||
}
|
||||
|
||||
// add logo to top left
|
||||
let imageView = UIImageView(image: UIImage(named: "sap_logo"))
|
||||
let barButtonItem = UIBarButtonItem(customView: imageView)
|
||||
navigationItem.leftBarButtonItem = barButtonItem
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
textView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: false)
|
||||
}
|
||||
|
||||
@IBAction func done(sender: AnyObject) {
|
||||
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
|
||||
|
||||
@@ -44,6 +44,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
}
|
||||
|
||||
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
|
||||
|
||||
let rootViewController = self.window!.rootViewController as! UINavigationController
|
||||
rootViewController.popToRootViewControllerAnimated(false)
|
||||
rootViewController.dismissViewControllerAnimated(false, completion: nil)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="pqQ-jd-OwW">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="pqQ-jd-OwW">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
@@ -47,6 +48,7 @@
|
||||
<string>OpenSans</string>
|
||||
<string>OpenSans</string>
|
||||
<string>OpenSans</string>
|
||||
<string>OpenSans</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="OpenSans-Semibold.ttf">
|
||||
<string>OpenSans-Semibold</string>
|
||||
@@ -208,20 +210,41 @@
|
||||
<outlet property="btnScan" destination="Ieu-ch-jeI" id="FWs-OF-b4i"/>
|
||||
<outlet property="tableView" destination="OXU-ft-TXZ" id="1BA-dy-00A"/>
|
||||
<outlet property="tableViewHeight" destination="yuo-wx-0A1" id="pFK-q1-1DI"/>
|
||||
<outlet property="vSplashScreen" destination="4Od-pk-xCd" id="3sj-Mx-34I"/>
|
||||
<segue destination="G3a-SV-Maf" kind="show" identifier="Regatta" id="FMW-37-go1"/>
|
||||
<segue destination="plm-Uw-c62" kind="show" identifier="Scan" id="U8l-If-CrF"/>
|
||||
<segue destination="4Fb-v3-mkB" kind="presentation" identifier="Settings" id="Xxn-jp-xEB"/>
|
||||
<segue destination="dfN-Ch-vpm" kind="presentation" identifier="About" id="QMa-LQ-D8c"/>
|
||||
<segue destination="4Fb-v3-mkB" kind="presentation" identifier="SettingsFromHome" id="Xxn-jp-xEB"/>
|
||||
<segue destination="dfN-Ch-vpm" kind="presentation" identifier="AboutFromHome" id="QMa-LQ-D8c"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
|
||||
<view contentMode="scaleToFill" id="4Od-pk-xCd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="applogo" translatesAutoresizingMaskIntoConstraints="NO" id="K04-Lb-fSm">
|
||||
<rect key="frame" x="117.5" y="220" width="365" height="96"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="K04-Lb-fSm" secondAttribute="height" multiplier="365:96" id="iTN-7Q-YkX"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="K04-Lb-fSm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="4Od-pk-xCd" secondAttribute="leading" constant="30" id="0ML-xS-Lk4"/>
|
||||
<constraint firstItem="K04-Lb-fSm" firstAttribute="width" secondItem="K04-Lb-fSm" secondAttribute="height" multiplier="365:96" id="YeC-DN-aQX"/>
|
||||
<constraint firstItem="K04-Lb-fSm" firstAttribute="centerY" secondItem="4Od-pk-xCd" secondAttribute="centerY" id="lJN-eB-asJ"/>
|
||||
<constraint firstItem="K04-Lb-fSm" firstAttribute="centerX" secondItem="4Od-pk-xCd" secondAttribute="centerX" id="lP3-oq-Tj2"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="K04-Lb-fSm" secondAttribute="trailing" constant="30" id="tNv-UR-6vj"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1222" y="-307"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="e3W-CJ-soQ">
|
||||
<objects>
|
||||
<navigationController id="pqQ-jd-OwW" sceneMemberID="viewController">
|
||||
<navigationController storyboardIdentifier="rootViewController" id="pqQ-jd-OwW" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="x3H-m5-yJB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
@@ -299,7 +322,7 @@
|
||||
</constraint>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CDA-ep-bjo">
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CDA-ep-bjo">
|
||||
<rect key="frame" x="200" y="48" width="200" height="33"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
@@ -345,13 +368,13 @@
|
||||
<rect key="frame" x="0.0" y="114" width="600" height="40"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="GER 17" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="iIf-9z-7fe">
|
||||
<rect key="frame" x="527.5" y="8" width="56.5" height="24"/>
|
||||
<rect key="frame" x="527" y="8" width="56.5" height="24"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DE.png" translatesAutoresizingMaskIntoConstraints="NO" id="szG-Mg-huO">
|
||||
<rect key="frame" x="495.5" y="8" width="24" height="24"/>
|
||||
<rect key="frame" x="495" y="8" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="Ina-uK-atY"/>
|
||||
<constraint firstAttribute="height" constant="24" id="TVX-WF-dOi"/>
|
||||
@@ -434,12 +457,12 @@
|
||||
<rect key="frame" x="255" y="194" width="90" height="60"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="24" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gaG-Iv-Xyq">
|
||||
<rect key="frame" x="24.5" y="0.0" width="41.5" height="49.5"/>
|
||||
<rect key="frame" x="24" y="0.0" width="41.5" height="49.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="36"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hours" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c2J-Uj-KEg">
|
||||
<rect key="frame" x="31.5" y="46" width="28.5" height="14"/>
|
||||
<rect key="frame" x="31" y="46" width="28.5" height="14"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="10"/>
|
||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -471,7 +494,7 @@
|
||||
<rect key="frame" x="353" y="194" width="90" height="60"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="59" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Txm-uf-MP4">
|
||||
<rect key="frame" x="24.5" y="0.0" width="41.5" height="49.5"/>
|
||||
<rect key="frame" x="24" y="0.0" width="41.5" height="49.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="36"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
@@ -513,11 +536,11 @@
|
||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="P9e-ZM-HZP">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="P9e-ZM-HZP">
|
||||
<rect key="frame" x="303" y="372" width="277" height="44"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.67843137249999996" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="jqD-cx-gQM"/>
|
||||
<constraint firstAttribute="height" constant="44" id="jqD-cx-gQM"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="Leader Board">
|
||||
@@ -566,7 +589,7 @@
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QHA-RX-lHP" userLabel="Spacer">
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QHA-RX-lHP" userLabel="Spacer">
|
||||
<rect key="frame" x="299" y="389" width="2" height="10"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
@@ -574,7 +597,7 @@
|
||||
<constraint firstAttribute="width" constant="2" id="mpd-5K-GxQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lzv-E6-gsr">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lzv-E6-gsr">
|
||||
<rect key="frame" x="20" y="372" width="277" height="44"/>
|
||||
<color key="backgroundColor" red="0.10980392156862745" green="0.48627450980392156" blue="0.76078431372549016" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
@@ -592,6 +615,35 @@
|
||||
<action selector="showEvent:" destination="G3a-SV-Maf" eventType="touchUpInside" id="aOq-oB-vIG"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Gjq-vj-gAR">
|
||||
<rect key="frame" x="170" y="48" width="260" height="33"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="260" id="5jL-oY-VM2"/>
|
||||
<constraint firstAttribute="height" constant="33" id="ZOg-nP-2k3"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
|
||||
<inset key="imageEdgeInsets" minX="5" minY="5" maxX="20" maxY="5"/>
|
||||
<state key="normal" title="Error during upload. Tap to retry." image="retry">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="2"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
|
||||
<real key="value" value="0.5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor">
|
||||
<color key="value" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="showImageAlertView:" destination="G3a-SV-Maf" eventType="touchUpInside" id="GzU-Yx-U2c"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
@@ -599,6 +651,7 @@
|
||||
<constraint firstItem="CDA-ep-bjo" firstAttribute="top" secondItem="Ezh-Sq-hsb" secondAttribute="top" constant="48" id="3xV-Px-tvy"/>
|
||||
<constraint firstItem="gHJ-am-Ulb" firstAttribute="top" secondItem="5is-0I-Kv3" secondAttribute="bottom" constant="8" symbolic="YES" id="4Ai-mf-Ab3"/>
|
||||
<constraint firstItem="ft9-jD-C5m" firstAttribute="trailing" secondItem="gHJ-am-Ulb" secondAttribute="trailing" id="4rt-0W-Jpl"/>
|
||||
<constraint firstItem="Gjq-vj-gAR" firstAttribute="centerX" secondItem="Ezh-Sq-hsb" secondAttribute="centerX" id="6Zd-Lr-JJ2"/>
|
||||
<constraint firstItem="mj9-m1-nYY" firstAttribute="trailing" secondItem="gHJ-am-Ulb" secondAttribute="trailing" id="6bk-OB-IQS"/>
|
||||
<constraint firstItem="pjH-rV-MGI" firstAttribute="top" secondItem="ft9-jD-C5m" secondAttribute="bottom" constant="8" symbolic="YES" id="6va-QB-QGA"/>
|
||||
<constraint firstItem="8aO-2n-aG5" firstAttribute="bottom" secondItem="cNo-41-lUw" secondAttribute="top" id="716-9b-eFO"/>
|
||||
@@ -621,6 +674,7 @@
|
||||
<constraint firstItem="8aO-2n-aG5" firstAttribute="top" secondItem="mj9-m1-nYY" secondAttribute="bottom" constant="8" symbolic="YES" id="SZP-ow-Och"/>
|
||||
<constraint firstItem="P9e-ZM-HZP" firstAttribute="top" relation="greaterThanOrEqual" secondItem="gHJ-am-Ulb" secondAttribute="bottom" constant="8" symbolic="YES" id="VAj-aB-Ezg"/>
|
||||
<constraint firstItem="tvc-eS-Us6" firstAttribute="leading" secondItem="5is-0I-Kv3" secondAttribute="trailing" constant="8" id="WJd-lR-8UH"/>
|
||||
<constraint firstItem="Gjq-vj-gAR" firstAttribute="top" secondItem="wYi-P2-UTF" secondAttribute="bottom" constant="48" id="XQn-se-otI"/>
|
||||
<constraint firstItem="Lzv-E6-gsr" firstAttribute="leading" secondItem="mj9-m1-nYY" secondAttribute="leading" id="XXL-Ep-csv"/>
|
||||
<constraint firstItem="5is-0I-Kv3" firstAttribute="top" secondItem="ft9-jD-C5m" secondAttribute="bottom" constant="8" symbolic="YES" id="YvG-vU-Ja4"/>
|
||||
<constraint firstItem="Ik1-Z0-TGp" firstAttribute="leading" secondItem="Ezh-Sq-hsb" secondAttribute="leading" id="dUq-Dh-9sc"/>
|
||||
@@ -669,6 +723,7 @@
|
||||
<outlet property="nameLabel" destination="oJS-dM-2B6" id="fXn-FX-UbJ"/>
|
||||
<outlet property="openEventButton" destination="Lzv-E6-gsr" id="I7S-26-Qp6"/>
|
||||
<outlet property="regattaStartLabel" destination="ft9-jD-C5m" id="C70-iD-pB3"/>
|
||||
<outlet property="retryUploadTeamPhotoButton" destination="Gjq-vj-gAR" id="AJd-4h-9Cz"/>
|
||||
<outlet property="sailLabel" destination="iIf-9z-7fe" id="xPM-y9-Tjg"/>
|
||||
<outlet property="startTrackingButton" destination="mj9-m1-nYY" id="eUX-Yd-aix"/>
|
||||
<outlet property="yourTeamPhotoButton" destination="CDA-ep-bjo" id="15b-r4-Mve"/>
|
||||
@@ -728,7 +783,7 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Status" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="r6d-OU-cRI">
|
||||
<rect key="frame" x="20" y="39.5" width="49.5" height="23.5"/>
|
||||
<rect key="frame" x="20" y="39" width="49.5" height="23.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -740,7 +795,7 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tracking Running" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="5Xu-6g-tqP">
|
||||
<rect key="frame" x="444" y="39.5" width="136" height="23.5"/>
|
||||
<rect key="frame" x="444" y="39" width="136" height="23.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.25098039220000001" green="0.50196078430000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -748,9 +803,7 @@
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Cached Fixes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="Ujw-jg-ilY">
|
||||
<rect key="frame" x="20" y="71" width="102.5" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="aFo-6u-YNo">
|
||||
<variation key="heightClass=compact" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="height" constant="24" id="aFo-6u-YNo"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -759,21 +812,19 @@
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="dz3-w7-CCh">
|
||||
<rect key="frame" x="570" y="71" width="10" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="itl-Pi-yYx">
|
||||
<variation key="heightClass=compact" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="height" constant="24" id="itl-Pi-yYx"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="UcT-H2-Fxp">
|
||||
<rect key="frame" x="0.0" y="134.5" width="600" height="401.5"/>
|
||||
<rect key="frame" x="0.0" y="134" width="600" height="401.5"/>
|
||||
<connections>
|
||||
<segue destination="rjH-vb-OUF" kind="embed" id="ln5-SR-WkO"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="no GPS" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DiM-MR-SGV">
|
||||
<rect key="frame" x="506.5" y="8" width="57.5" height="23.5"/>
|
||||
<rect key="frame" x="506" y="8" width="57.5" height="23.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -787,19 +838,41 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Online" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="tJY-RR-vpe">
|
||||
<rect key="frame" x="527.5" y="103" width="52.5" height="23.5"/>
|
||||
<rect key="frame" x="527" y="103" width="52.5" height="23.5"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.25098040700000002" green="0.50196081400000003" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mnl-aL-6R2">
|
||||
<rect key="frame" x="20" y="424" width="560" height="75"/>
|
||||
<color key="backgroundColor" red="0.87843137250000003" green="0.20000000000000001" blue="0.090196078430000007" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="75" id="NVa-wY-Jve">
|
||||
<variation key="heightClass=compact" constant="50"/>
|
||||
</constraint>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="Stop Tracking">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="stopTrackingButtonTapped:" destination="eHd-jN-WkS" eventType="touchUpInside" id="V6I-ta-wMI"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="tJY-RR-vpe" secondAttribute="trailing" id="4KI-fl-gq3"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="dz3-w7-CCh" secondAttribute="trailing" id="5YC-rH-Z2d"/>
|
||||
<constraint firstItem="Ujw-jg-ilY" firstAttribute="top" secondItem="r6d-OU-cRI" secondAttribute="bottom" constant="8" symbolic="YES" id="76Y-1b-oFJ">
|
||||
<variation key="heightClass=compact" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstItem="Ujw-jg-ilY" firstAttribute="top" secondItem="r6d-OU-cRI" secondAttribute="bottom" constant="8" symbolic="YES" id="76Y-1b-oFJ"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="mnl-aL-6R2" secondAttribute="trailing" id="8vV-66-vsk"/>
|
||||
<constraint firstItem="UcT-H2-Fxp" firstAttribute="top" secondItem="Xww-rc-pOA" secondAttribute="bottom" constant="8" symbolic="YES" id="9el-UI-bzr"/>
|
||||
<constraint firstItem="UcT-H2-Fxp" firstAttribute="bottom" secondItem="nE0-bK-d8x" secondAttribute="top" id="C25-aA-8XZ"/>
|
||||
<constraint firstItem="r6d-OU-cRI" firstAttribute="top" secondItem="Z1d-5I-pbj" secondAttribute="bottom" constant="8" symbolic="YES" id="C3i-US-IRf"/>
|
||||
@@ -810,6 +883,7 @@
|
||||
<constraint firstItem="Xww-rc-pOA" firstAttribute="leading" secondItem="6kF-Wb-Hv2" secondAttribute="leadingMargin" id="JQs-RK-ocI"/>
|
||||
<constraint firstItem="r6d-OU-cRI" firstAttribute="leading" secondItem="Z1d-5I-pbj" secondAttribute="leading" id="L9y-4I-Xx1"/>
|
||||
<constraint firstItem="Ujw-jg-ilY" firstAttribute="leading" secondItem="6kF-Wb-Hv2" secondAttribute="leadingMargin" id="MH7-cy-19A"/>
|
||||
<constraint firstItem="nE0-bK-d8x" firstAttribute="top" secondItem="mnl-aL-6R2" secondAttribute="bottom" constant="37" id="N0D-rv-8NW"/>
|
||||
<constraint firstItem="dz3-w7-CCh" firstAttribute="centerY" secondItem="Ujw-jg-ilY" secondAttribute="centerY" id="NPU-zR-WBN"/>
|
||||
<constraint firstItem="Xww-rc-pOA" firstAttribute="centerY" secondItem="tJY-RR-vpe" secondAttribute="centerY" id="NVc-vI-Vxb"/>
|
||||
<constraint firstItem="Xww-rc-pOA" firstAttribute="top" secondItem="Ujw-jg-ilY" secondAttribute="bottom" constant="8" symbolic="YES" id="Owh-AZ-oxm"/>
|
||||
@@ -819,6 +893,7 @@
|
||||
<constraint firstAttribute="trailingMargin" secondItem="5Xu-6g-tqP" secondAttribute="trailing" id="j12-j8-u1B"/>
|
||||
<constraint firstItem="Z1d-5I-pbj" firstAttribute="top" secondItem="qL4-PH-8ve" secondAttribute="bottom" constant="8" symbolic="YES" id="pnF-1D-Rxo"/>
|
||||
<constraint firstAttribute="trailing" secondItem="BFc-m8-XKV" secondAttribute="trailing" constant="16" id="r8t-UX-UKm"/>
|
||||
<constraint firstItem="mnl-aL-6R2" firstAttribute="leading" secondItem="6kF-Wb-Hv2" secondAttribute="leadingMargin" id="zei-4r-UQH"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Tracking" id="qfB-FT-Ysz">
|
||||
@@ -854,9 +929,7 @@
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tracking Time" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="IeZ-JM-OWw">
|
||||
<rect key="frame" x="20" y="0.0" width="109.5" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="HVj-ZO-f4Y">
|
||||
<variation key="heightClass=compact" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="height" constant="24" id="HVj-ZO-f4Y"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
@@ -868,41 +941,14 @@
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ULl-vy-5gb">
|
||||
<rect key="frame" x="20" y="525" width="560" height="75"/>
|
||||
<color key="backgroundColor" red="0.87843137250000003" green="0.20000000000000001" blue="0.090196078430000007" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="75" id="WnL-zt-cEe">
|
||||
<variation key="heightClass=compact" constant="50"/>
|
||||
</constraint>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="Stop Tracking">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="stopTrackingButtonTapped:" destination="QJL-mi-hJE" eventType="touchUpInside" id="5fq-CB-McA"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="mUm-EE-6Is" secondAttribute="centerY" priority="750" id="8N8-eA-npB"/>
|
||||
<constraint firstAttribute="centerX" secondItem="mUm-EE-6Is" secondAttribute="centerX" id="8mv-fJ-KnI"/>
|
||||
<constraint firstAttribute="centerX" secondItem="ULl-vy-5gb" secondAttribute="centerX" id="Fzl-H6-UnL"/>
|
||||
<constraint firstItem="IeZ-JM-OWw" firstAttribute="top" secondItem="mP6-V4-QPK" secondAttribute="top" id="IZk-R3-x2F"/>
|
||||
<constraint firstItem="ULl-vy-5gb" firstAttribute="bottom" secondItem="gKu-YN-ryh" secondAttribute="top" id="UN0-98-lxt"/>
|
||||
<constraint firstAttribute="trailing" secondItem="mUm-EE-6Is" secondAttribute="trailing" constant="20" symbolic="YES" id="ZKy-Zc-RiE"/>
|
||||
<constraint firstItem="IeZ-JM-OWw" firstAttribute="leading" secondItem="ULl-vy-5gb" secondAttribute="leading" id="eGE-uB-OHk"/>
|
||||
<constraint firstItem="IeZ-JM-OWw" firstAttribute="leading" secondItem="mP6-V4-QPK" secondAttribute="leadingMargin" id="eYA-zH-AXy"/>
|
||||
<constraint firstItem="mUm-EE-6Is" firstAttribute="leading" secondItem="mP6-V4-QPK" secondAttribute="leading" constant="20" symbolic="YES" id="lbB-rJ-KNj"/>
|
||||
<constraint firstItem="ULl-vy-5gb" firstAttribute="top" relation="greaterThanOrEqual" secondItem="mUm-EE-6Is" secondAttribute="bottom" constant="8" symbolic="YES" id="xXT-VC-dgn"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Tracking" id="fyS-rY-bYp"/>
|
||||
@@ -934,6 +980,9 @@
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Speed" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="V9h-qX-rao">
|
||||
<rect key="frame" x="20" y="0.0" width="49.5" height="23.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="23.5" id="lKq-NM-hVD"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1008,85 +1057,219 @@
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="24z-mh-txV">
|
||||
<rect key="frame" x="20" y="198" width="560" height="140"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Vc-YY-1rh">
|
||||
<rect key="frame" x="0.0" y="80" width="560" height="60"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.67843137254901964" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="lFu-3n-8uz"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="EULA">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" red="0.5725490196078431" green="0.5725490196078431" blue="0.5725490196078431" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="openEULA:" destination="WMr-pC-C12" eventType="touchUpInside" id="PhA-bf-yMV"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MpZ-GD-6aE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="560" height="60"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.67843137254901964" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="xSB-Dr-qVN"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="License Information">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" red="0.5725490196078431" green="0.5725490196078431" blue="0.5725490196078431" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<segue destination="awJ-L8-hjX" kind="show" id="0cD-Vt-sEk"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="8Vc-YY-1rh" secondAttribute="trailing" id="0ns-WL-guw"/>
|
||||
<constraint firstItem="MpZ-GD-6aE" firstAttribute="top" secondItem="24z-mh-txV" secondAttribute="top" id="3z0-uD-NWx"/>
|
||||
<constraint firstItem="MpZ-GD-6aE" firstAttribute="leading" secondItem="24z-mh-txV" secondAttribute="leading" id="CgF-IV-BDx"/>
|
||||
<constraint firstItem="8Vc-YY-1rh" firstAttribute="top" secondItem="MpZ-GD-6aE" secondAttribute="bottom" constant="20" id="KgN-wG-9Pf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8Vc-YY-1rh" secondAttribute="bottom" id="XB1-I9-hVG"/>
|
||||
<constraint firstAttribute="trailing" secondItem="MpZ-GD-6aE" secondAttribute="trailing" id="rvL-Ze-CNy"/>
|
||||
<constraint firstItem="8Vc-YY-1rh" firstAttribute="leading" secondItem="24z-mh-txV" secondAttribute="leading" id="sv6-8L-lF0"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YpQ-wa-mW3">
|
||||
<rect key="frame" x="20" y="346" width="45.5" height="18"/>
|
||||
<rect key="frame" x="20" y="484" width="45.5" height="18"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1.0.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jsi-LA-7jU">
|
||||
<rect key="frame" x="20" y="372" width="29.5" height="18"/>
|
||||
<rect key="frame" x="20" y="510" width="29.5" height="18"/>
|
||||
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Vc-YY-1rh">
|
||||
<rect key="frame" x="20" y="416" width="560" height="60"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.67843137254901964" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="lFu-3n-8uz"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="EULA">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" red="0.5725490196078431" green="0.5725490196078431" blue="0.5725490196078431" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="openEULA:" destination="WMr-pC-C12" eventType="touchUpInside" id="PhA-bf-yMV"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MpZ-GD-6aE">
|
||||
<rect key="frame" x="20" y="340" width="560" height="60"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.67843137254901964" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="xSB-Dr-qVN"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="15"/>
|
||||
<state key="normal" title="License Information">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" red="0.5725490196078431" green="0.5725490196078431" blue="0.5725490196078431" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
||||
<integer key="value" value="5"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<segue destination="awJ-L8-hjX" kind="show" id="0cD-Vt-sEk"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" editable="NO" usesAttributedText="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yEk-7o-5Ua">
|
||||
<rect key="frame" x="20" y="20" width="560" height="300"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment>
|
||||
<string key="content">The SAP Sail InSight app supports live tracking of race boats by leveraging mobile phone technology, allowing the ability for friends and fans to follow racing whether onsite or online through live leader boards and 2D visualization. Following racing sailors can replay their races allowing the opportunity to review performance and optimize strategies all available at: </string>
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content="sapsailing.com">
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.2196078431372549" green="0.43137254901960786" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<url key="NSLink" string="http://sapsailing.com/"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.2196078431372549" green="0.43137254901960786" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<integer key="NSUnderline" value="1"/>
|
||||
<color key="NSUnderlineColor" red="0.2196078431372549" green="0.43137254901960786" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=" ">
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content" base64-UTF8="YES">
|
||||
Cg
|
||||
</string>
|
||||
<attributes>
|
||||
<font key="NSFont" size="16" name="TimesNewRomanPSMT"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=" ">
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content" base64-UTF8="YES">
|
||||
Cg
|
||||
</string>
|
||||
<attributes>
|
||||
<font key="NSFont" size="16" name="TimesNewRomanPSMT"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content">SAP supports US Sailing through the implementation of a range of innovative technology solutions, delivering analytics to help teams and sailors improve performance whilst also providing applications to help sailing operations run more efficiently.</string>
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content" base64-UTF8="YES">
|
||||
Cg
|
||||
</string>
|
||||
<attributes>
|
||||
<font key="NSFont" size="16" name="TimesNewRomanPSMT"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment content=" ">
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content" base64-UTF8="YES">
|
||||
Cg
|
||||
</string>
|
||||
<attributes>
|
||||
<font key="NSFont" size="16" name="TimesNewRomanPSMT"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content">As the national governing body for sailing, US Sailing provides leadership, integrity and growth for the sport including training and education programs for instructors and race officials alongside administration and oversight of competitive sailing across the country.</string>
|
||||
<attributes>
|
||||
<color key="NSColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<font key="NSFont" size="16" name="Calibri"/>
|
||||
<real key="NSKern" value="0.0"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
|
||||
<tabStops/>
|
||||
</paragraphStyle>
|
||||
<color key="NSStrokeColor" red="0.094117647058823528" green="0.21568627450980393" blue="0.41568627450980394" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
</attributedString>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="yEk-7o-5Ua" firstAttribute="trailing" secondItem="wZ4-L7-UtM" secondAttribute="trailingMargin" id="6Pr-e7-RK2"/>
|
||||
<constraint firstItem="8Vc-YY-1rh" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="Ccw-Sx-67a"/>
|
||||
<constraint firstItem="Jsi-LA-7jU" firstAttribute="top" secondItem="YpQ-wa-mW3" secondAttribute="bottom" constant="8" id="Cj5-RI-puj"/>
|
||||
<constraint firstItem="24z-mh-txV" firstAttribute="centerY" secondItem="wZ4-L7-UtM" secondAttribute="centerY" id="ETl-XU-Jke"/>
|
||||
<constraint firstItem="24z-mh-txV" firstAttribute="centerX" secondItem="wZ4-L7-UtM" secondAttribute="centerX" id="Qeq-G6-dez"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="24z-mh-txV" secondAttribute="trailing" id="Rl3-ut-OsJ"/>
|
||||
<constraint firstItem="UkO-Wl-zJn" firstAttribute="top" secondItem="Jsi-LA-7jU" secondAttribute="bottom" constant="8" id="CyR-gx-2J2"/>
|
||||
<constraint firstItem="MpZ-GD-6aE" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="EG0-ma-ckk"/>
|
||||
<constraint firstItem="yEk-7o-5Ua" firstAttribute="top" secondItem="TdH-NN-ozb" secondAttribute="bottom" constant="20" id="HGZ-ua-ZM2"/>
|
||||
<constraint firstItem="yEk-7o-5Ua" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="JKk-Ew-9V1"/>
|
||||
<constraint firstItem="8Vc-YY-1rh" firstAttribute="top" secondItem="MpZ-GD-6aE" secondAttribute="bottom" constant="16" id="Jy6-Nc-7Jc"/>
|
||||
<constraint firstItem="Jsi-LA-7jU" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="SgV-Fo-88q"/>
|
||||
<constraint firstItem="YpQ-wa-mW3" firstAttribute="top" secondItem="24z-mh-txV" secondAttribute="bottom" constant="8" id="igG-9X-MdL"/>
|
||||
<constraint firstItem="24z-mh-txV" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="tz7-OQ-537"/>
|
||||
<constraint firstItem="MpZ-GD-6aE" firstAttribute="top" secondItem="yEk-7o-5Ua" secondAttribute="bottom" constant="20" id="bfl-MB-ii4"/>
|
||||
<constraint firstItem="YpQ-wa-mW3" firstAttribute="top" secondItem="8Vc-YY-1rh" secondAttribute="bottom" constant="8" id="fR3-Gc-K7V"/>
|
||||
<constraint firstItem="MpZ-GD-6aE" firstAttribute="trailing" secondItem="wZ4-L7-UtM" secondAttribute="trailingMargin" id="fRY-RC-lgO"/>
|
||||
<constraint firstItem="8Vc-YY-1rh" firstAttribute="trailing" secondItem="wZ4-L7-UtM" secondAttribute="trailingMargin" id="gxG-bx-dTv"/>
|
||||
<constraint firstItem="YpQ-wa-mW3" firstAttribute="leading" secondItem="wZ4-L7-UtM" secondAttribute="leadingMargin" id="wev-ws-P1D"/>
|
||||
</constraints>
|
||||
</view>
|
||||
@@ -1098,6 +1281,7 @@
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="textView" destination="yEk-7o-5Ua" id="a7p-wJ-DDg"/>
|
||||
<outlet property="versionDescriptionLabel" destination="YpQ-wa-mW3" id="ndm-Jp-4j0"/>
|
||||
<outlet property="versionLabel" destination="Jsi-LA-7jU" id="b1V-A3-5jG"/>
|
||||
</connections>
|
||||
@@ -1360,15 +1544,17 @@
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="DE.png" width="64" height="64"/>
|
||||
<image name="applogo" width="365" height="96"/>
|
||||
<image name="camera" width="24" height="24"/>
|
||||
<image name="edit" width="33" height="33"/>
|
||||
<image name="home_bg" width="980" height="653"/>
|
||||
<image name="profile_placeholder" width="360" height="256"/>
|
||||
<image name="retry" width="24" height="24"/>
|
||||
<image name="scan_white" width="214" height="214"/>
|
||||
<image name="settings" width="22" height="22"/>
|
||||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="QMa-LQ-D8c"/>
|
||||
<segue reference="Xxn-jp-xEB"/>
|
||||
<segue reference="tzB-PL-31j"/>
|
||||
<segue reference="Irs-ey-Uhs"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import UIKit
|
||||
import CoreData
|
||||
|
||||
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIActionSheetDelegate, NSFetchedResultsControllerDelegate, QRCodeManagerDelegate {
|
||||
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate, QRCodeManagerDelegate {
|
||||
|
||||
enum AlertView: Int {
|
||||
case NoCameraAvailable
|
||||
@@ -25,12 +25,15 @@ class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDe
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet weak var tableViewHeight: NSLayoutConstraint!
|
||||
@IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
|
||||
@IBOutlet var vSplashScreen: UIView!
|
||||
|
||||
var fetchedResultsController: NSFetchedResultsController?
|
||||
private var qrCodeManager: QRCodeManager?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
loadSplashScreen()
|
||||
|
||||
// set QR manager, needed in case app is being open by custom URL
|
||||
qrCodeManager = QRCodeManager(delegate: self)
|
||||
@@ -61,6 +64,50 @@ class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDe
|
||||
let barButtonItem = UIBarButtonItem(customView: imageView)
|
||||
navigationItem.leftBarButtonItem = barButtonItem
|
||||
}
|
||||
|
||||
func loadSplashScreen() {
|
||||
|
||||
if let keyWindow = UIApplication.sharedApplication().keyWindow {
|
||||
|
||||
vSplashScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||
keyWindow.addSubview(vSplashScreen)
|
||||
|
||||
let lcTop = NSLayoutConstraint(item: vSplashScreen,
|
||||
attribute: NSLayoutAttribute.Top,
|
||||
relatedBy: NSLayoutRelation.Equal,
|
||||
toItem: keyWindow,
|
||||
attribute: NSLayoutAttribute.Top,
|
||||
multiplier: 1.0,
|
||||
constant: 0)
|
||||
let lcBottom = NSLayoutConstraint(item: vSplashScreen,
|
||||
attribute: NSLayoutAttribute.Bottom,
|
||||
relatedBy: NSLayoutRelation.Equal,
|
||||
toItem: keyWindow,
|
||||
attribute: NSLayoutAttribute.Bottom,
|
||||
multiplier: 1.0,
|
||||
constant: 0)
|
||||
let lcLeft = NSLayoutConstraint(item: vSplashScreen,
|
||||
attribute: NSLayoutAttribute.Left,
|
||||
relatedBy: NSLayoutRelation.Equal,
|
||||
toItem: keyWindow,
|
||||
attribute: NSLayoutAttribute.Left,
|
||||
multiplier: 1.0,
|
||||
constant: 0)
|
||||
let lcRight = NSLayoutConstraint(item: vSplashScreen,
|
||||
attribute: NSLayoutAttribute.Right,
|
||||
relatedBy: NSLayoutRelation.Equal,
|
||||
toItem: keyWindow,
|
||||
attribute: NSLayoutAttribute.Right,
|
||||
multiplier: 1.0,
|
||||
constant: 0)
|
||||
keyWindow.addConstraints([lcTop, lcBottom, lcLeft, lcRight])
|
||||
|
||||
weak var weakself = self
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||
weakself?.vSplashScreen.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
@@ -103,26 +150,39 @@ class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDe
|
||||
let url = notification.userInfo!["url"] as! String
|
||||
qrCodeManager!.parseUrl(url)
|
||||
}
|
||||
|
||||
// MARK: - UIActionSheetDelegate
|
||||
|
||||
func _DEBUG_OPEN_URL() {
|
||||
let url = "http://ec2-54-171-89-140.eu-west-1.compute.amazonaws.com:8888/tracking/checkin?event_id=71c7b531-fb1b-441c-b2fa-f4e9ff672d60&leaderboard_name=Ubigatta&competitor_id=9df7b4f6-611b-4be0-b028-c7b1bdd434c2"
|
||||
let url2 = "http://ec2-54-171-89-140.eu-west-1.compute.amazonaws.com:8888/tracking/checkin?event_id=71c7b531-fb1b-441c-b2fa-f4e9ff672d60&leaderboard_name=Ubigatta&competitor_id=a5a00800-daf8-0131-89e6-60a44ce903c3"
|
||||
qrCodeManager!.parseUrl(url2)
|
||||
}
|
||||
|
||||
@IBAction func showActionSheet(sender: AnyObject) {
|
||||
let actionSheet = UIActionSheet(title: nil, delegate: self, cancelButtonTitle: nil, destructiveButtonTitle: nil, otherButtonTitles: NSLocalizedString("Settings", comment: ""), NSLocalizedString("About", comment: ""), NSLocalizedString("Cancel", comment: ""))
|
||||
actionSheet.cancelButtonIndex = 3
|
||||
actionSheet.showInView(view)
|
||||
}
|
||||
|
||||
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
|
||||
switch buttonIndex{
|
||||
case 0:
|
||||
performSegueWithIdentifier("Settings", sender: actionSheet)
|
||||
break
|
||||
case 1:
|
||||
performSegueWithIdentifier("About", sender: actionSheet)
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
|
||||
if let popoverController = actionSheet.popoverPresentationController,
|
||||
let barButtonItem = sender as? UIBarButtonItem {
|
||||
popoverController.barButtonItem = barButtonItem
|
||||
}
|
||||
|
||||
let aSettings = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .Default) { (action) -> Void in
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.6 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||
self.performSegueWithIdentifier("SettingsFromHome", sender: actionSheet)
|
||||
}
|
||||
}
|
||||
actionSheet.addAction(aSettings)
|
||||
|
||||
let aAbout = UIAlertAction(title: NSLocalizedString("About", comment: ""), style: .Default) { (action) -> Void in
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.6 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||
self.performSegueWithIdentifier("AboutFromHome", sender: actionSheet)
|
||||
}
|
||||
}
|
||||
actionSheet.addAction(aAbout)
|
||||
|
||||
let aCancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil)
|
||||
actionSheet.addAction(aCancel)
|
||||
|
||||
presentViewController(actionSheet, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
@@ -208,6 +268,10 @@ class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDe
|
||||
// MARK: - Button actions
|
||||
|
||||
@IBAction func scanButtonTap(sender: AnyObject) {
|
||||
|
||||
// _DEBUG_OPEN_URL()
|
||||
// return;
|
||||
|
||||
if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
|
||||
let alertView = UIAlertView(title: NSLocalizedString("No camera available.", comment: ""), message: nil, delegate: nil, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
alertView.tag = AlertView.NoCameraAvailable.rawValue;
|
||||
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -73,8 +73,9 @@
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "167_iPhone_6Plus_App_Icon@2x.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 879 KiB After Width: | Height: | Size: 879 KiB |
|
Before Width: | Height: | Size: 760 KiB After Width: | Height: | Size: 760 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1008 KiB After Width: | Height: | Size: 1008 KiB |
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "applogo@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "applogo@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "retry@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 870 B |
@@ -6,8 +6,8 @@
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "sap_logo.png"
|
||||
"filename" : "sap_logo@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -5,7 +5,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>SAP Sail inSight</string>
|
||||
<string>SAP Sail InSight</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -30,7 +30,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>27</string>
|
||||
<string>37</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
@@ -51,6 +51,8 @@
|
||||
<array>
|
||||
<string>location</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="applogo" translatesAutoresizingMaskIntoConstraints="NO" id="XA8-DM-z3j">
|
||||
<rect key="frame" x="117.5" y="252" width="365" height="96"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="XA8-DM-z3j" secondAttribute="height" multiplier="365:96" id="nLx-D5-TPO"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="XA8-DM-z3j" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4Bv-Zq-ZzP"/>
|
||||
<constraint firstItem="XA8-DM-z3j" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="30" id="EFm-df-I71"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="XA8-DM-z3j" secondAttribute="trailing" constant="30" id="KiK-A3-oaY"/>
|
||||
<constraint firstItem="XA8-DM-z3j" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="TsS-GE-Hlz"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="applogo" width="365" height="96"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -45,6 +45,14 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
||||
if (coreLocationManager.respondsToSelector("requestAlwaysAuthorization")) {
|
||||
coreLocationManager.requestAlwaysAuthorization()
|
||||
}
|
||||
|
||||
// Now try everything to allow the app to use the GPS sensor
|
||||
// while in background
|
||||
coreLocationManager.pausesLocationUpdatesAutomatically = false;
|
||||
if #available(iOS 9, *) {
|
||||
coreLocationManager.allowsBackgroundLocationUpdates = true;
|
||||
}
|
||||
|
||||
coreLocationManager.startUpdatingLocation()
|
||||
coreLocationManager.startUpdatingHeading()
|
||||
coreLocationManager.delegate = self
|
||||
@@ -102,4 +110,4 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,17 +96,17 @@ class QRCodeManager : NSObject, UIAlertViewDelegate {
|
||||
|
||||
// get event
|
||||
APIManager.sharedManager.getEvent(qrcodeData!.eventId,
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject eventResponseObject) -> Void in
|
||||
success: { (operation, eventResponseObject) -> Void in
|
||||
self.eventDictionary = eventResponseObject as? [String: AnyObject]
|
||||
APIManager.sharedManager.getLeaderBoard(self.qrcodeData!.leaderBoardName,
|
||||
|
||||
// get leader board
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject leaderBoardResponseObject) -> Void in
|
||||
success: { (operation, leaderBoardResponseObject) -> Void in
|
||||
self.leaderBoardDictionary = leaderBoardResponseObject as? [String: AnyObject]
|
||||
APIManager.sharedManager.getCompetitor(self.qrcodeData!.competitorId,
|
||||
|
||||
// get competitor
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject competitorResponseObject) -> Void in
|
||||
success: { (operation, competitorResponseObject) -> Void in
|
||||
|
||||
APIManager.sharedManager.teamImage(self.qrcodeData!.competitorId, result: { (imageUrl) -> Void in
|
||||
|
||||
@@ -125,14 +125,14 @@ class QRCodeManager : NSObject, UIAlertViewDelegate {
|
||||
alertView.show()
|
||||
})
|
||||
|
||||
}, failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
}, failure: { (operation, error) -> Void in
|
||||
self.delegate.activityIndicatorView?.stopAnimating()
|
||||
let title = String(format: NSLocalizedString("Couldn't get competitor %@", comment: ""), self.qrcodeData!.competitorId!)
|
||||
let alertView = UIAlertView(title: title, message: error.localizedDescription, delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
alertView.tag = AlertView.ServerError.rawValue;
|
||||
alertView.show()
|
||||
|
||||
}) }, failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
}) }, failure: { (operation, error) -> Void in
|
||||
self.delegate.activityIndicatorView?.stopAnimating()
|
||||
let title = String(format: NSLocalizedString("Couldn't get leader board %@", comment: ""), self.qrcodeData!.leaderBoardName!)
|
||||
let alertView = UIAlertView(title: title, message: error.localizedDescription, delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
@@ -140,7 +140,7 @@ class QRCodeManager : NSObject, UIAlertViewDelegate {
|
||||
alertView.show()
|
||||
})
|
||||
|
||||
}, failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
}, failure: { (operation, error) -> Void in
|
||||
self.delegate.activityIndicatorView?.stopAnimating()
|
||||
let title = String(format: NSLocalizedString("Couldn't get event %@", comment: ""), self.qrcodeData!.eventId!)
|
||||
let alertView = UIAlertView(title: title, message: error.localizedDescription, delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
@@ -185,7 +185,7 @@ class QRCodeManager : NSObject, UIAlertViewDelegate {
|
||||
checkIn.imageUrl = teamImageURL
|
||||
|
||||
APIManager.sharedManager.checkIn(leaderBoardName, competitorId: competitorId, deviceUuid: DeviceUDIDManager.UDID, pushDeviceId: "", fromMillis: fromMillis,
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject eventResponseObject) -> Void in
|
||||
success: { (operation, eventResponseObject) -> Void in
|
||||
|
||||
// create core data objects
|
||||
let event = DataManager.sharedManager.newEvent(checkIn)
|
||||
@@ -197,7 +197,7 @@ class QRCodeManager : NSObject, UIAlertViewDelegate {
|
||||
DataManager.sharedManager.saveContext()
|
||||
|
||||
self.delegate.qrCodeOK?()
|
||||
}, failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
}, failure: { (operation, error) -> Void in
|
||||
self.delegate.activityIndicatorView?.stopAnimating()
|
||||
let title = String(format:NSLocalizedString("Couldn't check-in to %@", comment: ""), leaderBoardName);
|
||||
let alertView = UIAlertView(title: title, message: error.localizedDescription, delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
|
||||
@@ -18,13 +18,18 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
enum AlertView: Int {
|
||||
case CheckOut, Image, UploadFailed
|
||||
}
|
||||
|
||||
|
||||
struct RegattaViewUserDefaults {
|
||||
static let UploadDidFail = "UploadDidFail"
|
||||
}
|
||||
|
||||
var sourceTypes = [UIImagePickerControllerSourceType]()
|
||||
var sourceTypeNames = [String]()
|
||||
|
||||
@IBOutlet weak var imageView: UIImageView!
|
||||
@IBOutlet weak var yourTeamPhotoButton: UIButton!
|
||||
@IBOutlet weak var editTeamPhotoButton: UIButton!
|
||||
@IBOutlet weak var retryUploadTeamPhotoButton: UIButton!
|
||||
@IBOutlet weak var nameLabel: UILabel!
|
||||
@IBOutlet weak var flagImageView: UIImageView!
|
||||
@IBOutlet weak var sailLabel: UILabel!
|
||||
@@ -55,6 +60,10 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
dateFormatter.dateFormat = "MMM d, yyyy, h:mm a" // As per request - see mail 19.02.2016
|
||||
super.init(coder: aDecoder)!
|
||||
}
|
||||
|
||||
var uploadKey: String {
|
||||
return RegattaViewUserDefaults.UploadDidFail + "_" + DataManager.sharedManager.selectedCheckIn!.competitorId
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
@@ -62,6 +71,8 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
navigationItem.title = DataManager.sharedManager.selectedCheckIn!.leaderBoardName
|
||||
|
||||
openEventButton.setTitle(NSLocalizedString("Show Event", comment: ""), forState: UIControlState.Normal)
|
||||
|
||||
retryUploadTeamPhotoButton.hidden = !NSUserDefaults.standardUserDefaults().boolForKey(uploadKey)
|
||||
|
||||
// set regatta image, either load it from server or load from core data
|
||||
if DataManager.sharedManager.selectedCheckIn?.userImage != nil {
|
||||
@@ -78,10 +89,12 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
},
|
||||
failure: { (request:NSURLRequest!,response:NSHTTPURLResponse!, error:NSError!) -> Void in
|
||||
self.editTeamPhotoButton.hidden = true
|
||||
self.yourTeamPhotoButton.hidden = !self.retryUploadTeamPhotoButton.hidden
|
||||
}
|
||||
)
|
||||
} else {
|
||||
self.editTeamPhotoButton.hidden = true
|
||||
self.yourTeamPhotoButton.hidden = !self.retryUploadTeamPhotoButton.hidden
|
||||
}
|
||||
if (DataManager.sharedManager.selectedCheckIn?.competitor != nil) {
|
||||
let competitor = DataManager.sharedManager.selectedCheckIn!.competitor!
|
||||
@@ -211,7 +224,9 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
case 0:
|
||||
showCheckOutAlertView()
|
||||
case 1:
|
||||
performSegueWithIdentifier("Settings", sender: actionSheet)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.6 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||
self.performSegueWithIdentifier("Settings", sender: actionSheet)
|
||||
}
|
||||
break
|
||||
case 2:
|
||||
showImageAlertView(actionSheet)
|
||||
@@ -261,24 +276,32 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
imageView.image = image
|
||||
yourTeamPhotoButton.hidden = true
|
||||
editTeamPhotoButton.hidden = false
|
||||
retryUploadTeamPhotoButton.hidden = true
|
||||
let jpegData = UIImageJPEGRepresentation(image, 0.8)
|
||||
DataManager.sharedManager.selectedCheckIn!.userImage = jpegData
|
||||
APIManager.sharedManager.postTeamImage(DataManager.sharedManager.selectedCheckIn!.competitorId,
|
||||
imageData: jpegData,
|
||||
success: { (AnyObject responseObject) -> Void in
|
||||
success: { (responseObject) -> Void in
|
||||
// http://wiki.sapsailing.com/wiki/tracking-app/api-v1#Competitor-Information-%28in-general%29
|
||||
// "Additional Notes: Competitor profile image left out for now."
|
||||
let responseDictionary = responseObject as![String: AnyObject]
|
||||
let imageUrl = (responseDictionary["teamImageUri"]) as! String;
|
||||
DataManager.sharedManager.selectedCheckIn!.imageUrl = imageUrl;
|
||||
|
||||
NSUserDefaults.standardUserDefaults().setBool(false, forKey: self.uploadKey)
|
||||
NSUserDefaults.standardUserDefaults().synchronize()
|
||||
},
|
||||
failure: { (NSError error) -> Void in
|
||||
failure: { (error) -> Void in
|
||||
let alertView = UIAlertView(title: NSLocalizedString("Failed to upload image", comment: ""), message: error.localizedDescription, delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
|
||||
alertView.tag = AlertView.UploadFailed.rawValue;
|
||||
alertView.show()
|
||||
alertView.show()
|
||||
|
||||
NSUserDefaults.standardUserDefaults().setBool(true, forKey: self.uploadKey)
|
||||
NSUserDefaults.standardUserDefaults().synchronize()
|
||||
self.retryUploadTeamPhotoButton.hidden = false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Check-out
|
||||
func showCheckOutAlertView() {
|
||||
let alertView = UIAlertView(title: NSLocalizedString("Check-out of Regatta?", comment: ""), message: "", delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""), otherButtonTitles: NSLocalizedString("OK", comment: ""))
|
||||
@@ -302,9 +325,9 @@ class RegattaViewController : UIViewController, UIActionSheetDelegate, UINavigat
|
||||
competitorId: DataManager.sharedManager.selectedCheckIn!.competitorId,
|
||||
deviceUuid: DeviceUDIDManager.UDID,
|
||||
toMillis: toMillis,
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject competitorResponseObject) -> Void in
|
||||
success: { (operation, competitorResponseObject) -> Void in
|
||||
},
|
||||
failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
failure: { (operation, error) -> Void in
|
||||
}
|
||||
)
|
||||
DataManager.sharedManager.deleteCheckIn(DataManager.sharedManager.selectedCheckIn!)
|
||||
|
||||
@@ -80,7 +80,7 @@ class SendGPSFixController: NSObject {
|
||||
APIManager.sharedManager.initManager(serverUrl)
|
||||
if APIManager.sharedManager.networkAvailable {
|
||||
APIManager.sharedManager.postGPSFixes(DeviceUDIDManager.UDID, gpsFixes: gpsFixes,
|
||||
success: { (AFHTTPRequestOperation operation, AnyObject competitorResponseObject) -> Void in
|
||||
success: { (operation, competitorResponseObject) -> Void in
|
||||
print("sent GPS fixes")
|
||||
for gpsFix in gpsFixes {
|
||||
DataManager.sharedManager.managedObjectContext!.deleteObject(gpsFix)
|
||||
@@ -88,7 +88,7 @@ class SendGPSFixController: NSObject {
|
||||
let notification = NSNotification(name: NotificationType.gpsFixesSynced, object: self)
|
||||
NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP)
|
||||
},
|
||||
failure: { (AFHTTPRequestOperation operation, NSError error) -> Void in
|
||||
failure: { (operation, error) -> Void in
|
||||
print("error sending GPS fixes")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ class SettingsViewController: UITableViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
batterySavingSwitch.setOn(BatteryManager.sharedManager.batterySavingPreference, animated: true)
|
||||
|
||||
// add logo to top left
|
||||
let imageView = UIImageView(image: UIImage(named: "sap_logo"))
|
||||
let barButtonItem = UIBarButtonItem(customView: imageView)
|
||||
navigationItem.leftBarButtonItem = barButtonItem
|
||||
}
|
||||
|
||||
@IBAction func batterySavingChanged(sender: UISwitch) {
|
||||
|
||||
@@ -25,8 +25,12 @@ class SpeedViewController: UIViewController {
|
||||
|
||||
func newLocation(notification: NSNotification) {
|
||||
let ms = notification.userInfo!["speed"] as! Double
|
||||
let kn = ms * knPerMs
|
||||
speedLabel.text = String(format: "%0.1f kn", kn)
|
||||
if(ms >= 0) {
|
||||
let kn = ms * knPerMs
|
||||
speedLabel.text = String(format: "%0.1f kn", kn)
|
||||
} else {
|
||||
speedLabel.text = "– kn"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// SplashScreenDummy.swift
|
||||
// SAPTracker
|
||||
//
|
||||
// Created by computing on 02/12/14.
|
||||
// Copyright (c) 2014 com.sap.sailing. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/* Helper class used for created launch screens. */
|
||||
class SplashScreenDummy: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// add logo to top left
|
||||
let imageView = UIImageView(image: UIImage(named: "sap_logo"))
|
||||
let barButtonItem = UIBarButtonItem(customView: imageView)
|
||||
navigationItem.leftBarButtonItem = barButtonItem
|
||||
|
||||
//UIApplication.sharedApplication().statusBarHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
/* Uncomment this when creating launch screens. */
|
||||
/*
|
||||
extension UINavigationBar {
|
||||
public override func sizeThatFits(size: CGSize) -> CGSize {
|
||||
let newSize = CGSizeMake(UIScreen.mainScreen().bounds.width, 64)
|
||||
return newSize
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -8,11 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class TimerViewController: UIViewController, UIAlertViewDelegate {
|
||||
enum AlertView: Int {
|
||||
case StopTracking
|
||||
}
|
||||
|
||||
class TimerViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var trackingTimeLabel: UILabel!
|
||||
|
||||
let startDate = NSDate()
|
||||
@@ -37,33 +34,4 @@ class TimerViewController: UIViewController, UIAlertViewDelegate {
|
||||
let timerDate = NSDate(timeIntervalSince1970: timeInterval)
|
||||
trackingTimeLabel.text = dateFormatter.stringFromDate(timerDate)
|
||||
}
|
||||
|
||||
// MARK:- Buttons
|
||||
|
||||
/* Stop tracking, go back to regattas view */
|
||||
@IBAction func stopTrackingButtonTapped(sender: AnyObject) {
|
||||
let alertView = UIAlertView(title: NSLocalizedString("Stop tracking?", comment: ""), message: "", delegate: self, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""), otherButtonTitles: NSLocalizedString("Stop", comment: ""))
|
||||
alertView.tag = AlertView.StopTracking.rawValue;
|
||||
alertView.show()
|
||||
}
|
||||
|
||||
/* Alert view delegate */
|
||||
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
|
||||
switch alertView.tag {
|
||||
// Stop tracking?
|
||||
case AlertView.StopTracking.rawValue:
|
||||
switch buttonIndex {
|
||||
case alertView.cancelButtonIndex:
|
||||
break
|
||||
default:
|
||||
LocationManager.sharedManager.stopTracking()
|
||||
SendGPSFixController.sharedManager.checkIn = nil
|
||||
self.dismissViewControllerAnimated(true, completion: nil)
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,6 +39,23 @@ class TrackingViewController : UIViewController {
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector:"newLocation:", name:LocationManager.NotificationType.newLocation, object: nil)
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector:"locationManagerFailed:", name:LocationManager.NotificationType.locationManagerFailed, object: nil)
|
||||
}
|
||||
|
||||
// MARK:- Buttons
|
||||
|
||||
/* Stop tracking, go back to regattas view */
|
||||
@IBAction func stopTrackingButtonTapped(sender: AnyObject) {
|
||||
|
||||
let alertController = UIAlertController(title: NSLocalizedString("Stop tracking?", comment: ""), message: "", preferredStyle: .Alert)
|
||||
let aCancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil)
|
||||
alertController.addAction(aCancel)
|
||||
let aStop = UIAlertAction(title: NSLocalizedString("Stop", comment: ""), style: .Default) { action in
|
||||
LocationManager.sharedManager.stopTracking()
|
||||
SendGPSFixController.sharedManager.checkIn = nil
|
||||
self.dismissViewControllerAnimated(true, completion: nil)
|
||||
}
|
||||
alertController.addAction(aStop)
|
||||
presentViewController(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
// MARK:- Notifications
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class TracTrac {
|
||||
raceRecords = getTracTracAdapter().getTracTracRaceRecords(new URL(eventJsonURL), /*loadClientParam*/ false);
|
||||
List<TracTracRaceRecordDTO> result = new ArrayList<TracTracRaceRecordDTO>();
|
||||
for (RaceRecord raceRecord : raceRecords.getB()) {
|
||||
if (listHiddenRaces == false && raceRecord.getRaceStatus().equals(TracTracConnectionConstants.HIDDEN_STATUS)) {
|
||||
if (listHiddenRaces == false && raceRecord.getRaceVisibility().equals(TracTracConnectionConstants.HIDDEN_VISIBILITY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java/com/sap/sailing/dashboards/gwt/client/i18n/StringMessages.properties=UTF-8
|
||||
encoding//src/main/java/com/sap/sailing/dashboards/gwt/client/i18n/StringMessages_de.properties=UTF-8
|
||||
@@ -1,140 +1,140 @@
|
||||
package com.sap.sailing.datamining;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBoolSumAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceAverageAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMaxAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMedianAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMinAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceSumAggregationProcessor;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sse.datamining.DataSourceProvider;
|
||||
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.components.DataRetrieverChainDefinition;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.impl.AbstractDataMiningActivatorWithPredefinedQueries;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl;
|
||||
|
||||
public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries {
|
||||
|
||||
private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/Sailing_StringMessages";
|
||||
private static final SailingClusterGroups clusterGroups = new SailingClusterGroups();
|
||||
|
||||
private static Activator INSTANCE;
|
||||
|
||||
private BundleContext context = null;
|
||||
|
||||
private final ResourceBundleStringMessages sailingServerStringMessages;
|
||||
private final SailingDataRetrievalChainDefinitions dataRetrieverChainDefinitions;
|
||||
private final SailingPredefinedQueries predefinedQueries;
|
||||
private Collection<DataSourceProvider<?>> dataSourceProviders;
|
||||
private boolean dataSourceProvidersHaveBeenInitialized;
|
||||
|
||||
public Activator() {
|
||||
sailingServerStringMessages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, getClassLoader());
|
||||
dataRetrieverChainDefinitions = new SailingDataRetrievalChainDefinitions();
|
||||
predefinedQueries = new SailingPredefinedQueries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
INSTANCE = this;
|
||||
this.context = context;
|
||||
dataSourceProvidersHaveBeenInitialized = false;
|
||||
super.start(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
this.context = null;
|
||||
INSTANCE = null;
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundleStringMessages getStringMessages() {
|
||||
return sailingServerStringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Class<?>> getClassesWithMarkedMethods() {
|
||||
Set<Class<?>> internalClasses = new HashSet<>();
|
||||
internalClasses.add(HasTrackedRaceContext.class);
|
||||
internalClasses.add(HasRaceResultOfCompetitorContext.class);
|
||||
internalClasses.add(HasTrackedLegContext.class);
|
||||
internalClasses.add(HasTrackedLegOfCompetitorContext.class);
|
||||
internalClasses.add(HasGPSFixContext.class);
|
||||
internalClasses.add(HasMarkPassingContext.class);
|
||||
internalClasses.add(HasRaceOfCompetitorContext.class);
|
||||
internalClasses.add(HasLeaderboardGroupContext.class);
|
||||
internalClasses.add(HasLeaderboardContext.class);
|
||||
return internalClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DataRetrieverChainDefinition<?, ?>> getDataRetrieverChainDefinitions() {
|
||||
return dataRetrieverChainDefinitions.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DataSourceProvider<?>> getDataSourceProviders() {
|
||||
if (!dataSourceProvidersHaveBeenInitialized) {
|
||||
initializeDataSourceProviders();
|
||||
dataSourceProvidersHaveBeenInitialized = true;
|
||||
}
|
||||
return dataSourceProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AggregationProcessorDefinition<?, ?>> getAggregationProcessorDefinitions() {
|
||||
HashSet<AggregationProcessorDefinition<?, ?>> aggregators = new HashSet<>();
|
||||
aggregators.add(ParallelBoolSumAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceSumAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceAverageAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMaxAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMinAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMedianAggregationProcessor.getDefinition());
|
||||
return aggregators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> getPredefinedQueries() {
|
||||
return predefinedQueries.get();
|
||||
}
|
||||
|
||||
private void initializeDataSourceProviders() {
|
||||
dataSourceProviders = new HashSet<>();
|
||||
dataSourceProviders.add(new RacingEventServiceProvider(context));
|
||||
}
|
||||
|
||||
public static ClusterGroup<Speed> getWindStrengthInBeaufortClusterGroup() {
|
||||
return clusterGroups.getWindStrengthInBeaufortCluster();
|
||||
}
|
||||
|
||||
public static Activator getDefault() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new Activator(); // probably non-OSGi case, as in test execution
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.datamining;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.datamining.data.HasMarkPassingContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelBoolSumAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceAverageAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMaxAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMedianAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMinAggregationProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceSumAggregationProcessor;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sse.datamining.DataSourceProvider;
|
||||
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
|
||||
import com.sap.sse.datamining.components.DataRetrieverChainDefinition;
|
||||
import com.sap.sse.datamining.data.ClusterGroup;
|
||||
import com.sap.sse.datamining.impl.AbstractDataMiningActivatorWithPredefinedQueries;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl;
|
||||
|
||||
public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries {
|
||||
|
||||
private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/Sailing_StringMessages";
|
||||
private static final SailingClusterGroups clusterGroups = new SailingClusterGroups();
|
||||
|
||||
private static Activator INSTANCE;
|
||||
|
||||
private BundleContext context = null;
|
||||
|
||||
private final ResourceBundleStringMessages sailingServerStringMessages;
|
||||
private final SailingDataRetrievalChainDefinitions dataRetrieverChainDefinitions;
|
||||
private final SailingPredefinedQueries predefinedQueries;
|
||||
private Collection<DataSourceProvider<?>> dataSourceProviders;
|
||||
private boolean dataSourceProvidersHaveBeenInitialized;
|
||||
|
||||
public Activator() {
|
||||
sailingServerStringMessages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, getClassLoader());
|
||||
dataRetrieverChainDefinitions = new SailingDataRetrievalChainDefinitions();
|
||||
predefinedQueries = new SailingPredefinedQueries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
INSTANCE = this;
|
||||
this.context = context;
|
||||
dataSourceProvidersHaveBeenInitialized = false;
|
||||
super.start(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
this.context = null;
|
||||
INSTANCE = null;
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundleStringMessages getStringMessages() {
|
||||
return sailingServerStringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Class<?>> getClassesWithMarkedMethods() {
|
||||
Set<Class<?>> internalClasses = new HashSet<>();
|
||||
internalClasses.add(HasTrackedRaceContext.class);
|
||||
internalClasses.add(HasRaceResultOfCompetitorContext.class);
|
||||
internalClasses.add(HasTrackedLegContext.class);
|
||||
internalClasses.add(HasTrackedLegOfCompetitorContext.class);
|
||||
internalClasses.add(HasGPSFixContext.class);
|
||||
internalClasses.add(HasMarkPassingContext.class);
|
||||
internalClasses.add(HasRaceOfCompetitorContext.class);
|
||||
internalClasses.add(HasLeaderboardGroupContext.class);
|
||||
internalClasses.add(HasLeaderboardContext.class);
|
||||
return internalClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DataRetrieverChainDefinition<?, ?>> getDataRetrieverChainDefinitions() {
|
||||
return dataRetrieverChainDefinitions.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DataSourceProvider<?>> getDataSourceProviders() {
|
||||
if (!dataSourceProvidersHaveBeenInitialized) {
|
||||
initializeDataSourceProviders();
|
||||
dataSourceProvidersHaveBeenInitialized = true;
|
||||
}
|
||||
return dataSourceProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AggregationProcessorDefinition<?, ?>> getAggregationProcessorDefinitions() {
|
||||
HashSet<AggregationProcessorDefinition<?, ?>> aggregators = new HashSet<>();
|
||||
aggregators.add(ParallelBoolSumAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceSumAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceAverageAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMaxAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMinAggregationProcessor.getDefinition());
|
||||
aggregators.add(ParallelDistanceMedianAggregationProcessor.getDefinition());
|
||||
return aggregators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> getPredefinedQueries() {
|
||||
return predefinedQueries.getQueries();
|
||||
}
|
||||
|
||||
private void initializeDataSourceProviders() {
|
||||
dataSourceProviders = new HashSet<>();
|
||||
dataSourceProviders.add(new RacingEventServiceProvider(context));
|
||||
}
|
||||
|
||||
public static ClusterGroup<Speed> getWindStrengthInBeaufortClusterGroup() {
|
||||
return clusterGroups.getWindStrengthInBeaufortCluster();
|
||||
}
|
||||
|
||||
public static Activator getDefault() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new Activator(); // probably non-OSGi case, as in test execution
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,143 +1,194 @@
|
||||
package com.sap.sailing.datamining;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedRaceRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.datamining.shared.impl.dto.AggregationProcessorDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverLevelDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.LocalizedTypeDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
|
||||
|
||||
public class SailingPredefinedQueries {
|
||||
|
||||
private final Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> predefinedQueries;
|
||||
|
||||
public SailingPredefinedQueries() {
|
||||
predefinedQueries = new HashMap<>();
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier("AvgSpeed_Per_Regatta-Race", "Average Speed grouped by Regatta Name and Race Name"),
|
||||
create_AvgSpeed_Per_Regatta_Race());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier("AvgSpeed_Per_Competitor-LegType", "Average Speed grouped by Competitor Team Name and Leg Type"),
|
||||
create_AvgSpeed_Per_Competitor_LegType());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier("SumDistance_Per_Competitor-LegType", "Sum of the traveled Distance grouped by Competitor Team Name and Leg Type"),
|
||||
create_SumDistance_Per_Competitor_LegType());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier("SumManeuvers_Per_Competitor", "Sum of the performed Maneuvers grouped by Competitor Team Name"),
|
||||
create_SumManeuvers_Per_Competitor());
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_AvgSpeed_Per_Regatta_Race() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getGPSFix().getSpeed().getKnots()", HasGPSFixContext.class.getName(), double.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Average", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(5, GPSFixRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasGPSFixContext.class.getName(), "GPS-Fix"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getRegatta().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getRace().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_AvgSpeed_Per_Competitor_LegType() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getGPSFix().getSpeed().getKnots()", HasGPSFixContext.class.getName(), double.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Average", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(5, GPSFixRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasGPSFixContext.class.getName(), "GPS-Fix"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getCompetitor().getTeam().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getLegType()", HasGPSFixContext.class.getName(), LegType.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_SumDistance_Per_Competitor_LegType() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getDistanceTraveled()", HasTrackedLegOfCompetitorContext.class.getName(), Distance.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Sum", Distance.class.getName(), Distance.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getCompetitor().getTeam().getName()", HasTrackedLegOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegContext().getLegType()", HasTrackedLegOfCompetitorContext.class.getName(), LegType.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_SumManeuvers_Per_Competitor() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getNumberOfManeuvers()", HasRaceOfCompetitorContext.class.getName(), int.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Sum", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, RaceOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasRaceOfCompetitorContext.class.getName(), "Competitor"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getCompetitor().getTeam().getName()", HasRaceOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
public Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> get() {
|
||||
return predefinedQueries;
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.datamining;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasGPSFixContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedLegRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.components.TrackedRaceRetrievalProcessor;
|
||||
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
|
||||
import com.sap.sse.datamining.shared.impl.dto.AggregationProcessorDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverLevelDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.LocalizedTypeDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
|
||||
|
||||
public class SailingPredefinedQueries {
|
||||
private final Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> predefinedQueries;
|
||||
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_REGATTA_RACE = "AvgSpeed_Per_Regatta-Race";
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE = "AvgSpeed_Per_Competitor-LegType";
|
||||
public final static String QUERY_AVERAGE_SPEED_PER_COMPETITOR = "AvgSpeed_Per_Competitor";
|
||||
public final static String QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE = "DistanceTraveled_Per_Competitor-LegType";
|
||||
public final static String QUERY_DISTANCE_TRAVELED_PER_COMPETITOR = "DistanceTraveled_Per_Competitor";
|
||||
public final static String QUERY_MANEUVERS_PER_COMPETITOR = "Maneuvers_Per_Competitor";
|
||||
|
||||
public SailingPredefinedQueries() {
|
||||
predefinedQueries = new HashMap<>();
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_AVERAGE_SPEED_PER_REGATTA_RACE, "Average Speed grouped by regatta name and race name"),
|
||||
create_AvgSpeed_Per_Regatta_Race());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_AVERAGE_SPEED_PER_COMPETITOR_LEGTYPE, "Average speed grouped by competitor/team name and leg type"),
|
||||
create_AvgSpeed_Per_Competitor_LegType());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_AVERAGE_SPEED_PER_COMPETITOR, "Average speed grouped by competitor/team name"),
|
||||
create_AvgSpeed_Per_Competitor());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_DISTANCE_TRAVELED_PER_COMPETITOR_LEGTYPE, "Distance traveled grouped by competitor/team name and leg type"),
|
||||
create_SumTraveledDistance_Per_Competitor_LegType());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_DISTANCE_TRAVELED_PER_COMPETITOR, "Distance traveled grouped by competitor/team name and leg type"),
|
||||
create_SumTraveledDistance_Per_Competitor());
|
||||
predefinedQueries.put(new PredefinedQueryIdentifier(QUERY_MANEUVERS_PER_COMPETITOR, "Maneuvers grouped by competitor/team name"),
|
||||
create_SumManeuvers_Per_Competitor());
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_AvgSpeed_Per_Regatta_Race() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getGPSFix().getSpeed().getKnots()", HasGPSFixContext.class.getName(), double.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Average", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(5, GPSFixRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasGPSFixContext.class.getName(), "GPS-Fix"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getRegatta().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getTrackedRaceContext().getRace().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_AvgSpeed_Per_Competitor_LegType() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getGPSFix().getSpeed().getKnots()", HasGPSFixContext.class.getName(), double.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Average", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(5, GPSFixRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasGPSFixContext.class.getName(), "GPS-Fix"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getCompetitor().getTeam().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getTrackedLegContext().getLegType()", HasGPSFixContext.class.getName(), LegType.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_SumTraveledDistance_Per_Competitor_LegType() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getDistanceTraveled()", HasTrackedLegOfCompetitorContext.class.getName(), Distance.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Sum", Distance.class.getName(), Distance.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getCompetitor().getTeam().getName()", HasTrackedLegOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getTrackedLegContext().getLegType()", HasTrackedLegOfCompetitorContext.class.getName(), LegType.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_AvgSpeed_Per_Competitor() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getGPSFix().getSpeed().getKnots()", HasGPSFixContext.class.getName(), double.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Average", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(5, GPSFixRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasGPSFixContext.class.getName(), "GPS-Fix"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedLegOfCompetitorContext().getCompetitor().getTeam().getName()", HasGPSFixContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_SumTraveledDistance_Per_Competitor() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getDistanceTraveled()", HasTrackedLegOfCompetitorContext.class.getName(), Distance.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Sum", Distance.class.getName(), Distance.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, TrackedLegRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegContext.class.getName(), "Leg"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(4, TrackedLegOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedLegOfCompetitorContext.class.getName(), "Leg of competitor"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getCompetitor().getTeam().getName()", HasTrackedLegOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
private StatisticQueryDefinitionDTO create_SumManeuvers_Per_Competitor() {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getNumberOfManeuvers()", HasRaceOfCompetitorContext.class.getName(), int.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Sum", Number.class.getName(), Number.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, LeaderboardGroupRetrievalProcessor.class.getName(), new LocalizedTypeDTO(LeaderboardGroupWithContext.class.getName(), "Leaderboard Group"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, LeaderboardRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), "Leaderboard"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, TrackedRaceRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), "Race"), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, RaceOfCompetitorRetrievalProcessor.class.getName(), new LocalizedTypeDTO(HasRaceOfCompetitorContext.class.getName(), "Competitor"), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("", RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("default", statistic, aggregator, retrieverChain);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getCompetitor().getTeam().getName()", HasRaceOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
public Map<PredefinedQueryIdentifier, StatisticQueryDefinitionDTO> getQueries() {
|
||||
return predefinedQueries;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ Export-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.confidence,
|
||||
com.sap.sailing.domain.common.confidence.impl,
|
||||
com.sap.sailing.domain.common.dto,
|
||||
com.sap.sailing.domain.common.i18n,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.media,
|
||||
com.sap.sailing.domain.common.quadtree,
|
||||
|
||||
@@ -16,7 +16,12 @@ public abstract class AbstractSpeedImpl implements Speed {
|
||||
|
||||
@Override
|
||||
public Distance travel(TimePoint t1, TimePoint t2) {
|
||||
return new NauticalMileDistance((t2.asMillis() - t1.asMillis()) / 1000. / 3600. * getKnots());
|
||||
return travel(t1.until(t2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance travel(Duration duration) {
|
||||
return new NauticalMileDistance(duration.asHours() * getKnots());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,6 +26,7 @@ public enum BoatClassMasterdata {
|
||||
CANOE_IC ("International Canoe", true, 5.20, 1.01, BoatHullType.MONOHULL, true, "Canoe IC", "Canoe-IC", "IC", "Kanu IC", "International Canoe", "International 10 Sq.m. Sailing Canoe"),
|
||||
CANOE_TAIFUN ("Canoe Taifun", true, 5.20, 1.32, BoatHullType.MONOHULL, false, "Taifun", "Taifun Kanu", "Kanu Taifun"),
|
||||
CONTENDER ("Contender", true, 4.88, 1.42, BoatHullType.MONOHULL, false),
|
||||
CC_30 ("C&C 30", true, 9.12, 3.25, BoatHullType.MONOHULL, true),
|
||||
D_ONE ("D-One", true, 4.23, 2.31, BoatHullType.MONOHULL, true, "Devoti D-One", "DOne", "D_One"),
|
||||
DRAGON_INT ("Dragon Int.", true, 8.89, 1.96, BoatHullType.MONOHULL, true, "Drachen", "Dragon"),
|
||||
DYAS("Dyas", true, 7.15, 1.95, BoatHullType.MONOHULL, true),
|
||||
@@ -35,13 +36,15 @@ public enum BoatClassMasterdata {
|
||||
EUROPE_INT ("Europe Int.", true, 3.35, 1.35, BoatHullType.MONOHULL, false, "Europe"),
|
||||
F_18 ("Formula 18", true, 6.85, 2.25, BoatHullType.CATAMARAN, true, "F18", "F-18"),
|
||||
FARR_30 ("Farr 30", true, 9.42, 3.08, BoatHullType.MONOHULL, true, "F30", "F-30", "Farr-30"),
|
||||
FARR_280 ("Farr 280", true, 8.72, 2.87, BoatHullType.MONOHULL, true, "F280", "F-280", "Farr-280"),
|
||||
FINN ("Finn", true, 4.50, 1.51, BoatHullType.MONOHULL, false),
|
||||
FLYING_DUTCHMAN ("Flying Dutchman", true, 6.10, 1.80, BoatHullType.MONOHULL, true),
|
||||
FLYING_DUTCHMAN ("Flying Dutchman", true, 6.10, 1.80, BoatHullType.MONOHULL, true, "FD"),
|
||||
FLYING_PHANTOM ("Flying Phantom", true, 5.52, 3.00, BoatHullType.CATAMARAN, true),
|
||||
FOLKBOAT ("Folkboat", true, 7.68, 2.20, BoatHullType.MONOHULL, false, "Folke", "Folkeboot"),
|
||||
FUN ("FUN", true, 7.20, 2.45, BoatHullType.MONOHULL, true, "FUN O.D.", "FUN OD", "Open FUN"),
|
||||
F_16 ("Formula 16", true, 5.00, 2.50, BoatHullType.CATAMARAN, true, "F16", "F-16"),
|
||||
GC_32 ("GC 32", false, 10.0, 6.00, BoatHullType.CATAMARAN, true, "GC32", "GC-32"),
|
||||
GP_26 ("GP 26", true, 7.90, 2.55, BoatHullType.MONOHULL, true, "GP26", "GP-26"),
|
||||
HOBIE_16 ("Hobie 16", true, 5.05, 2.41, BoatHullType.CATAMARAN, false, "H16"),
|
||||
H_BOAT ("H-Boat", true, 8.28, 2.18, BoatHullType.MONOHULL, true, "HB"),
|
||||
HOBIE_TIGER ("Hobie Tiger", true, 5.51, 2.60, BoatHullType.CATAMARAN, true),
|
||||
@@ -51,6 +54,9 @@ public enum BoatClassMasterdata {
|
||||
J24 ("J/24", true, 7.32, 2.67, BoatHullType.MONOHULL, true, "J24", "J-24"),
|
||||
J70 ("J/70", true, 6.93, 2.25, BoatHullType.MONOHULL, true, "J70", "J-70"),
|
||||
J80 ("J/80", true, 8.0, 2.51, BoatHullType.MONOHULL, true, "J80", "J-80"),
|
||||
J88 ("J/88", true, 8.9, 1.89, BoatHullType.MONOHULL, true, "J88", "J-88"),
|
||||
J105 ("J/105", true, 10.52, 3.35, BoatHullType.MONOHULL, true, "J105", "J-105"),
|
||||
J111 ("J/111", true, 11.1, 3.29, BoatHullType.MONOHULL, true, "J111", "J-111"),
|
||||
KIELZUGVOGEL ("Kielzugvogel", true, 5.80, 1.88, BoatHullType.MONOHULL, false, "KZV"),
|
||||
KITE ("Kite", true, 3.35, 1.52, BoatHullType.MONOHULL, false),
|
||||
LASER_2 ("Laser 2", true, 4.39, 1.42, BoatHullType.MONOHULL, false, "Laser II", "Laser2", "Laser-2", "Laser-II"),
|
||||
@@ -59,6 +65,7 @@ public enum BoatClassMasterdata {
|
||||
LASER_INT ("Laser Int.", true, 4.19, 1.39, BoatHullType.MONOHULL, false, "Laser", "LSR"),
|
||||
LASER_SB3 ("Laser SB3", true, 6.15, 2.15, BoatHullType.MONOHULL, false, "LSB3", "SB20"),
|
||||
LAGO_26 ("Lago 26", true, 7.95, 2.50, BoatHullType.MONOHULL, true, "Lago26"),
|
||||
MELGES_20 ("Melges 20", true, 6.10, 2.13, BoatHullType.MONOHULL, true, "Melges-20", "M20"),
|
||||
MELGES_24 ("Melges 24", true, 7.32, 2.50, BoatHullType.MONOHULL, true, "Melges-24", "M24"),
|
||||
MINI_TRANSAT ("Mini Transat 6.50", true, 6.50, 3.00, BoatHullType.MONOHULL, true, "Mini Transat"),
|
||||
MUSTO_SKIFF ("Musto Skiff", true, 4.55, 1.35, BoatHullType.MONOHULL, true, "Musto Performance Skiff", "MPS", "Musto"),
|
||||
@@ -78,14 +85,20 @@ public enum BoatClassMasterdata {
|
||||
STAR ("Star", true, 6.92, 1.74, BoatHullType.MONOHULL, false, "STR"),
|
||||
STREAMLINE ("Streamline", true, 7.15, 2.55, BoatHullType.MONOHULL, true),
|
||||
SWAN_45 ("Swan 45", true, 13.83, 3.91, BoatHullType.MONOHULL, true, "Swan", "Swan-45"),
|
||||
TARTAN_10 ("Tartan 10", true, 10.10, 2.82, BoatHullType.MONOHULL, true),
|
||||
TORNADO ("Tornado Catamaran", true, 6.10, 3.02, BoatHullType.CATAMARAN, true, "Tornado", "Tornado Cat"),
|
||||
TRIAS ("Trias", true, 9.20, 2.12, BoatHullType.MONOHULL, true),
|
||||
VIPER_640 ("Viper 640", true, 6.43, 2.49, BoatHullType.MONOHULL, true),
|
||||
VX_ONE ("VX ONE", true, 5.79, 2.19, BoatHullType.MONOHULL, true, "VX-ONE"),
|
||||
X_99 ("X-99", true, 9.96, 2.95, BoatHullType.MONOHULL, true, "X99"),
|
||||
|
||||
// multi-class "boat classes"; to be replaced at some later point in time by something like a RegattaClass
|
||||
ORC ("ORC", true, 13.83, 3.91, BoatHullType.MONOHULL, true),
|
||||
ORC_CLUB ("ORC Club", true, 13.83, 3.91, BoatHullType.MONOHULL, true),
|
||||
ORC_INTERNATIONAL ("ORC International", true, 13.83, 3.91, BoatHullType.MONOHULL, true, "ORC Int.");
|
||||
ORC_INTERNATIONAL ("ORC International", true, 13.83, 3.91, BoatHullType.MONOHULL, true, "ORC Int."),
|
||||
|
||||
// Performance Handicap Racing Fleet (PHRF) is a handicap system used for racing in North America
|
||||
PHRF ("PHRF", true, 13.83, 3.91, BoatHullType.MONOHULL, true);
|
||||
|
||||
private final String displayName;
|
||||
private final String[] alternativeNames;
|
||||
|
||||
@@ -9,15 +9,23 @@ import java.util.List;
|
||||
* When modifying these values also check res/preferences.xml of racecommittee.app!
|
||||
*/
|
||||
public enum CourseDesignerMode {
|
||||
UNKNOWN("Unknown"),
|
||||
BY_NAME("By-Name Course Designer"), // O2, O3, I2,...
|
||||
BY_MAP("By-Map Course Designer"), // Map-based Course Designer
|
||||
BY_MARKS("By-Marks Course Designer"); // ESS
|
||||
UNKNOWN("Unknown", /* waypointSequenceValid */ false),
|
||||
BY_NAME("By-Name Course Designer", /* waypointSequenceValid */ false), // O2, O3, I2,...
|
||||
BY_MAP("By-Map Course Designer", /* waypointSequenceValid */ true), // Map-based Course Designer
|
||||
BY_MARKS("By-Marks Course Designer", /* waypointSequenceValid */ true), // ESS
|
||||
ADMIN_CONSOLE("Administration Console", /* waypointSequenceValid */ true);
|
||||
|
||||
private String displayName;
|
||||
private final String displayName;
|
||||
|
||||
/**
|
||||
* Some course designers may only be able to tell, say, a name for the new course but not
|
||||
* necessarily a valid waypoint sequence. This flag tells.
|
||||
*/
|
||||
private final boolean waypointSequenceValid;
|
||||
|
||||
private CourseDesignerMode(String displayName) {
|
||||
private CourseDesignerMode(String displayName, boolean waypointSequenceValid) {
|
||||
this.displayName = displayName;
|
||||
this.waypointSequenceValid = waypointSequenceValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,6 +33,10 @@ public enum CourseDesignerMode {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public boolean isWaypointSequenceValid() {
|
||||
return waypointSequenceValid;
|
||||
}
|
||||
|
||||
public static CourseDesignerMode[] validValues() {
|
||||
List<CourseDesignerMode> validValues = new ArrayList<CourseDesignerMode>();
|
||||
for (CourseDesignerMode type : values()) {
|
||||
|
||||
@@ -4,14 +4,40 @@ import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface DataImportProgress extends Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Helper for i18n of import sub progresses messages. A method according to the messageKey is required
|
||||
* in com.sap.sailing.gwt.ui.masterdataimport.MasterDataImportSubProgressMessages interface.
|
||||
*/
|
||||
enum SubProgress {
|
||||
CONNECTION_SETUP("connectionSetup"),
|
||||
CONNECTION_ESTABLISH("connectionEstablish"),
|
||||
TRANSFER_STARTED("transferStarted"),
|
||||
TRANSFER_COMPLETED("transferCompleted"),
|
||||
IMPORT_INIT("importInit"),
|
||||
IMPORT_WAIT("importWait"),
|
||||
IMPORT_LEADERBOARD_GROUPS("importLeaderboardGroups"),
|
||||
IMPORT_WIND_TRACKS("importWindTracks"),
|
||||
UPDATE_EVENT_LEADERBOARD_GROUP_LINKS("updateEventLeaderboardGroupLinks");
|
||||
|
||||
private final String messageKey;
|
||||
|
||||
private SubProgress(String messageKey) {
|
||||
this.messageKey = messageKey;
|
||||
}
|
||||
|
||||
public String getMessageKey() {
|
||||
return messageKey;
|
||||
}
|
||||
}
|
||||
|
||||
double getOverallProgressPct();
|
||||
|
||||
void setOverAllProgressPct(double pct);
|
||||
|
||||
String getNameOfCurrentSubProgress();
|
||||
|
||||
void setNameOfCurrentSubProgress(String name);
|
||||
|
||||
DataImportSubProgress getCurrentSubProgress();
|
||||
|
||||
void setCurrentSubProgress(DataImportSubProgress subProgress);
|
||||
|
||||
double getCurrentSubProgressPct();
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import com.sap.sailing.domain.common.i18n.CommonStringMessages;
|
||||
|
||||
public enum DataImportSubProgress {
|
||||
|
||||
INIT {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.init();
|
||||
}
|
||||
},
|
||||
CONNECTION_SETUP {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.connectionSetup();
|
||||
}
|
||||
},
|
||||
CONNECTION_ESTABLISH {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.connectionEstablish();
|
||||
}
|
||||
},
|
||||
TRANSFER_STARTED {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.transferStarted();
|
||||
}
|
||||
},
|
||||
TRANSFER_COMPLETED {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.transferCompleted();
|
||||
}
|
||||
},
|
||||
IMPORT_INIT {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.importInit();
|
||||
}
|
||||
},
|
||||
IMPORT_WAIT {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.importWait();
|
||||
}
|
||||
},
|
||||
IMPORT_LEADERBOARD_GROUPS {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.importLeaderboardGroups();
|
||||
}
|
||||
},
|
||||
IMPORT_WIND_TRACKS {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.importWindTracks();
|
||||
}
|
||||
},
|
||||
UPDATE_EVENT_LEADERBOARD_GROUP_LINKS {
|
||||
@Override
|
||||
public String getMessage(CommonStringMessages messages) {
|
||||
return messages.updateEventLeaderboardGroupLinks();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract String getMessage(CommonStringMessages messages);
|
||||
|
||||
}
|
||||
@@ -14,7 +14,8 @@ public enum FleetColors {
|
||||
RED (232, 74, 26, 0),
|
||||
PURPLE (212, 28, 175, 0),
|
||||
NEON_GREEN (118, 255, 33, 0),
|
||||
ORANGE (255, 174, 23, 0);
|
||||
ORANGE (255, 174, 23, 0),
|
||||
WHITE (250, 250, 250, 0);
|
||||
|
||||
private Color color;
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ public enum MaxPointsReason {
|
||||
/** Retired */
|
||||
RET(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true),
|
||||
/** Uniform Flag Disqualification */
|
||||
UFD(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true);
|
||||
UFD(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true),
|
||||
/** Time limit Expired */
|
||||
TLE(/* discardable */ true, /* advanceCompetitorsTrackedWorse */ true);
|
||||
|
||||
private final boolean discardable;
|
||||
|
||||
|
||||
@@ -14,20 +14,34 @@ package com.sap.sailing.domain.common;
|
||||
public enum PassingInstruction {
|
||||
None(1, 2),
|
||||
Port(1),
|
||||
Single_Unknown(1),
|
||||
Starboard(1),
|
||||
Single_Unknown(1),
|
||||
Gate(2),
|
||||
Line(2),
|
||||
Offset(2),
|
||||
FixedBearing(1);
|
||||
|
||||
/**
|
||||
* Those values relevant for picking by a user when creating a waypoint; for example, this list
|
||||
* does not include the {@link #None} or the {@link #Single_Unknown} literals. No guarantees
|
||||
* made as to the ordering. The enum literals may change, be extended, have elements inserted or
|
||||
* removed at any time!
|
||||
*/
|
||||
public static PassingInstruction[] relevantValues() {
|
||||
PassingInstruction[] uiValues = new PassingInstruction[PassingInstruction.values().length - 1];
|
||||
|
||||
final PassingInstruction[] uselessValues = new PassingInstruction[] { None, Single_Unknown, Offset, FixedBearing };
|
||||
PassingInstruction[] uiValues = new PassingInstruction[PassingInstruction.values().length - uselessValues.length];
|
||||
int i = 0;
|
||||
for (PassingInstruction p : PassingInstruction.values()) {
|
||||
if (p != PassingInstruction.None)
|
||||
boolean useless = false;
|
||||
for (PassingInstruction u : uselessValues) {
|
||||
if (u == p) {
|
||||
useless = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!useless) {
|
||||
uiValues[i++] = p;
|
||||
}
|
||||
}
|
||||
return uiValues;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.simulator;
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
public enum PathType {
|
||||
OMNISCIENT("1#Omniscient"),
|
||||
@@ -60,6 +60,11 @@ public interface Speed extends Comparable<Speed>, Serializable {
|
||||
public double getStatuteMilesPerHour() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance travel(Duration duration) {
|
||||
return Distance.NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@Statistic(messageKey="", resultDecimals=2)
|
||||
@@ -85,4 +90,6 @@ public interface Speed extends Comparable<Speed>, Serializable {
|
||||
* line" on a sphere) with this speed.
|
||||
*/
|
||||
Duration getDuration(Distance distance);
|
||||
|
||||
Distance travel(Duration duration);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.sap.sailing.domain.common.abstractlog;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* Events from {@link RaceLog}s and {@link RegattaLog}s may be used to specify timing aspects for a race.
|
||||
* When searching for such events, three types of outcome are possible: a valid time point specification
|
||||
* may be found; or an explicit specification of {@code null} may be found (such as forcing a tracking
|
||||
* interval to be open at one end); or no specification is found.<p>
|
||||
*
|
||||
* If only a {@link TimePoint} were used, the last two cases could not be disambiguated when specifying
|
||||
* {@code null} as this {@link TimePoint}. This interface makes the distinction possible. If the reference
|
||||
* to an object of this type is {@code null} it means that no information regarding the time point was found
|
||||
* in the log. If a valid {@link TimePointSpecificationFoundInLog} object is presented, information was found in the log,
|
||||
* but the {@link #getTimePoint} could still be {@code null}, meaning that a log entry explicitly set this
|
||||
* time point to {@code null}.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface TimePointSpecificationFoundInLog extends Serializable {
|
||||
TimePoint getTimePoint();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.sap.sailing.domain.common.abstractlog;
|
||||
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class TimePointSpecificationFoundInLogImpl implements TimePointSpecificationFoundInLog {
|
||||
private static final long serialVersionUID = -5499989656571658254L;
|
||||
private TimePoint timePoint;
|
||||
|
||||
TimePointSpecificationFoundInLogImpl() {} // for GWT serialization
|
||||
|
||||
public TimePointSpecificationFoundInLogImpl(TimePoint timePoint) {
|
||||
super();
|
||||
this.timePoint = timePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return timePoint;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,9 @@ public interface CompetitorDTO extends Serializable, MappableToDevice {
|
||||
String getIdAsString();
|
||||
|
||||
String getSailID();
|
||||
|
||||
|
||||
String getSearchTag();
|
||||
|
||||
BoatDTO getBoat();
|
||||
|
||||
BoatClassDTO getBoatClass();
|
||||
|
||||
@@ -1,207 +1,219 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
|
||||
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
|
||||
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
|
||||
* to change for a competitor while the ID remains unchanged.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serializable {
|
||||
private static final long serialVersionUID = -4997852354821083154L;
|
||||
private String countryName;
|
||||
private String twoLetterIsoCountryCode;
|
||||
private String threeLetterIocCountryCode;
|
||||
private Color color;
|
||||
private String email;
|
||||
private String idAsString;
|
||||
private BoatClassDTO boatClass;
|
||||
private BoatDTO boat;
|
||||
private String imageURL;
|
||||
private String flagImageURL;
|
||||
private Double timeOnTimeFactor;
|
||||
private Duration timeOnDistanceAllowancePerNauticalMile;
|
||||
|
||||
public CompetitorDTOImpl() {}
|
||||
|
||||
public CompetitorDTOImpl(String name, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
|
||||
String countryName, String idAsString, String imageURL, String flagImageURL,
|
||||
BoatDTO boat, BoatClassDTO boatClass, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
|
||||
super(name);
|
||||
this.color = color;
|
||||
this.email = email;
|
||||
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
|
||||
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
|
||||
this.countryName = countryName;
|
||||
this.idAsString = idAsString;
|
||||
this.imageURL = imageURL;
|
||||
this.flagImageURL = flagImageURL;
|
||||
this.boat = boat;
|
||||
this.boatClass = boatClass;
|
||||
this.timeOnTimeFactor = timeOnTimeFactor;
|
||||
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
|
||||
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
|
||||
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
|
||||
result = prime * result + ((color == null) ? 0 : color.hashCode());
|
||||
result = prime * result + ((email == null) ? 0 : email.hashCode());
|
||||
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
|
||||
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
|
||||
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
|
||||
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
|
||||
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CompetitorDTOImpl other = (CompetitorDTOImpl) obj;
|
||||
if (boatClass == null) {
|
||||
if (other.boatClass != null)
|
||||
return false;
|
||||
} else if (!boatClass.equals(other.boatClass))
|
||||
return false;
|
||||
if (boat == null) {
|
||||
if (other.boat != null)
|
||||
return false;
|
||||
} else if (!boat.equals(other.boat))
|
||||
return false;
|
||||
if (idAsString == null) {
|
||||
if (other.idAsString != null)
|
||||
return false;
|
||||
} else if (!idAsString.equals(other.idAsString))
|
||||
return false;
|
||||
if (threeLetterIocCountryCode == null) {
|
||||
if (other.threeLetterIocCountryCode != null)
|
||||
return false;
|
||||
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
|
||||
return false;
|
||||
if (color == null) {
|
||||
if (other.color != null)
|
||||
return false;
|
||||
} else if (!color.equals(other.color))
|
||||
return false;
|
||||
if (email == null) {
|
||||
if (other.email != null)
|
||||
return false;
|
||||
} else if (!email.equals(other.email))
|
||||
return false;
|
||||
if (imageURL == null) {
|
||||
if (other.imageURL != null)
|
||||
return false;
|
||||
} else if (!imageURL.equals(other.imageURL))
|
||||
return false;
|
||||
if (flagImageURL == null) {
|
||||
if (other.flagImageURL != null)
|
||||
return false;
|
||||
} else if (!flagImageURL.equals(other.flagImageURL))
|
||||
return false;
|
||||
if (timeOnTimeFactor == null) {
|
||||
if (other.timeOnTimeFactor != null)
|
||||
return false;
|
||||
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
|
||||
return false;
|
||||
if (timeOnDistanceAllowancePerNauticalMile == null) {
|
||||
if (other.timeOnDistanceAllowancePerNauticalMile != null)
|
||||
return false;
|
||||
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTwoLetterIsoCountryCode() {
|
||||
return twoLetterIsoCountryCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIocCountryCode() {
|
||||
return threeLetterIocCountryCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCountryName() {
|
||||
return countryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSailID() {
|
||||
return boat==null?null:boat.getSailId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageURL() {
|
||||
return imageURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFlagImageURL() {
|
||||
return flagImageURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAsString() {
|
||||
return idAsString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClassDTO getBoatClass() {
|
||||
return boatClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String email(){
|
||||
return email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEmail() {
|
||||
return email != null && !email.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor() {
|
||||
return timeOnTimeFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
|
||||
return timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatDTO getBoat() {
|
||||
return boat;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
|
||||
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
|
||||
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
|
||||
* to change for a competitor while the ID remains unchanged.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serializable {
|
||||
private static final long serialVersionUID = -4997852354821083154L;
|
||||
private String countryName;
|
||||
private String twoLetterIsoCountryCode;
|
||||
private String threeLetterIocCountryCode;
|
||||
private Color color;
|
||||
private String email;
|
||||
private String searchTag;
|
||||
private String idAsString;
|
||||
private BoatClassDTO boatClass;
|
||||
private BoatDTO boat;
|
||||
private String imageURL;
|
||||
private String flagImageURL;
|
||||
private Double timeOnTimeFactor;
|
||||
private Duration timeOnDistanceAllowancePerNauticalMile;
|
||||
|
||||
public CompetitorDTOImpl() {}
|
||||
|
||||
public CompetitorDTOImpl(String name, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
|
||||
String countryName, String idAsString, String imageURL, String flagImageURL,
|
||||
BoatDTO boat, BoatClassDTO boatClass, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
|
||||
super(name);
|
||||
this.color = color;
|
||||
this.email = email;
|
||||
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
|
||||
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
|
||||
this.countryName = countryName;
|
||||
this.idAsString = idAsString;
|
||||
this.imageURL = imageURL;
|
||||
this.flagImageURL = flagImageURL;
|
||||
this.boat = boat;
|
||||
this.boatClass = boatClass;
|
||||
this.timeOnTimeFactor = timeOnTimeFactor;
|
||||
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
|
||||
this.searchTag = searchTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
|
||||
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
|
||||
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
|
||||
result = prime * result + ((color == null) ? 0 : color.hashCode());
|
||||
result = prime * result + ((email == null) ? 0 : email.hashCode());
|
||||
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
|
||||
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
|
||||
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
|
||||
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
|
||||
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
|
||||
result = prime * result + ((searchTag == null) ? 0 : searchTag.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CompetitorDTOImpl other = (CompetitorDTOImpl) obj;
|
||||
if (boatClass == null) {
|
||||
if (other.boatClass != null)
|
||||
return false;
|
||||
} else if (!boatClass.equals(other.boatClass))
|
||||
return false;
|
||||
if (boat == null) {
|
||||
if (other.boat != null)
|
||||
return false;
|
||||
} else if (!boat.equals(other.boat))
|
||||
return false;
|
||||
if (idAsString == null) {
|
||||
if (other.idAsString != null)
|
||||
return false;
|
||||
} else if (!idAsString.equals(other.idAsString))
|
||||
return false;
|
||||
if (threeLetterIocCountryCode == null) {
|
||||
if (other.threeLetterIocCountryCode != null)
|
||||
return false;
|
||||
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
|
||||
return false;
|
||||
if (color == null) {
|
||||
if (other.color != null)
|
||||
return false;
|
||||
} else if (!color.equals(other.color))
|
||||
return false;
|
||||
if (email == null) {
|
||||
if (other.email != null)
|
||||
return false;
|
||||
} else if (!email.equals(other.email))
|
||||
return false;
|
||||
if (imageURL == null) {
|
||||
if (other.imageURL != null)
|
||||
return false;
|
||||
} else if (!imageURL.equals(other.imageURL))
|
||||
return false;
|
||||
if (flagImageURL == null) {
|
||||
if (other.flagImageURL != null)
|
||||
return false;
|
||||
} else if (!flagImageURL.equals(other.flagImageURL))
|
||||
return false;
|
||||
if (timeOnTimeFactor == null) {
|
||||
if (other.timeOnTimeFactor != null)
|
||||
return false;
|
||||
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
|
||||
return false;
|
||||
if (timeOnDistanceAllowancePerNauticalMile == null) {
|
||||
if (other.timeOnDistanceAllowancePerNauticalMile != null)
|
||||
return false;
|
||||
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
|
||||
return false;
|
||||
if (searchTag == null) {
|
||||
if (other.searchTag != null)
|
||||
return false;
|
||||
} else if (!searchTag.equals(other.searchTag))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTwoLetterIsoCountryCode() {
|
||||
return twoLetterIsoCountryCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIocCountryCode() {
|
||||
return threeLetterIocCountryCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCountryName() {
|
||||
return countryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSailID() {
|
||||
return boat==null?null:boat.getSailId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageURL() {
|
||||
return imageURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFlagImageURL() {
|
||||
return flagImageURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAsString() {
|
||||
return idAsString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClassDTO getBoatClass() {
|
||||
return boatClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getSearchTag() {
|
||||
return searchTag;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String email(){
|
||||
return email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEmail() {
|
||||
return email != null && !email.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor() {
|
||||
return timeOnTimeFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
|
||||
return timeOnDistanceAllowancePerNauticalMile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatDTO getBoat() {
|
||||
return boat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +1,149 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Equality and hash code are based on the index pointing into a previous leaderboard's competitors list.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PreviousCompetitorDTOImpl implements CompetitorDTO {
|
||||
private static final long serialVersionUID = 8820028699103040805L;
|
||||
private int indexInPreviousCompetitorList;
|
||||
|
||||
PreviousCompetitorDTOImpl() {} // for serialization only
|
||||
|
||||
public PreviousCompetitorDTOImpl(int indexInPreviousCompetitorList) {
|
||||
super();
|
||||
this.indexInPreviousCompetitorList = indexInPreviousCompetitorList;
|
||||
}
|
||||
|
||||
protected int getIndexInPreviousCompetitorList() {
|
||||
return indexInPreviousCompetitorList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + indexInPreviousCompetitorList;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PreviousCompetitorDTOImpl other = (PreviousCompetitorDTOImpl) obj;
|
||||
if (indexInPreviousCompetitorList != other.indexInPreviousCompetitorList)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTwoLetterIsoCountryCode() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIocCountryCode() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCountryName() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSailID() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatDTO getBoat() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAsString() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClassDTO getBoatClass() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageURL() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFlagImageURL() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEmail() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
|
||||
return previousVersion.competitors.get(indexInPreviousCompetitorList);
|
||||
}
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import com.sap.sse.common.Color;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* Equality and hash code are based on the index pointing into a previous leaderboard's competitors list.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class PreviousCompetitorDTOImpl implements CompetitorDTO {
|
||||
private static final long serialVersionUID = 8820028699103040805L;
|
||||
private int indexInPreviousCompetitorList;
|
||||
|
||||
PreviousCompetitorDTOImpl() {} // for serialization only
|
||||
|
||||
public PreviousCompetitorDTOImpl(int indexInPreviousCompetitorList) {
|
||||
super();
|
||||
this.indexInPreviousCompetitorList = indexInPreviousCompetitorList;
|
||||
}
|
||||
|
||||
protected int getIndexInPreviousCompetitorList() {
|
||||
return indexInPreviousCompetitorList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + indexInPreviousCompetitorList;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
PreviousCompetitorDTOImpl other = (PreviousCompetitorDTOImpl) obj;
|
||||
if (indexInPreviousCompetitorList != other.indexInPreviousCompetitorList)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTwoLetterIsoCountryCode() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThreeLetterIocCountryCode() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCountryName() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSailID() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatDTO getBoat() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAsString() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoatClassDTO getBoatClass() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSearchTag() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageURL() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFlagImageURL() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEmail() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
|
||||
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
|
||||
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
|
||||
return previousVersion.competitors.get(indexInPreviousCompetitorList);
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,24 @@ public class RaceColumnDTO extends NamedDTO implements Serializable {
|
||||
return start;
|
||||
}
|
||||
|
||||
public Date getStartOfTracking(FleetDTO fleet){
|
||||
Date start = null;
|
||||
RaceDTO raceDTO = racesPerFleet.get(fleet);
|
||||
if (raceDTO != null && raceDTO.isTracked) {
|
||||
start = raceDTO.trackedRace.startOfTracking;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
public Date getEndOfTracking(FleetDTO fleet){
|
||||
Date start = null;
|
||||
RaceDTO raceDTO = racesPerFleet.get(fleet);
|
||||
if (raceDTO != null && raceDTO.isTracked) {
|
||||
start = raceDTO.trackedRace.endOfTracking;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link PlacemarkOrderDTO places} or <code>null</code>, if no places are available
|
||||
*/
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
|
||||
|
||||
public class RaceLogTrackingInfoDTO implements Serializable {
|
||||
private static final long serialVersionUID = -6861382173074620168L;
|
||||
public boolean raceLogTrackerExists;
|
||||
public boolean competitorRegistrationsExists;
|
||||
public RaceLogTrackingState raceLogTrackingState;
|
||||
|
||||
protected RaceLogTrackingInfoDTO() {}
|
||||
|
||||
public RaceLogTrackingInfoDTO(boolean raceLogTrackerExists, boolean competitorRegistrationsExists,
|
||||
RaceLogTrackingState raceLogTrackingState) {
|
||||
this.raceLogTrackerExists = raceLogTrackerExists;
|
||||
this.competitorRegistrationsExists = competitorRegistrationsExists;
|
||||
this.raceLogTrackingState = raceLogTrackingState;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
|
||||
|
||||
public class RaceLogTrackingInfoDTO implements Serializable {
|
||||
private static final long serialVersionUID = -6861382173074620168L;
|
||||
public boolean raceLogTrackerExists;
|
||||
public boolean competitorRegistrationsExists;
|
||||
public boolean courseExists;
|
||||
public RaceLogTrackingState raceLogTrackingState;
|
||||
|
||||
protected RaceLogTrackingInfoDTO() {}
|
||||
|
||||
public RaceLogTrackingInfoDTO(boolean raceLogTrackerExists, boolean competitorRegistrationsExists, boolean courseExists,
|
||||
RaceLogTrackingState raceLogTrackingState) {
|
||||
this.raceLogTrackerExists = raceLogTrackerExists;
|
||||
this.competitorRegistrationsExists = competitorRegistrationsExists;
|
||||
this.courseExists = courseExists;
|
||||
this.raceLogTrackingState = raceLogTrackingState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,65 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class SeriesCreationParametersDTO implements Serializable {
|
||||
private static final long serialVersionUID = -3205172230707607515L;
|
||||
|
||||
private List<FleetDTO> fleets;
|
||||
|
||||
private boolean medal;
|
||||
|
||||
private boolean startsWithZero;
|
||||
|
||||
private boolean firstColumnIsNonDiscardableCarryForward;
|
||||
|
||||
private int[] discardingThresholds;
|
||||
|
||||
private boolean hasSplitFleetContiguousScoring;
|
||||
|
||||
SeriesCreationParametersDTO() {}
|
||||
|
||||
public SeriesCreationParametersDTO(List<FleetDTO> fleets, boolean medal, boolean startsWithZero, boolean firstColumnIsNonDiscardableCarryForward,
|
||||
int[] discardingThresholds, boolean hasSplitFleetContiguousScoring) {
|
||||
super();
|
||||
this.fleets = fleets;
|
||||
this.medal = medal;
|
||||
this.startsWithZero = startsWithZero;
|
||||
this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring;
|
||||
this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward;
|
||||
this.discardingThresholds = discardingThresholds;
|
||||
}
|
||||
|
||||
public List<FleetDTO> getFleets() {
|
||||
return fleets;
|
||||
}
|
||||
|
||||
public boolean isMedal() {
|
||||
return medal;
|
||||
}
|
||||
|
||||
public boolean isStartsWithZero() {
|
||||
return startsWithZero;
|
||||
}
|
||||
|
||||
public boolean hasSplitFleetContiguousScoring() {
|
||||
return hasSplitFleetContiguousScoring;
|
||||
}
|
||||
|
||||
public int[] getDiscardingThresholds() {
|
||||
return discardingThresholds;
|
||||
}
|
||||
|
||||
public boolean isFirstColumnIsNonDiscardableCarryForward() {
|
||||
return firstColumnIsNonDiscardableCarryForward;
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class SeriesCreationParametersDTO implements Serializable {
|
||||
private static final long serialVersionUID = -3205172230707607515L;
|
||||
|
||||
private List<FleetDTO> fleets;
|
||||
|
||||
private boolean isMedal;
|
||||
|
||||
private boolean isFleetsCanRunInParallel;
|
||||
|
||||
private boolean isStartsWithZeroScore;
|
||||
|
||||
private boolean firstColumnIsNonDiscardableCarryForward;
|
||||
|
||||
private int[] discardingThresholds;
|
||||
|
||||
private boolean hasSplitFleetContiguousScoring;
|
||||
|
||||
SeriesCreationParametersDTO() {}
|
||||
|
||||
public SeriesCreationParametersDTO(List<FleetDTO> fleets, boolean isMedal, boolean isFleetsCanRunInParallel, boolean isStartsWithZeroScore, boolean firstColumnIsNonDiscardableCarryForward,
|
||||
int[] discardingThresholds, boolean hasSplitFleetContiguousScoring) {
|
||||
super();
|
||||
this.fleets = fleets;
|
||||
this.isMedal = isMedal;
|
||||
this.isFleetsCanRunInParallel = isFleetsCanRunInParallel;
|
||||
this.isStartsWithZeroScore = isStartsWithZeroScore;
|
||||
this.hasSplitFleetContiguousScoring = hasSplitFleetContiguousScoring;
|
||||
this.firstColumnIsNonDiscardableCarryForward = firstColumnIsNonDiscardableCarryForward;
|
||||
this.discardingThresholds = discardingThresholds;
|
||||
}
|
||||
|
||||
public List<FleetDTO> getFleets() {
|
||||
return fleets;
|
||||
}
|
||||
|
||||
public boolean isMedal() {
|
||||
return isMedal;
|
||||
}
|
||||
|
||||
public boolean isStartsWithZero() {
|
||||
return isStartsWithZeroScore;
|
||||
}
|
||||
|
||||
public boolean isFleetsCanRunInParallel() {
|
||||
return isFleetsCanRunInParallel;
|
||||
}
|
||||
|
||||
public boolean hasSplitFleetContiguousScoring() {
|
||||
return hasSplitFleetContiguousScoring;
|
||||
}
|
||||
|
||||
public int[] getDiscardingThresholds() {
|
||||
return discardingThresholds;
|
||||
}
|
||||
|
||||
public boolean isFirstColumnIsNonDiscardableCarryForward() {
|
||||
return firstColumnIsNonDiscardableCarryForward;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.sap.sailing.domain.common.i18n;
|
||||
|
||||
public interface CommonStringMessages {
|
||||
|
||||
/* Master data import sub progress messages */
|
||||
String init();
|
||||
String connectionSetup();
|
||||
String connectionEstablish();
|
||||
String transferStarted();
|
||||
String transferCompleted();
|
||||
String importInit();
|
||||
String importWait();
|
||||
String importLeaderboardGroups();
|
||||
String importWindTracks();
|
||||
String updateEventLeaderboardGroupLinks();
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.common.impl;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.DataImportSubProgress;
|
||||
import com.sap.sailing.domain.common.MasterDataImportObjectCreationCount;
|
||||
|
||||
public class DataImportProgressImpl implements DataImportProgress {
|
||||
@@ -11,7 +12,7 @@ public class DataImportProgressImpl implements DataImportProgress {
|
||||
private UUID currentImportOperationId;
|
||||
private MasterDataImportObjectCreationCount result = null;
|
||||
private double overallProgressPct = 0;
|
||||
private String currentSubProgressName = "Initializing Import";
|
||||
private DataImportSubProgress currentSubProgress = DataImportSubProgress.IMPORT_INIT;
|
||||
private double currentSubProgressPct = 0;
|
||||
private boolean failed = false;
|
||||
private String errorMessage;
|
||||
@@ -21,17 +22,16 @@ public class DataImportProgressImpl implements DataImportProgress {
|
||||
|
||||
public DataImportProgressImpl(final UUID currentImportOperationId) {
|
||||
this.currentImportOperationId = currentImportOperationId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getOverallProgressPct() {
|
||||
return overallProgressPct;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNameOfCurrentSubProgress() {
|
||||
return currentSubProgressName;
|
||||
public DataImportSubProgress getCurrentSubProgress() {
|
||||
return currentSubProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,10 +48,10 @@ public class DataImportProgressImpl implements DataImportProgress {
|
||||
public void setOverAllProgressPct(double pct) {
|
||||
overallProgressPct = pct;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setNameOfCurrentSubProgress(String name) {
|
||||
currentSubProgressName = name;
|
||||
public void setCurrentSubProgress(DataImportSubProgress subProgress) {
|
||||
currentSubProgress = subProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
public class RaceColumnConstants {
|
||||
|
||||
public static final String LEADERBOARD_NAME = "leaderboard_name";
|
||||
public static final String LEADERBOARD_DISPLAY_NAME = "leaderboard_display_name";
|
||||
public static final String RACE_COLUMNS = "race_columns";
|
||||
public static final String RACE_COLUMN_NAME = "race_column_name";
|
||||
public static final String EXPLICIT_FACTOR = "explicit_factor";
|
||||
public static final String FACTOR = "factor";
|
||||
|
||||
}
|
||||
@@ -14,6 +14,11 @@ public enum RaceLogRaceStatus {
|
||||
RaceLogRaceStatus(int orderNumber) {
|
||||
this.orderNumber = orderNumber;
|
||||
}
|
||||
|
||||
public static boolean isPreRunning(RaceLogRaceStatus status) {
|
||||
return status != null &&
|
||||
(status.equals(SCHEDULED) || status.equals(STARTPHASE));
|
||||
}
|
||||
|
||||
public static boolean isActive(RaceLogRaceStatus status) {
|
||||
return status != null &&
|
||||
@@ -21,6 +26,11 @@ public enum RaceLogRaceStatus {
|
||||
|
||||
}
|
||||
|
||||
public static boolean isRunningOrFinished(RaceLogRaceStatus status) {
|
||||
return status != null &&
|
||||
(status.equals(STARTPHASE) || status.equals(RUNNING) || status.equals(FINISHING) || status.equals(FINISHED));
|
||||
}
|
||||
|
||||
public int getOrderNumber() {
|
||||
return orderNumber;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sap.sailing.domain.common.racelog.tracking;
|
||||
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogServletConstants;
|
||||
import com.sap.sse.common.util.UrlHelper;
|
||||
|
||||
/**
|
||||
@@ -39,44 +38,16 @@ public class DeviceMappingConstants {
|
||||
public static final String JSON_TO_MILLIS = "toMillis";
|
||||
public static final String JSON_TEAM_IMAGE_URI = "teamImageUri";
|
||||
|
||||
@Deprecated
|
||||
static final String APK_PATH = "/apps/com.sap.sailing.android.tracking.app.apk";
|
||||
|
||||
public static String getDeviceMappingForRegattaLogUrl(String serverUrlWithoutTrailingSlash, String eventId,
|
||||
String leaderboardName, String mappedItemType, String mappedItemId, UrlHelper helper) {
|
||||
return helper.encodeUrl(serverUrlWithoutTrailingSlash + TRACKING_URL_BASE + "?" + URL_EVENT_ID + "=" + eventId + "&"
|
||||
+ URL_LEADERBOARD_NAME + "=" + leaderboardName + "&" + mappedItemType + "="
|
||||
+ mappedItemId);
|
||||
return serverUrlWithoutTrailingSlash + TRACKING_URL_BASE + "?" + URL_EVENT_ID + "=" + helper.encodeQueryString(eventId) + "&"
|
||||
+ URL_LEADERBOARD_NAME + "=" + helper.encodeQueryString(leaderboardName) + "&" + helper.encodeQueryString(mappedItemType) + "="
|
||||
+ helper.encodeQueryString(mappedItemId);
|
||||
}
|
||||
|
||||
public static String getBuoyTenderInvitationUrl(String serverUrlWithoutTrailingSlash,
|
||||
String leaderboardName, String eventId, UrlHelper helper) {
|
||||
return helper.encodeUrl(serverUrlWithoutTrailingSlash + BUOY_TENDER_URL_BASE + "?" + URL_EVENT_ID + "="
|
||||
+ eventId + "&" + URL_LEADERBOARD_NAME + "=" + leaderboardName);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getDeviceMappingForRaceLogUrl(String serverUrlWithoutTrailingSlash, String leaderboardName,
|
||||
String raceColumnName, String fleetName, String mappedItemType, String mappedItemId, Long fromMillis,
|
||||
Long toMillis, UrlHelper helper) throws QRCodeURLCreationException {
|
||||
|
||||
if (toMillis != null && fromMillis != null){
|
||||
if (fromMillis > toMillis) {
|
||||
throw new QRCodeURLCreationException("from can't lie after to");
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder urlToEncode = new StringBuilder();
|
||||
|
||||
urlToEncode.append(serverUrlWithoutTrailingSlash + DeviceMappingConstants.APK_PATH + "?"
|
||||
+ RaceLogServletConstants.PARAMS_LEADERBOARD_NAME + "=" + leaderboardName + "&"
|
||||
+ RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME + "=" + raceColumnName + "&"
|
||||
+ RaceLogServletConstants.PARAMS_RACE_FLEET_NAME + "=" + fleetName + "&" + mappedItemType + "="
|
||||
+ mappedItemId);
|
||||
|
||||
urlToEncode.append((fromMillis != null) ? "&" + DeviceMappingConstants.URL_FROM_MILLIS + "=" + fromMillis : "");
|
||||
urlToEncode.append((toMillis != null) ? "&" + DeviceMappingConstants.URL_TO_MILLIS + "=" + toMillis : "");
|
||||
|
||||
return helper.encodeUrl(urlToEncode.toString());
|
||||
return serverUrlWithoutTrailingSlash + BUOY_TENDER_URL_BASE + "?" + URL_EVENT_ID + "="
|
||||
+ helper.encodeQueryString(eventId) + "&" + URL_LEADERBOARD_NAME + "=" + helper.encodeQueryString(leaderboardName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
package com.sap.sailing.domain.common.tracking;
|
||||
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Positioned;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sse.common.Timed;
|
||||
|
||||
public interface GPSFix extends Positioned, Timed, WithValidityCache, WithEstimatedSpeedCache {
|
||||
/**
|
||||
* A typical horizontal dilution of precision, or in other words, an error that is quite likely and may occur.
|
||||
* For example, when trying to tell whether an object was on the one or the other side of some other object,
|
||||
* this typical level of accuracy can be used as a default margin of error.
|
||||
*/
|
||||
Distance TYPICAL_HDOP = new MeterDistance(5);
|
||||
|
||||
/**
|
||||
* Reaches <code>to</code> at <code>to</code>'s {@link GPSFix#getTimePoint() time point} starting at this fix,
|
||||
* traveling on a straight great circle segment.
|
||||
|
||||
@@ -22,7 +22,9 @@ public class CompetitorJsonConstants {
|
||||
public static final String FIELD_BOAT = "boat";
|
||||
public static final String FIELD_DISPLAY_COLOR = "displayColor";
|
||||
public static final String FIELD_EMAIL = "email";
|
||||
public static final String FIELD_SEARCHTAG = "searchTag";
|
||||
public static final String FIELD_FLAG_IMAGE_URI = "flagImageUri";
|
||||
public static final String FIELD_TEAM_IMAGE_URI = "teamImageUri";
|
||||
public static final String FIELD_TIME_ON_TIME_FACTOR = "timeOnTimeFactor";
|
||||
public static final String FIELD_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE = "timeOnDistanceAllowanceInSecondsPerNauticalMile";
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ public class GPSFixImpl extends AbstractGPSFixImpl implements GPSFix {
|
||||
public String toString() {
|
||||
return getTimePoint()+": "+getPosition();
|
||||
}
|
||||
|
||||
|
||||
public static GPSFixImpl create(double lonDeg, double latDeg, long timeMillis) {
|
||||
return new GPSFixImpl(new DegreePosition(latDeg, lonDeg), new MillisecondsTimePoint(timeMillis));
|
||||
|
||||
@@ -28,7 +28,9 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.Timeout;
|
||||
|
||||
import com.sap.sailing.domain.igtimiadapter.Account;
|
||||
import com.sap.sailing.domain.igtimiadapter.BulkFixReceiver;
|
||||
@@ -47,6 +49,8 @@ import com.sap.sse.mongodb.MongoDBService;
|
||||
public class WebSocketTest {
|
||||
private static final Logger logger = Logger.getLogger(WebSocketTest.class.getName());
|
||||
|
||||
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(1 * 60 * 1000);
|
||||
|
||||
@WebSocket
|
||||
public class SimpleEchoTestSocket {
|
||||
private final CountDownLatch closeLatch;
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -501,14 +500,7 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
|
||||
result.add(uri);
|
||||
}
|
||||
// sort those to the front that don't do port 443 nor wss://
|
||||
Collections.sort(result, new Comparator<URI>() {
|
||||
@Override
|
||||
public int compare(URI o1, URI o2) {
|
||||
int o1Score = (o1.toString().contains("443") ? 1 : 0) + (o1.toString().contains("wss") ? 1 : 0);
|
||||
int o2Score = (o2.toString().contains("443") ? 1 : 0) + (o2.toString().contains("wss") ? 1 : 0);
|
||||
return o1Score - o2Score;
|
||||
}
|
||||
});
|
||||
Collections.shuffle(result); // shuffle as a failover strategy
|
||||
logger.info("Trying Igtimi WebSocket servers in the following order: "+result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ import com.sap.sailing.domain.base.impl.SailingServerConfigurationImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.base.impl.VenueImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.CourseDesignerMode;
|
||||
import com.sap.sailing.domain.common.MarkType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
@@ -1188,6 +1189,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
private Series loadSeries(DBObject dbSeries, TrackedRegattaRegistry trackedRegattaRegistry) {
|
||||
String name = (String) dbSeries.get(FieldNames.SERIES_NAME.name());
|
||||
boolean isMedal = (Boolean) dbSeries.get(FieldNames.SERIES_IS_MEDAL.name());
|
||||
// isFleetCanRunInParallel is a new field -> set to true when it does not exist in older db versions
|
||||
boolean isFleetsCanRunInParallel = true;
|
||||
Object isFleetCanRunInParallelObject = dbSeries.get(FieldNames.SERIES_IS_FLEETS_CAN_RUN_IN_PARALLEL.name());
|
||||
if (isFleetCanRunInParallelObject != null) {
|
||||
isFleetsCanRunInParallel = (Boolean) dbSeries.get(FieldNames.SERIES_IS_FLEETS_CAN_RUN_IN_PARALLEL.name());
|
||||
}
|
||||
Boolean startsWithZeroScore = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name());
|
||||
Boolean hasSplitFleetContiguousScoring = (Boolean) dbSeries.get(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name());
|
||||
Boolean firstColumnIsNonDiscardableCarryForward = (Boolean) dbSeries.get(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name());
|
||||
@@ -1195,7 +1202,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
List<Fleet> fleets = loadFleets(dbFleets);
|
||||
BasicDBList dbRaceColumns = (BasicDBList) dbSeries.get(FieldNames.SERIES_RACE_COLUMNS.name());
|
||||
Iterable<String> raceColumnNames = loadRaceColumnNames(dbRaceColumns);
|
||||
Series series = new SeriesImpl(name, isMedal, fleets, raceColumnNames, trackedRegattaRegistry);
|
||||
Series series = new SeriesImpl(name, isMedal, isFleetsCanRunInParallel, fleets, raceColumnNames, trackedRegattaRegistry);
|
||||
if (dbSeries.get(FieldNames.SERIES_DISCARDING_THRESHOLDS.name()) != null) {
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule = loadResultDiscardingRule(dbSeries, FieldNames.SERIES_DISCARDING_THRESHOLDS);
|
||||
series.setResultDiscardingRule(resultDiscardingRule);
|
||||
@@ -1498,7 +1505,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
private RaceLogCourseDesignChangedEvent loadRaceLogCourseDesignChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
|
||||
String courseName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name());
|
||||
CourseBase courseData = loadCourseData((BasicDBList) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN.name()), courseName);
|
||||
return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData);
|
||||
final String courseDesignerModeName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGNER_MODE.name());
|
||||
final CourseDesignerMode courseDesignerMode = courseDesignerModeName == null ? null : CourseDesignerMode.valueOf(courseDesignerModeName);
|
||||
return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData, courseDesignerMode);
|
||||
}
|
||||
|
||||
private RaceLogCourseAreaChangedEvent loadRaceLogCourseAreaChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List<Competitor> competitors, DBObject dbObject) {
|
||||
@@ -1615,8 +1624,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
loadRegattaLogEvents(result, query, identifier);
|
||||
} catch (Throwable t) {
|
||||
// something went wrong during DB access; report, then use empty new regatta log
|
||||
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded regatta log data. Check MongoDB settings.");
|
||||
logger.log(Level.SEVERE, "loadRegattaLog", t);
|
||||
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded regatta log data for "+identifier+". Check MongoDB settings.", t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1708,7 +1716,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
private RegattaLogRegisterCompetitorEvent loadRegattaLogRegisterCompetitorEvent(TimePoint createdAt, AbstractLogEventAuthor author,
|
||||
TimePoint logicalTimePoint, Serializable id, DBObject dbObject) {
|
||||
Competitor comp = getCompetitorByID(dbObject);
|
||||
return new RegattaLogRegisterCompetitorEventImpl(createdAt, logicalTimePoint, author, id, comp);
|
||||
final RegattaLogRegisterCompetitorEvent result;
|
||||
if (comp == null) {
|
||||
result = null;
|
||||
logger.log(Level.SEVERE, "Couldn't resolve competitor with ID "+dbObject.get(FieldNames.REGATTA_LOG_COMPETITOR_ID.name())+
|
||||
" from registration event with ID "+id+". Skipping this competitor registration.");
|
||||
} else {
|
||||
result = new RegattaLogRegisterCompetitorEventImpl(createdAt, logicalTimePoint, author, id, comp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private RegattaLogCloseOpenEndedDeviceMappingEvent loadRegattaLogCloseOpenEndedDeviceMappingEvent(TimePoint createdAt,
|
||||
@@ -1795,23 +1811,31 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
logger.log(Level.WARNING, "Could not load deviceId for RaceLogEvent", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
final Serializable competitorId = (Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name());
|
||||
Competitor mappedTo = baseDomainFactory.getExistingCompetitorById(
|
||||
(Serializable) dbObject.get(FieldNames.COMPETITOR_ID.name()));
|
||||
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
|
||||
final FieldNames deprecatedFromFieldName = FieldNames.RACE_LOG_FROM;
|
||||
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
|
||||
final FieldNames deprecatedToFieldName = FieldNames.RACE_LOG_TO;
|
||||
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, deprecatedFromFieldName, FieldNames.REGATTA_LOG_TO, deprecatedToFieldName);
|
||||
final TimePoint from = times.getA();
|
||||
final TimePoint to = times.getB();
|
||||
final boolean needsMigration = times.getC();
|
||||
final RegattaLogDeviceCompetitorMappingEventImpl result = new RegattaLogDeviceCompetitorMappingEventImpl(createdAt, logicalTimePoint, author, id, mappedTo, device, from, to);
|
||||
if (needsMigration) {
|
||||
// remove old version of mapping event
|
||||
WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject);
|
||||
assert removeResult.getN() == 1;
|
||||
// and then insert using the fixed storage implementation
|
||||
new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result);
|
||||
competitorId);
|
||||
final RegattaLogDeviceCompetitorMappingEventImpl result;
|
||||
if (mappedTo == null) {
|
||||
logger.severe("Found a "+RegattaLogDeviceCompetitorMappingEventImpl.class.getName()+
|
||||
" event but couldn't find competitor with ID "+competitorId);
|
||||
result = null;
|
||||
} else {
|
||||
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
|
||||
final FieldNames deprecatedFromFieldName = FieldNames.RACE_LOG_FROM;
|
||||
@SuppressWarnings("deprecation") // used only for auto-migration; may be removed in future releases
|
||||
final FieldNames deprecatedToFieldName = FieldNames.RACE_LOG_TO;
|
||||
Triple<TimePoint, TimePoint, Boolean> times = loadFromToTimePoint(dbObject, FieldNames.REGATTA_LOG_FROM, deprecatedFromFieldName, FieldNames.REGATTA_LOG_TO, deprecatedToFieldName);
|
||||
final TimePoint from = times.getA();
|
||||
final TimePoint to = times.getB();
|
||||
final boolean needsMigration = times.getC();
|
||||
result = new RegattaLogDeviceCompetitorMappingEventImpl(createdAt, logicalTimePoint, author, id, mappedTo, device, from, to);
|
||||
if (needsMigration) {
|
||||
// remove old version of mapping event
|
||||
WriteResult removeResult = database.getCollection(CollectionNames.REGATTA_LOGS.name()).remove(outerDBObject);
|
||||
assert removeResult.getN() == 1;
|
||||
// and then insert using the fixed storage implementation
|
||||
new MongoObjectFactoryImpl(database, serviceFinderFactory).storeRegattaLogEvent(regattaLogIdentifier, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public enum FieldNames {
|
||||
REGATTA_USE_START_TIME_INFERENCE,
|
||||
SERIES_NAME,
|
||||
SERIES_IS_MEDAL,
|
||||
SERIES_IS_FLEETS_CAN_RUN_IN_PARALLEL,
|
||||
SERIES_STARTS_WITH_ZERO_SCORE,
|
||||
SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING,
|
||||
SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD,
|
||||
@@ -88,7 +89,7 @@ public enum FieldNames {
|
||||
// race log
|
||||
RACE_LOG_IDENTIFIER, RACE_LOG_EVENT, RACE_LOG_EVENT_PASS_ID, RACE_LOG_EVENT_ID, RACE_LOG_EVENT_CREATED_AT, RACE_LOG_EVENT_AUTHOR_NAME,
|
||||
RACE_LOG_EVENT_AUTHOR_PRIORITY, RACE_LOG_EVENT_INVOLVED_BOATS, RACE_LOG_EVENT_FLAG_UPPER, RACE_LOG_EVENT_FLAG_LOWER, RACE_LOG_EVENT_FLAG_DISPLAYED,
|
||||
RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, WAYPOINT_ID, WAYPOINT_NAME,
|
||||
RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, RACE_LOG_COURSE_DESIGNER_MODE, WAYPOINT_ID, WAYPOINT_NAME,
|
||||
WAYPOINT_PASSINGINSTRUCTIONS, CONTROLPOINT, CONTROLPOINT_CLASS, MARK_ID, MARK_COLOR, MARK_NAME, MARK_PATTERN, MARK_SHAPE, MARK_TYPE,
|
||||
CONTROLPOINT_VALUE, CONTROLPOINTWITHTWOMARKS_ID, CONTROLPOINTWITHTWOMARKS_NAME, CONTROLPOINTWITHTWOMARKS_LEFT, CONTROLPOINTWITHTWOMARKS_RIGHT,
|
||||
RACE_LOG_POSITIONED_COMPETITORS, RACE_LOG_PATHFINDER_ID, RACE_LOG_GATE_LINE_OPENING_TIME, RACE_LOG_GOLF_DOWN_TIME, RACE_LOG_START_PROCEDURE_TYPE,
|
||||
|
||||
@@ -674,6 +674,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBObject dbSeries = new BasicDBObject();
|
||||
dbSeries.put(FieldNames.SERIES_NAME.name(), s.getName());
|
||||
dbSeries.put(FieldNames.SERIES_IS_MEDAL.name(), s.isMedal());
|
||||
dbSeries.put(FieldNames.SERIES_IS_FLEETS_CAN_RUN_IN_PARALLEL.name(), s.isFleetsCanRunInParallel());
|
||||
dbSeries.put(FieldNames.SERIES_HAS_SPLIT_FLEET_CONTIGUOUS_SCORING.name(), s.hasSplitFleetContiguousScoring());
|
||||
dbSeries.put(FieldNames.SERIES_STARTS_WITH_ZERO_SCORE.name(), s.isStartsWithZeroScore());
|
||||
dbSeries.put(FieldNames.SERIES_STARTS_WITH_NON_DISCARDABLE_CARRY_FORWARD.name(), s.isFirstColumnIsNonDiscardableCarryForward());
|
||||
@@ -1002,6 +1003,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogUseCompetitorsFromRaceLogEvent event) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
storeRaceLogIdentifier(raceLogIdentifier, result);
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogUseCompetitorsFromRaceLogEvent(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogUseCompetitorsFromRaceLogEvent(RaceLogUseCompetitorsFromRaceLogEvent event) {
|
||||
DBObject result = new BasicDBObject();
|
||||
storeRaceLogEventProperties(event, result);
|
||||
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogUseCompetitorsFromRaceLogEvent.class.getSimpleName());
|
||||
@@ -1109,6 +1117,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
storeRaceLogEventProperties(courseDesignChangedEvent, result);
|
||||
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName());
|
||||
result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName());
|
||||
result.put(FieldNames.RACE_LOG_COURSE_DESIGNER_MODE.name(),
|
||||
courseDesignChangedEvent.getCourseDesignerMode() == null ? null : courseDesignChangedEvent.getCourseDesignerMode().name());
|
||||
result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
package com.sap.sailing.domain.racelogtracking.test;
|
||||
|
||||
import static com.sap.sse.common.Util.size;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
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.RegattaLogImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoGPSFixStoreImpl;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.DeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class AbstractGPSFixStoreTest {
|
||||
protected RacingEventService service;
|
||||
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
|
||||
DeviceAndSessionIdentifierWithGPSFixesDeserializer deserializer =
|
||||
new MockDeviceAndSessionIdentifierWithGPSFixesDeserializer();
|
||||
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
|
||||
protected RaceLog raceLog;
|
||||
protected RegattaLog regattaLog;
|
||||
protected GPSFixStore store;
|
||||
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null);
|
||||
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
|
||||
|
||||
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
|
||||
|
||||
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
|
||||
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
|
||||
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setServiceAndRaceLog() {
|
||||
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
|
||||
raceLog = new RaceLogImpl("racelog");
|
||||
regattaLog = new RegattaLogImpl("regattalog");
|
||||
store = new MongoGPSFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
|
||||
serviceFinderFactory);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
|
||||
mongoOF.getGPSFixCollection().drop();
|
||||
mongoOF.getGPSFixMetadataCollection().drop();
|
||||
}
|
||||
|
||||
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
map(regattaLog, comp, device, from, to);
|
||||
}
|
||||
|
||||
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void testNumberOfRawFixes(Track<?> track, long expected) {
|
||||
track.lockForRead();
|
||||
assertEquals(expected, size(track.getRawFixes()));
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.racelogtracking.test;
|
||||
|
||||
import static com.sap.sse.common.Util.size;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
|
||||
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
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.RegattaLogImpl;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoGPSFixStoreImpl;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.DeviceAndSessionIdentifierWithGPSFixesDeserializer;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class AbstractGPSFixStoreTest {
|
||||
protected RacingEventService service;
|
||||
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
|
||||
DeviceAndSessionIdentifierWithGPSFixesDeserializer deserializer =
|
||||
new MockDeviceAndSessionIdentifierWithGPSFixesDeserializer();
|
||||
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
|
||||
protected RaceLog raceLog;
|
||||
protected RegattaLog regattaLog;
|
||||
protected GPSFixStore store;
|
||||
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
|
||||
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
|
||||
|
||||
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
|
||||
|
||||
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
|
||||
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
|
||||
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setServiceAndRaceLog() {
|
||||
service = new RacingEventServiceImpl(null, null, serviceFinderFactory);
|
||||
raceLog = new RaceLogImpl("racelog");
|
||||
regattaLog = new RegattaLogImpl("regattalog");
|
||||
store = new MongoGPSFixStoreImpl(service.getMongoObjectFactory(), service.getDomainObjectFactory(),
|
||||
serviceFinderFactory);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
MongoObjectFactoryImpl mongoOF = (MongoObjectFactoryImpl) service.getMongoObjectFactory();
|
||||
mongoOF.getGPSFixCollection().drop();
|
||||
mongoOF.getGPSFixMetadataCollection().drop();
|
||||
}
|
||||
|
||||
protected void map(RegattaLog regattaLog, Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
comp, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void map(Competitor comp, DeviceIdentifier device, long from, long to) {
|
||||
map(regattaLog, comp, device, from, to);
|
||||
}
|
||||
|
||||
protected void map(Mark mark, DeviceIdentifier device, long from, long to) {
|
||||
regattaLog.add(new RegattaLogDeviceMarkMappingEventImpl(MillisecondsTimePoint.now(), MillisecondsTimePoint.now(), author, UUID.randomUUID(),
|
||||
mark, device, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to)));
|
||||
}
|
||||
|
||||
protected void testNumberOfRawFixes(Track<?> track, long expected) {
|
||||
track.lockForRead();
|
||||
assertEquals(expected, size(track.getRawFixes()));
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class CreateAndTrackWithRaceLogTest {
|
||||
gpsFixStore = service.getGPSFixStore();
|
||||
service.getMongoObjectFactory().getDatabase().dropDatabase();
|
||||
author = service.getServerAuthor();
|
||||
Series series = new SeriesImpl("series", false, Collections.singletonList(fleet), Collections.emptySet(),
|
||||
Series series = new SeriesImpl("series", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, Collections.singletonList(fleet), Collections.emptySet(),
|
||||
service);
|
||||
regatta = service.createRegatta(RegattaImpl.getDefaultName("regatta", "Laser"), "Laser",
|
||||
/* startDate */null, /* endDate */null, UUID.randomUUID(), Collections.<Series> singletonList(series), false,
|
||||
@@ -170,7 +170,7 @@ public class CreateAndTrackWithRaceLogTest {
|
||||
|
||||
// add a mapping and one fix in, one out of mapping
|
||||
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(0), t(10)));
|
||||
addFixes0(dev1);
|
||||
@@ -206,7 +206,7 @@ public class CreateAndTrackWithRaceLogTest {
|
||||
|
||||
// add a mapping and one fix in, one out of mapping
|
||||
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
|
||||
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, UUID.randomUUID(), comp1, dev1,
|
||||
t(0), t(10)));
|
||||
|
||||
@@ -1,150 +1,150 @@
|
||||
package com.sap.sailing.domain.racelogtracking.test.impl;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
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.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
|
||||
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||
|
||||
@Test
|
||||
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
|
||||
NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
|
||||
map(comp, device, 0, 10000);
|
||||
map(mark, markDevice, 0, 10000);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40)); // before
|
||||
store.storeFix(device, createFix(1100, 10, 20, 30, 40)); // in
|
||||
store.storeFix(device, createFix(2100, 10, 20, 30, 40)); // after
|
||||
store.storeFix(markDevice, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40));
|
||||
store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40));
|
||||
|
||||
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000));
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
// now extend the tracking interval of the tracked race and assert that the additional fixes are loaded
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500), /* wait for fixes to load */ true);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 2);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0), /* wait for fixes to load */ true);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 3);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException,
|
||||
InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
|
||||
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp,
|
||||
comp2 }));
|
||||
|
||||
map(comp, device, 0, 20000);
|
||||
map(comp2, device2, 0, 600);
|
||||
// reuse device for two marks
|
||||
map(mark, device3, 0, 600);
|
||||
map(mark2, device3, 0, 600);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
store.storeFix(device2, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
store.storeFix(device, createFix(i + 1000, 10, 20, 30, 40));
|
||||
}
|
||||
|
||||
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 10002);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp2), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
assertEquals(0, store.getNumberOfFixes(device));
|
||||
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
|
||||
|
||||
map(comp, device, 0, 600);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
|
||||
assertEquals(2, store.getNumberOfFixes(device));
|
||||
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.racelogtracking.test.impl;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
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.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.impl.TimeRangeImpl;
|
||||
|
||||
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
|
||||
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||
|
||||
@Test
|
||||
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
|
||||
NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
|
||||
map(comp, device, 0, 10000);
|
||||
map(mark, markDevice, 0, 10000);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40)); // before
|
||||
store.storeFix(device, createFix(1100, 10, 20, 30, 40)); // in
|
||||
store.storeFix(device, createFix(2100, 10, 20, 30, 40)); // after
|
||||
store.storeFix(markDevice, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40));
|
||||
store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40));
|
||||
|
||||
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000));
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000));
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
// now extend the tracking interval of the tracked race and assert that the additional fixes are loaded
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500), /* wait for fixes to load */ true);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 2);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2);
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0), /* wait for fixes to load */ true);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 3);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException,
|
||||
InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
DeviceIdentifier device2 = new SmartphoneImeiIdentifier("imei2");
|
||||
DeviceIdentifier device3 = new SmartphoneImeiIdentifier("imei3");
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp,
|
||||
comp2 }));
|
||||
|
||||
map(comp, device, 0, 20000);
|
||||
map(comp2, device2, 0, 600);
|
||||
// reuse device for two marks
|
||||
map(mark, device3, 0, 600);
|
||||
map(mark2, device3, 0, 600);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
store.storeFix(device2, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device3, createFix(100, 10, 20, 30, 40));
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
store.storeFix(device, createFix(i + 1000, 10, 20, 30, 40));
|
||||
}
|
||||
|
||||
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
|
||||
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp), 10002);
|
||||
testNumberOfRawFixes(trackedRace.getTrack(comp2), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1);
|
||||
testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException {
|
||||
assertEquals(0, store.getNumberOfFixes(device));
|
||||
assertEquals(null, store.getTimeRangeCoveredByFixes(device));
|
||||
|
||||
map(comp, device, 0, 600);
|
||||
|
||||
store.storeFix(device, createFix(100, 10, 20, 30, 40));
|
||||
store.storeFix(device, createFix(200, 10, 20, 30, 40));
|
||||
|
||||
assertEquals(2, store.getNumberOfFixes(device));
|
||||
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.sap.sailing.domain.racelogtracking.test.impl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
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.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
|
||||
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.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
|
||||
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
|
||||
|
||||
/**
|
||||
* tests the precedence order described in {@link TrackedRaceImpl#updateStartAndEndOfTracking()}
|
||||
*/
|
||||
@Test
|
||||
public void testStartTimeInferencePrecedenceOrder() throws TransformationException,
|
||||
NoCorrespondingServiceRegisteredException, InterruptedException {
|
||||
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
|
||||
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
|
||||
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
|
||||
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
|
||||
new WaypointImpl(mark2) }));
|
||||
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
|
||||
|
||||
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
|
||||
null, /* endDate */null, null, null, "a", null));
|
||||
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
|
||||
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
|
||||
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
|
||||
|
||||
setStartAndEndOfRaceInRaceLog(10000, 20000);
|
||||
trackedRace.attachRaceLog(raceLog);
|
||||
trackedRace.attachRegattaLog(regattaLog);
|
||||
|
||||
//test inference via race start/end time in racelog
|
||||
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(regattaLog);
|
||||
MillisecondsTimePoint startOfRaceInRaceLog = new MillisecondsTimePoint(10000);
|
||||
TimePoint expectedStartOfTracking = startOfRaceInRaceLog.minus(Duration.ONE_MINUTE.times(TrackedRaceImpl.TRACKING_BUFFER_IN_MINUTES));
|
||||
MillisecondsTimePoint endOfRaceInRaceLog = new MillisecondsTimePoint(20000);
|
||||
TimePoint expectedEndOfTracking = endOfRaceInRaceLog.plus(Duration.ONE_MINUTE.times(TrackedRaceImpl.TRACKING_BUFFER_IN_MINUTES));
|
||||
assertEquals(expectedStartOfTracking, trackedRace.getStartOfTracking());
|
||||
assertEquals(expectedEndOfTracking, trackedRace.getEndOfTracking());
|
||||
|
||||
|
||||
//test inference via manually set start/end of tracking
|
||||
setManualTrackingTimesOnTrackedRace(trackedRace, 30000, 40000);
|
||||
assertEquals(new MillisecondsTimePoint(30000), trackedRace.getStartOfTracking());
|
||||
assertEquals(new MillisecondsTimePoint(40000), trackedRace.getEndOfTracking());
|
||||
|
||||
//shouldn't change when setting time in raceLog again
|
||||
setStartAndEndOfRaceInRaceLog(100000, 200000);
|
||||
assertEquals(new MillisecondsTimePoint(30000), trackedRace.getStartOfTracking());
|
||||
assertEquals(new MillisecondsTimePoint(40000), trackedRace.getEndOfTracking());
|
||||
|
||||
//test inference via start/end of tracking in RaceLog
|
||||
setStartAndEndOfTrackingInRaceLog(50000, 60000);
|
||||
MillisecondsTimePoint startOfTrackingInRacelog = new MillisecondsTimePoint(50000);
|
||||
MillisecondsTimePoint endOfTrackingInRacelog = new MillisecondsTimePoint(60000);
|
||||
assertEquals(startOfTrackingInRacelog, trackedRace.getStartOfTracking());
|
||||
assertEquals(endOfTrackingInRacelog, trackedRace.getEndOfTracking());
|
||||
|
||||
//shouldn't change when setting time in raceLog again
|
||||
setStartAndEndOfRaceInRaceLog(300000, 400000);
|
||||
assertEquals(startOfTrackingInRacelog, trackedRace.getStartOfTracking());
|
||||
assertEquals(endOfTrackingInRacelog, trackedRace.getEndOfTracking());
|
||||
|
||||
//shouldn't change when setting start/end of tracking
|
||||
setManualTrackingTimesOnTrackedRace(trackedRace, 500000, 600000);
|
||||
assertEquals(startOfTrackingInRacelog, trackedRace.getStartOfTracking());
|
||||
assertEquals(endOfTrackingInRacelog, trackedRace.getEndOfTracking());
|
||||
}
|
||||
|
||||
|
||||
public void setStartAndEndOfTrackingInRaceLog(int startTime, int endTime){
|
||||
MillisecondsTimePoint startOfTrackingInRacelog = new MillisecondsTimePoint(startTime);
|
||||
MillisecondsTimePoint endOfTrackingInRacelog = new MillisecondsTimePoint(endTime);
|
||||
raceLog.add(new RaceLogStartOfTrackingEventImpl(startOfTrackingInRacelog, author, 0));
|
||||
raceLog.add(new RaceLogEndOfTrackingEventImpl(endOfTrackingInRacelog, author, 0));
|
||||
}
|
||||
|
||||
public void setStartAndEndOfRaceInRaceLog(int startTime, int endTime){
|
||||
MillisecondsTimePoint startTimeInRaceLog2 = new MillisecondsTimePoint(startTime);
|
||||
MillisecondsTimePoint endTimeInRaceLog2 = new MillisecondsTimePoint(endTime);
|
||||
raceLog.add(new RaceLogStartTimeEventImpl(startTimeInRaceLog2, author, 0, startTimeInRaceLog2));
|
||||
raceLog.add(new RaceLogRaceStatusEventImpl(endTimeInRaceLog2, endTimeInRaceLog2, author, UUID.randomUUID(), 0, RaceLogRaceStatus.FINISHED));
|
||||
}
|
||||
|
||||
public void setManualTrackingTimesOnTrackedRace(DynamicTrackedRace trackedRace, int startTime, int endTime){
|
||||
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(startTime));
|
||||
trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(endTime));
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//resources/stringmessages/TrackingStringMessages_de.properties=UTF-8
|
||||
@@ -21,6 +21,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.mail
|
||||
Import-Package: com.google.zxing;version="3.1.0",
|
||||
com.mongodb,
|
||||
com.sap.sse.shared.media,
|
||||
javax.mail;version="1.4.0",
|
||||
javax.mail.internet;version="1.4.0",
|
||||
javax.mail.util;version="1.4.0",
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
trackingInvitationFor=Einladung zum Tracken für
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Installiere die SAP Sailing Boat Tracker App. Dann scanne den QRCode oder klicke den Link mit deinem Smartphone an, um dich zu registrieren als
|
||||
trackingInvitationFor=Einladung zum Tracken für
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Installiere die {0} App. Dann scanne den QRCode oder klicke den Link mit deinem Smartphone an, um dich zu registrieren als
|
||||
welcomeTo=Willkommen zu
|
||||
iOSUsers=iOS-Benutzer
|
||||
androidUsers=Android-Benutzer
|
||||
alternativelyVisitThisLink=Alternativ kannst du, wenn du die App bereits installiert hast, diesen Link anklicken
|
||||
buoyTender=Bojenleger
|
||||
iOSUsers=iOS App starten
|
||||
androidUsers=Android App starten
|
||||
alternativelyVisitThisLink=Wenn die App bereits installiert ist, und du diese Mail auch auf dem Geräte offen hast, dann einfach hier clicken:
|
||||
buoyTender=Bojenleger
|
||||
appStoreInstallText=Falls die App noch nicht installiert ist, kannst du sie hier finden:Ÿ
|
||||
appIos=iOS App installieren
|
||||
appAndroid=Android App installieren
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
sailInSightAppName=SAP Sail InSight
|
||||
@@ -1,7 +1,12 @@
|
||||
trackingInvitationFor=Tracking Invitation for
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Make sure you have the SAP Sailing Boat Tracker App installed. Then scan the following QRCode or click the link using your smartphone to register as
|
||||
scanQRCodeOrVisitUrlToRegisterAs=Make sure you have the {0} App installed. Then scan the following QRCode or click the link using your smartphone to register as
|
||||
welcomeTo=Welcome to
|
||||
iOSUsers=iOS Users
|
||||
androidUsers=Android Users
|
||||
alternativelyVisitThisLink=Alternatively, when you have the app already installed, you can click this Link
|
||||
buoyTender=buoy tender
|
||||
iOSUsers=Start iOS App
|
||||
androidUsers=Start Android App
|
||||
alternativelyVisitThisLink=If you are reading this mail on the device with the App already installed, simply click below to start:
|
||||
buoyTender=buoy tender
|
||||
appStoreInstallText=If don't have the App yet, please install:
|
||||
appIos=Install iOS App
|
||||
appAndroid=Install Android App
|
||||
buoyPingerAppName=SAP Sailing Buoy Pinger
|
||||
sailInSightAppName=SAP Sail InSight
|
||||
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
|
||||
import com.sap.sailing.domain.racelogtracking.impl.RaceLogRaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -87,15 +88,17 @@ public interface RaceLogTrackingAdapter {
|
||||
* @throws MailException
|
||||
*/
|
||||
void inviteCompetitorsForTrackingViaEmail(Event event, Leaderboard leaderboard,
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, Locale locale) throws MailException;
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, String iOSAppUrl, String androidAppUrl,
|
||||
Locale locale) throws MailException;
|
||||
|
||||
/**
|
||||
* Invite buoy tenders for buoy pinging via the Buoy Tender App by sending out emails.
|
||||
*
|
||||
* @param appUrl
|
||||
* @throws MailException
|
||||
*/
|
||||
void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
|
||||
String emails, Locale locale) throws MailException;
|
||||
String emails, String iOSAppUrl, String androidAppUrl, Locale locale) throws MailException;
|
||||
|
||||
/**
|
||||
* Copy the course in the newest {@link RaceLogCourseDesignChangedEvent} in {@code from} race log to the {@code to}
|
||||
|
||||
@@ -19,11 +19,14 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEndOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
|
||||
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinder;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
|
||||
@@ -56,6 +59,8 @@ import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.common.abstractlog.TimePointSpecificationFoundInLog;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException;
|
||||
@@ -145,6 +150,18 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
public void visit(RaceLogEndOfTrackingEvent event) {
|
||||
RaceLogRaceTracker.this.onEndOfTrackingEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogStartTimeEvent event) {
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogRaceStatusEvent event) {
|
||||
if (event.getNextStatus().equals(RaceLogRaceStatus.FINISHED)){
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
}
|
||||
};
|
||||
visitors.put(log, visitor);
|
||||
((RaceLog) log).addListener(visitor);
|
||||
@@ -181,6 +198,14 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
|
||||
@Override
|
||||
public void stop(boolean preemptive) {
|
||||
RaceLog raceLog = params.getRaceLog();
|
||||
final Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog> trackingTimes = new TrackingTimesFinder(raceLog).analyze();
|
||||
if (trackingTimes == null || trackingTimes.getB() == null || trackingTimes.getB().getTimePoint() == null) {
|
||||
// seems the first time tracking for this race is stopped; enter "now" as end of tracking
|
||||
// into the race log
|
||||
raceLog.add(new RaceLogEndOfTrackingEventImpl(MillisecondsTimePoint.now(), raceLogEventAuthor, /* passId */ 0));
|
||||
}
|
||||
|
||||
// mark passing calculator is automatically stopped, when the race status is set to {@link
|
||||
// TrackedRaceStatusEnum#FINISHED}
|
||||
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.FINISHED, 100));
|
||||
@@ -399,19 +424,19 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
|
||||
private void onStartOfTrackingEvent(RaceLogStartOfTrackingEvent event) {
|
||||
if (trackedRace != null) {
|
||||
trackedRace.setStartOfTrackingReceived(event.getLogicalTimePoint());
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
}
|
||||
|
||||
private void onEndOfTrackingEvent(RaceLogEndOfTrackingEvent event) {
|
||||
if (trackedRace != null) {
|
||||
trackedRace.setEndOfTrackingReceived(event.getLogicalTimePoint());
|
||||
trackedRace.updateStartAndEndOfTracking();
|
||||
}
|
||||
}
|
||||
|
||||
private void onCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent event) {
|
||||
if (trackedRace != null) {
|
||||
CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog()).analyze();
|
||||
CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog(), /* onlyCoursesWithValidWaypointList */ true).analyze();
|
||||
List<Util.Pair<ControlPoint, PassingInstruction>> update = new ArrayList<>();
|
||||
for (Waypoint waypoint : base.getWaypoints()) {
|
||||
update.add(new Util.Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions()));
|
||||
@@ -429,15 +454,15 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
RaceColumn raceColumn = params.getRaceColumn();
|
||||
Fleet fleet = params.getFleet();
|
||||
RaceLogDenoteForTrackingEvent denoteEvent = new RaceInformationFinder(raceLog).analyze();
|
||||
final Pair<TimePoint, TimePoint> trackingTimes = new TrackingTimesFinder(raceLog).analyze();
|
||||
if (trackingTimes == null) {
|
||||
// seems the first time tracking for this race is started; enter "now" as start of tracking
|
||||
final Pair<TimePointSpecificationFoundInLog, TimePointSpecificationFoundInLog> trackingTimes = new TrackingTimesFinder(raceLog).analyze();
|
||||
if (trackingTimes == null || trackingTimes.getA() == null || trackingTimes.getA().getTimePoint() == null) {
|
||||
// the start of tracking interval is unset or set to null; enter "now" as start of tracking
|
||||
// into the race log
|
||||
raceLog.add(new RaceLogStartOfTrackingEventImpl(MillisecondsTimePoint.now(), raceLogEventAuthor, /* passId */ 0));
|
||||
}
|
||||
BoatClass boatClass = denoteEvent.getBoatClass();
|
||||
String raceName = denoteEvent.getRaceName();
|
||||
CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog).analyze();
|
||||
CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true).analyze();
|
||||
if (courseBase == null) {
|
||||
courseBase = new CourseDataImpl("Default course for " + raceName);
|
||||
logger.log(Level.FINE, "Using empty course in creation of race " + raceName);
|
||||
@@ -507,7 +532,22 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
|
||||
for (DeviceMapping<Mark> mapping : markMappingsByDevices.get(device)) {
|
||||
Mark mark = mapping.getMappedTo();
|
||||
if (mapping.getTimeRange().includes(timePoint)) {
|
||||
trackedRace.recordFix(mark, fix);
|
||||
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
|
||||
final GPSFix firstFixAtOrAfter;
|
||||
boolean forceFix;
|
||||
markTrack.lockForRead();
|
||||
try {
|
||||
forceFix = Util.isEmpty(markTrack.getRawFixes()) ||
|
||||
(firstFixAtOrAfter=markTrack.getFirstFixAtOrAfter(timePoint)) != null &&
|
||||
firstFixAtOrAfter.getTimePoint().equals(timePoint);
|
||||
} finally {
|
||||
markTrack.unlockAfterRead();
|
||||
}
|
||||
if (forceFix) {
|
||||
trackedRace.recordFix(mark, fix, /* only when in tracking interval */ false); // force fix into track
|
||||
} else {
|
||||
trackedRace.recordFix(mark, fix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.racelogtracking.impl;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -46,6 +47,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.SharedDomainFactory;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.domain.common.CourseDesignerMode;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException;
|
||||
@@ -69,8 +71,11 @@ import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.mail.MailException;
|
||||
import com.sap.sse.common.media.MediaTagConstants;
|
||||
import com.sap.sse.i18n.ResourceBundleStringMessages;
|
||||
import com.sap.sse.mail.MailService;
|
||||
import com.sap.sse.qrcode.QRCodeGenerationUtil;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.util.impl.NonGwtUrlHelper;
|
||||
|
||||
public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
@@ -190,7 +195,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
@Override
|
||||
public void copyCourse(RaceLog fromRaceLog, Set<RaceLog> toRaceLogs, SharedDomainFactory baseDomainFactory,
|
||||
RacingEventService service) {
|
||||
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze();
|
||||
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog, /* onlyCoursesWithValidWaypointList */ true).analyze();
|
||||
final Set<Mark> marks = new HashSet<>();
|
||||
if (course != null) {
|
||||
course.getWaypoints().forEach(wp -> Util.addAll(wp.getMarks(), marks));
|
||||
@@ -199,7 +204,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
for (RaceLog toRaceLog : toRaceLogs) {
|
||||
if (new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
|
||||
if (course != null) {
|
||||
CourseBase newCourse = new CourseDataImpl("Copy of \"" + course.getName() + "\"");
|
||||
CourseBase newCourse = new CourseDataImpl(course.getName());
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
int i = 0;
|
||||
for (Waypoint oldWaypoint : course.getWaypoints()) {
|
||||
@@ -208,7 +213,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
|
||||
int passId = toRaceLog.getCurrentPassId();
|
||||
RaceLogEvent newCourseEvent = new RaceLogCourseDesignChangedEventImpl(now,
|
||||
service.getServerAuthor(), passId, newCourse);
|
||||
service.getServerAuthor(), passId, newCourse, CourseDesignerMode.ADMIN_CONSOLE);
|
||||
toRaceLog.add(newCourseEvent);
|
||||
}
|
||||
|
||||
@@ -277,20 +282,26 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
|
||||
@Override
|
||||
public void inviteCompetitorsForTrackingViaEmail(Event event, Leaderboard leaderboard,
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, Locale locale) throws MailException {
|
||||
String serverUrlWithoutTrailingSlash, Set<Competitor> competitors, String iOSAppUrl, String androidAppUrl,
|
||||
Locale locale) throws MailException {
|
||||
StringBuilder occuredExceptions = new StringBuilder();
|
||||
|
||||
for (Competitor competitor : competitors) {
|
||||
final String toAddress = competitor.getEmail();
|
||||
if (toAddress != null) {
|
||||
String leaderboardName = leaderboard.getName();
|
||||
String competitorName = competitor.getName();
|
||||
|
||||
String url = DeviceMappingConstants.getDeviceMappingForRegattaLogUrl(serverUrlWithoutTrailingSlash,
|
||||
event.getId().toString(), leaderboardName, DeviceMappingConstants.URL_COMPETITOR_ID_AS_STRING,
|
||||
competitor.getId().toString(), NonGwtUrlHelper.INSTANCE);
|
||||
String logoUrl = null;
|
||||
final List<ImageDescriptor> imagesWithTag = event.findImagesWithTag(MediaTagConstants.LOGO);
|
||||
if (imagesWithTag != null && !imagesWithTag.isEmpty()) {
|
||||
logoUrl = imagesWithTag.get(0).getURL().toString();
|
||||
}
|
||||
try {
|
||||
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName, url);
|
||||
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
|
||||
sendInvitationEmail(locale, toAddress, leaderboardName, competitorName, url, B.get(locale, "sailInSightAppName"),
|
||||
iOSAppUrl, androidAppUrl, logoUrl);
|
||||
} catch (MailException e) {
|
||||
occuredExceptions.append(e.getMessage() + "\r\n");
|
||||
}
|
||||
@@ -302,29 +313,69 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
}
|
||||
|
||||
private void sendInvitationEmail(Locale locale, final String toAddress, String leaderboardName, String invitee,
|
||||
String url) throws MailException {
|
||||
String subject = String.format("%s %s",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "trackingInvitationFor"), invitee);
|
||||
String url, String appName, String iOSAppUrl, String androidAppUrl, String logoUrl) throws MailException {
|
||||
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
|
||||
String subject = String.format("%s %s", B.get(locale, "trackingInvitationFor"), invitee);
|
||||
|
||||
// taken from http://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm
|
||||
BodyPart messageTextPart = new MimeBodyPart();
|
||||
String htmlText = String.format("<h1>%s %s</h1>" + "<p>%s <b>%s</b></p>"
|
||||
+ "<img src=\"cid:image\" title=\"%s\"><br/><b>%s</b>: <a href=\"%s\">%s</a><br/><b>%s</b>: <a href=\"%s\">%s</a>",
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "welcomeTo"), leaderboardName,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "scanQRCodeOrVisitUrlToRegisterAs"), invitee,
|
||||
url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "iOSUsers"),
|
||||
IOS_DEEP_LINK_PREFIX+url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"),
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "androidUsers"),
|
||||
url, RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "alternativelyVisitThisLink"));
|
||||
|
||||
boolean hasIOSAppUrl = iOSAppUrl != null && !iOSAppUrl.isEmpty();
|
||||
boolean hasAndroidAppUrl = androidAppUrl != null && !androidAppUrl.isEmpty();
|
||||
boolean hasLogoUrl = logoUrl != null && !logoUrl.isEmpty();
|
||||
StringBuilder htmlText = new StringBuilder();
|
||||
htmlText.append("<!doctype html>\n");
|
||||
htmlText.append("<html>");
|
||||
htmlText.append("<head><title>");
|
||||
htmlText.append(B.get(locale, "welcomeTo")).append(" ").append(leaderboardName).append("</title>");
|
||||
htmlText.append("<style type=\"text/css\">\n");
|
||||
htmlText.append(".b,.b:active,b:visited {padding:15px;margin:10px;width:200px;display:inline-block;background-color:#337ab7;border-radius:4px;color:#ffffff;border:1px solid #2e6da4;text-decoration:none;}\n");
|
||||
htmlText.append(".b:hover {background-color:#2b618e;border:1px solid #204d74;}\n");
|
||||
htmlText.append(".qr {margin: 10px;height:250px; width: auto;}\n");
|
||||
htmlText.append(".spacer {margin-top: 50px;}\n");
|
||||
htmlText.append("</style>");
|
||||
htmlText.append("</head>");
|
||||
htmlText.append("<body>");
|
||||
if (hasLogoUrl) {
|
||||
htmlText.append("<p><img src=\"").append(logoUrl).append("\" /></p> ");
|
||||
}
|
||||
htmlText.append("<h1>").append(B.get(locale, "welcomeTo")).append(" ").append(leaderboardName).append("</h1> ");
|
||||
htmlText.append("<p>").append(B.get(locale, "scanQRCodeOrVisitUrlToRegisterAs", appName)).append(" <b>").append(invitee)
|
||||
.append("</b></p> ");
|
||||
htmlText.append("<p class=\"qr\"><img src=\"cid:image\" title=\"").append(url).append("\" /></p> ");
|
||||
htmlText.append("<p class=\"spacer\">").append(B.get(locale, "alternativelyVisitThisLink")).append("</p> ");
|
||||
if (hasIOSAppUrl) {
|
||||
htmlText.append("<a class=\"b\" href=\"").append(IOS_DEEP_LINK_PREFIX + url).append("\">")
|
||||
.append(B.get(locale, "iOSUsers")).append("</a> ");
|
||||
}
|
||||
if (hasAndroidAppUrl) {
|
||||
htmlText.append("<a class=\"b\" href=\"").append(url).append("\">").append(B.get(locale, "androidUsers"))
|
||||
.append("</a> ");
|
||||
}
|
||||
if (hasIOSAppUrl || hasAndroidAppUrl) {
|
||||
htmlText.append("<p class=\"spacer\">").append(B.get(locale, "appStoreInstallText")).append("</p> ");
|
||||
}
|
||||
if (hasIOSAppUrl) {
|
||||
htmlText.append("<a class=\"b\" href=\"").append(iOSAppUrl).append("\">").append(B.get(locale, "appIos"))
|
||||
.append("</a> ");
|
||||
}
|
||||
if (hasAndroidAppUrl) {
|
||||
htmlText.append("<a class=\"b\" href=\"").append(androidAppUrl).append("\">")
|
||||
.append(B.get(locale, "appAndroid")).append("</a> ");
|
||||
}
|
||||
htmlText.append("<p class=\"spacer\"></p>");
|
||||
htmlText.append("</body>");
|
||||
htmlText.append("</html>");
|
||||
|
||||
try {
|
||||
messageTextPart.setContent(htmlText, "text/html");
|
||||
messageTextPart.setContent(htmlText.toString(), "text/html");
|
||||
|
||||
BodyPart messageImagePart = new MimeBodyPart();
|
||||
InputStream imageIs = QRCodeGenerationUtil.create(url, 250);
|
||||
DataSource imageDs = new ByteArrayDataSource(imageIs, "image/png");
|
||||
messageImagePart.setDataHandler(new DataHandler(imageDs));
|
||||
messageImagePart.setHeader("Content-ID", "<image>");
|
||||
messageImagePart.setHeader("Content-Disposition", "inline;filename=\"qr.png\"");
|
||||
|
||||
MimeMultipart multipart = new MimeMultipart();
|
||||
multipart.addBodyPart(messageTextPart);
|
||||
@@ -339,27 +390,29 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
|
||||
|
||||
@Override
|
||||
public void inviteBuoyTenderViaEmail(Event event, Leaderboard leaderboard, String serverUrlWithoutTrailingSlash,
|
||||
String emails, Locale locale) throws MailException {
|
||||
|
||||
String emails, String iOSAppUrl, String androidAppUrl, Locale locale) throws MailException {
|
||||
StringBuilder occuredExceptions = new StringBuilder();
|
||||
|
||||
String[] emailArray = emails.split(",");
|
||||
String leaderboardName = leaderboard.getName();
|
||||
|
||||
String eventId = event.getId().toString();
|
||||
|
||||
String logoUrl = null;
|
||||
List<ImageDescriptor> imagesWithTag = event.findImagesWithTag(MediaTagConstants.LOGO);
|
||||
if (imagesWithTag != null && !imagesWithTag.isEmpty()) {
|
||||
logoUrl = imagesWithTag.get(0).getURL().toString();
|
||||
}
|
||||
// http://<host>/buoy-tender/checkin?event_id=<event-id>&leaderboard_name=<leaderboard-name>
|
||||
String url = DeviceMappingConstants.getBuoyTenderInvitationUrl(serverUrlWithoutTrailingSlash, leaderboardName,
|
||||
eventId, NonGwtUrlHelper.INSTANCE);
|
||||
for (String toAddress : emailArray) {
|
||||
try {
|
||||
final ResourceBundleStringMessages B = RaceLogTrackingI18n.STRING_MESSAGES;
|
||||
sendInvitationEmail(locale, toAddress, leaderboardName,
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url);
|
||||
RaceLogTrackingI18n.STRING_MESSAGES.get(locale, "buoyTender"), url, B.get(locale, "buoyPingerAppName"), iOSAppUrl,
|
||||
androidAppUrl, logoUrl);
|
||||
} catch (MailException e) {
|
||||
occuredExceptions.append(e.getMessage() + "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!(occuredExceptions.length() == 0)) {
|
||||
throw new MailException(occuredExceptions.toString());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
package com.sap.sailing.domain.base.racegroup.impl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.racegroup.CurrentRaceFilter;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceCell;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceGroup;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceGroupSeriesFleetRaceColumn;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceRow;
|
||||
import com.sap.sailing.domain.base.racegroup.SeriesWithRows;
|
||||
import com.sap.sailing.domain.common.BoatClassMasterdata;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
|
||||
public class CurrentRaceFilterImplTest {
|
||||
|
||||
private CurrentRaceFilter<SimpleFilterableRace> fixture;
|
||||
private RaceGroup _505;
|
||||
private RaceGroup yes;
|
||||
private RaceGroup isaf;
|
||||
private RaceGroup league;
|
||||
private RaceGroup ess;
|
||||
private Map<RaceGroupSeriesFleetRaceColumn, SimpleFilterableRace> races;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
races = new HashMap<>();
|
||||
// five regattas ("RaceGroup"s):
|
||||
// - simple single-series, single fleet set-up (505 style)
|
||||
// - single-series, two fleets (Yellow / Blue, as used by YES)
|
||||
// - qualification with Yellow / Blue; final with Gold / Silver; Medal
|
||||
// - league set-up with single series with three fleets Red/Green/Blue
|
||||
_505 = create505Regatta();
|
||||
races.putAll(getAllRaces(_505));
|
||||
yes = createYesRegatta();
|
||||
races.putAll(getAllRaces(yes));
|
||||
isaf = createIsafRegatta();
|
||||
races.putAll(getAllRaces(isaf));
|
||||
league = createLeagueRegatta();
|
||||
races.putAll(getAllRaces(league));
|
||||
ess = createEssRegatta();
|
||||
races.putAll(getAllRaces(ess));
|
||||
fixture = new CurrentRaceFilterImpl<>(races.values());
|
||||
}
|
||||
|
||||
private RaceGroup create505Regatta() {
|
||||
final List<SeriesWithRows> _505Series = new ArrayList<>();
|
||||
final List<RaceRow> _505RaceRows = new ArrayList<>();
|
||||
final RaceRow _505RaceRow = createRaceRow(/* firstRaceColumnNumber */ 1, /* numberOfRaces */ 9, /* raceColumnNamePrefix */ "R", /* fleetName */ "Default");
|
||||
_505RaceRows.add(_505RaceRow);
|
||||
_505Series.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, _505RaceRows));
|
||||
final RaceGroup _505 = new RaceGroupImpl("505", /* displayName */ null,
|
||||
new BoatClassImpl(BoatClassMasterdata._5O5.getDisplayName(), BoatClassMasterdata._5O5),
|
||||
/* courseArea */ null, _505Series, /* regattaConfiguration */ null);
|
||||
return _505;
|
||||
}
|
||||
|
||||
private RaceGroup createYesRegatta() {
|
||||
final List<SeriesWithRows> yesSeries = new ArrayList<>();
|
||||
final List<RaceRow> yesRaceRows = Arrays.asList(createRaceRow(1, 9, "R", "Yellow"), createRaceRow(1, 9, "R", "Blue"));
|
||||
yesSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, yesRaceRows));
|
||||
final RaceGroup yes = new RaceGroupImpl("YES", /* displayName */ null,
|
||||
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470),
|
||||
/* courseArea */ null, yesSeries, /* regattaConfiguration */ null);
|
||||
return yes;
|
||||
}
|
||||
|
||||
private RaceGroup createIsafRegatta() {
|
||||
final List<SeriesWithRows> isafSeries = new ArrayList<>();
|
||||
final List<RaceRow> isafQualificationRaceRows = Arrays.asList(createRaceRow(1, 5, "Q", "Yellow"), createRaceRow(1, 5, "Q", "Blue"));
|
||||
isafSeries.add(new SeriesWithRowsImpl("Qualification", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, isafQualificationRaceRows));
|
||||
final List<RaceRow> isafFinalRaceRows = Arrays.asList(createRaceRow(6, 5, "F", "Gold"), createRaceRow(6, 5, "F", "Silver"));
|
||||
isafSeries.add(new SeriesWithRowsImpl("Final", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, isafFinalRaceRows));
|
||||
final List<RaceRow> isafMedalRaceRows = Arrays.asList(createRaceRow(1, 1, "M", "Medal"));
|
||||
isafSeries.add(new SeriesWithRowsImpl("Medal", /* isMedal */ true, /* isFleetsCanRunInParallel */ true, isafMedalRaceRows));
|
||||
final RaceGroup isaf = new RaceGroupImpl("ISAF", /* displayName */ null,
|
||||
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470),
|
||||
/* courseArea */ null, isafSeries, /* regattaConfiguration */ null);
|
||||
return isaf;
|
||||
}
|
||||
|
||||
private RaceGroup createEssRegatta() {
|
||||
final List<SeriesWithRows> essSeries = new ArrayList<>();
|
||||
final List<RaceRow> essDay1RaceRows = Arrays.asList(createRaceRow(1, 5, "R", "Default"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Day 1", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay1RaceRows));
|
||||
final List<RaceRow> essDay2RaceRows = Arrays.asList(createRaceRow(6, 5, "R", "Default"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Day 2", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay2RaceRows));
|
||||
final List<RaceRow> essKnockoutQualificationRaceRows = Arrays.asList(createRaceRow(1, 1, "Q", "Yellow"), createRaceRow(1, 1, "Q", "Blue"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Knockout Qualification", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essKnockoutQualificationRaceRows));
|
||||
final List<RaceRow> essKnockoutScoringRaceRows = Arrays.asList(createRaceRow(1, 1, "F", "Gold"), createRaceRow(1, 1, "F", "Silver"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Knockout Finals", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, essKnockoutScoringRaceRows));
|
||||
final List<RaceRow> essDay3RaceRows = Arrays.asList(createRaceRow(11, 5, "R", "Default"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Day 3", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay3RaceRows));
|
||||
final List<RaceRow> essDay4RaceRows = Arrays.asList(createRaceRow(16, 5, "R", "Default"));
|
||||
essSeries.add(new SeriesWithRowsImpl("Day 4", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay4RaceRows));
|
||||
final RaceGroup ess = new RaceGroupImpl("ESS", /* displayName */ null,
|
||||
new BoatClassImpl(BoatClassMasterdata.EXTREME_40.getDisplayName(), BoatClassMasterdata.EXTREME_40),
|
||||
/* courseArea */ null, essSeries, /* regattaConfiguration */ null);
|
||||
return ess;
|
||||
}
|
||||
|
||||
private RaceGroup createLeagueRegatta() {
|
||||
final List<SeriesWithRows> leagueSeries = new ArrayList<>();
|
||||
final List<RaceRow> leagueRaceRows = Arrays.asList(createRaceRow(1, 15, "F", "Red"), createRaceRow(1, 15, "F", "Green"), createRaceRow(1, 15, "F", "Blue"));
|
||||
leagueSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, leagueRaceRows));
|
||||
final RaceGroup league = new RaceGroupImpl("League", /* displayName */ null,
|
||||
new BoatClassImpl(BoatClassMasterdata.J70.getDisplayName(), BoatClassMasterdata.J70),
|
||||
/* courseArea */ null, leagueSeries, /* regattaConfiguration */ null);
|
||||
return league;
|
||||
}
|
||||
|
||||
private Map<RaceGroupSeriesFleetRaceColumn, SimpleFilterableRace> getAllRaces(RaceGroup raceGroup) {
|
||||
final Map<RaceGroupSeriesFleetRaceColumn, SimpleFilterableRace> result = new HashMap<>();
|
||||
int zeroBasedSeriesIndex = 0;
|
||||
for (SeriesWithRows series : raceGroup.getSeries()) {
|
||||
for (final RaceRow raceRow : series.getRaceRows()) {
|
||||
int zeroBasedIndexInFleet = 0;
|
||||
for (final RaceCell raceCell : raceRow.getCells()) {
|
||||
final SimpleFilterableRace race = new SimpleFilterableRace(raceGroup, series, raceRow.getFleet(), zeroBasedIndexInFleet, zeroBasedSeriesIndex, raceCell.getName());
|
||||
result.put(new RaceGroupSeriesFleetRaceColumn(race), race);
|
||||
zeroBasedIndexInFleet++;
|
||||
}
|
||||
}
|
||||
zeroBasedSeriesIndex++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceAccessAndStatusUpdate() {
|
||||
SimpleFilterableRace isafQ4Yellow = get(isaf, "F7", "Gold");
|
||||
assertNotNull(isafQ4Yellow);
|
||||
assertEquals("F7", isafQ4Yellow.getRaceColumnName());
|
||||
assertEquals("Gold", isafQ4Yellow.getFleet().getName());
|
||||
assertEquals(1, isafQ4Yellow.getZeroBasedIndexInFleet());
|
||||
assertEquals(1, isafQ4Yellow.getZeroBasedSeriesIndex());
|
||||
assertEquals(RaceLogRaceStatus.UNSCHEDULED, isafQ4Yellow.getStatus());
|
||||
isafQ4Yellow.setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
assertEquals(RaceLogRaceStatus.SCHEDULED, isafQ4Yellow.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicFilteringForFirstUnscheduledRaces() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
|
||||
{
|
||||
final Set<SimpleFilterableRace> current505Races = currentRaces.stream().filter(r->r.getRaceGroup() == _505).collect(Collectors.toSet());
|
||||
assertEquals(1, current505Races.size());
|
||||
final SimpleFilterableRace firstRace = current505Races.iterator().next();
|
||||
assertEquals("R1", firstRace.getRaceColumnName());
|
||||
}
|
||||
{
|
||||
final Set<SimpleFilterableRace> currentYesRaces = currentRaces.stream().filter(r->r.getRaceGroup() == yes).collect(Collectors.toSet());
|
||||
assertEquals(2, currentYesRaces.size());
|
||||
for (final SimpleFilterableRace currentYesRace : currentYesRaces) {
|
||||
assertEquals("R1", currentYesRace.getRaceColumnName());
|
||||
}
|
||||
}
|
||||
{
|
||||
final Set<SimpleFilterableRace> currentIsafRaces = currentRaces.stream().filter(r->r.getRaceGroup() == isaf).collect(Collectors.toSet());
|
||||
assertEquals(2, currentIsafRaces.size());
|
||||
for (final SimpleFilterableRace currentYesRace : currentIsafRaces) {
|
||||
assertEquals("Q1", currentYesRace.getRaceColumnName());
|
||||
}
|
||||
}
|
||||
{
|
||||
final Set<SimpleFilterableRace> currentLeagueRaces = currentRaces.stream().filter(r->r.getRaceGroup() == league).collect(Collectors.toSet());
|
||||
assertEquals(1, currentLeagueRaces.size());
|
||||
final SimpleFilterableRace firstRace = currentLeagueRaces.iterator().next();
|
||||
assertEquals("Red", firstRace.getFleet().getName());
|
||||
assertEquals("F1", firstRace.getRaceColumnName());
|
||||
}
|
||||
{
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(1, currentEssRaces.size());
|
||||
final SimpleFilterableRace firstRace = currentEssRaces.iterator().next();
|
||||
assertEquals("Default", firstRace.getFleet().getName());
|
||||
assertEquals("R1", firstRace.getRaceColumnName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulingFirst505Race() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
get(_505, "R1", "Default").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> current505Races = currentRaces.stream().filter(r->r.getRaceGroup() == _505).collect(Collectors.toSet());
|
||||
assertEquals(2, current505Races.size());
|
||||
assertTrue(current505Races.contains(get(_505, "R1", "Default"))); // it's scheduled, so it shows
|
||||
assertTrue(current505Races.contains(get(_505, "R2", "Default"))); // it's unscheduled and has a scheduled immediate predecessor
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulingFirstIsafRace() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
get(isaf, "Q1", "Yellow").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentIsafRaces = currentRaces.stream().filter(r->r.getRaceGroup() == isaf).collect(Collectors.toSet());
|
||||
assertEquals(3, currentIsafRaces.size());
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "Q1", "Yellow"))); // it's scheduled, so it shows
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "Q1", "Blue"))); // it's unscheduled, first in fleet
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "Q2", "Yellow"))); // predecessor Q1/Yellow is scheduled, so show this as next in fleet
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulingFirstEssRace() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
get(ess, "R1", "Default").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(2, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "R1", "Default"))); // it's scheduled, so it shows
|
||||
assertTrue(currentEssRaces.contains(get(ess, "R2", "Default"))); // it's unscheduled, first after last scheduled
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllEssRacesBeforeKnockoutQualification() {
|
||||
for (int i=1; i<=10; i++) {
|
||||
get(ess, "R"+i, "Default").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(2, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "Q1", "Yellow")));
|
||||
assertTrue(currentEssRaces.contains(get(ess, "Q1", "Blue")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllEssRacesBeforeKnockoutQualificationAndSchedulingFirstKnockout() {
|
||||
for (int i=1; i<=10; i++) {
|
||||
get(ess, "R"+i, "Default").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
get(ess, "Q1", "Yellow").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(3, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "Q1", "Yellow"))); // scheduled
|
||||
assertTrue(currentEssRaces.contains(get(ess, "Q1", "Blue"))); // unscheduled
|
||||
assertTrue(currentEssRaces.contains(get(ess, "F1", "Gold"))); // first unscheduled in series; last column in preceding series has scheduled race
|
||||
// F1/Silver remains invisible because the knockout finals runs its fleets in sequence
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllEssRacesBeforeKnockoutFinals() {
|
||||
for (int i=1; i<=10; i++) {
|
||||
get(ess, "R"+i, "Default").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
get(ess, "Q1", "Yellow").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "Q1", "Blue").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(1, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "F1", "Gold"))); // first unscheduled in series; last column in preceding series has scheduled race
|
||||
// F1/Silver remains invisible because the knockout finals runs its fleets in sequence
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllEssRacesBeforeKnockoutFinalsAndGoldRaceStarted() {
|
||||
for (int i=1; i<=10; i++) {
|
||||
get(ess, "R"+i, "Default").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
get(ess, "Q1", "Yellow").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "Q1", "Blue").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "F1", "Gold").setStatus(RaceLogRaceStatus.RUNNING);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(2, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "F1", "Gold"))); // running
|
||||
assertTrue(currentEssRaces.contains(get(ess, "F1", "Silver"))); // first unscheduled with a predecessor that's running
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllEssRacesBeforeKnockoutFinalsAndGoldRaceFinishedAndSilverRaceScheduled() {
|
||||
for (int i=1; i<=10; i++) {
|
||||
get(ess, "R"+i, "Default").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
get(ess, "Q1", "Yellow").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "Q1", "Blue").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "F1", "Gold").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(ess, "F1", "Silver").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentEssRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(2, currentEssRaces.size());
|
||||
assertTrue(currentEssRaces.contains(get(ess, "F1", "Silver"))); // scheduled
|
||||
assertTrue(currentEssRaces.contains(get(ess, "R11", "Default"))); // first unscheduled in series with the last race in the preceding series scheduled
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulingAllIsafQualificationRacesButOne() {
|
||||
for (int i=1; i<=4; i++) {
|
||||
get(isaf, "Q"+i, "Yellow").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(isaf, "Q"+i, "Blue").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
get(isaf, "Q5", "Blue").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentIsafRaces = currentRaces.stream().filter(r->r.getRaceGroup() == isaf).collect(Collectors.toSet());
|
||||
assertEquals(4, currentIsafRaces.size());
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "Q5", "Yellow"))); // it's unscheduled; its predecessor Q4/Yellow is FINISHED; show it
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "Q5", "Blue"))); // it's scheduled
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "F6", "Gold"))); // Q5/Blue is a scheduled immediate predecessor
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "F6", "Silver"))); // Q5/Blue is a scheduled immediate predecessor
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingAllIsafQualificationAndFinalRaces() {
|
||||
// the medal race shall be the only one remaining
|
||||
for (int i=1; i<=5; i++) {
|
||||
get(isaf, "Q"+i, "Yellow").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(isaf, "Q"+i, "Blue").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(isaf, "F"+(i+5), "Gold").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(isaf, "F"+(i+5), "Silver").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
}
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentIsafRaces = currentRaces.stream().filter(r->r.getRaceGroup() == isaf).collect(Collectors.toSet());
|
||||
assertEquals(1, currentIsafRaces.size());
|
||||
assertTrue(currentIsafRaces.contains(get(isaf, "M1", "Medal")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinishingFirstLeagueRace() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
get(league, "F1", "Red").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentLeagueRaces = currentRaces.stream().filter(r->r.getRaceGroup() == league).collect(Collectors.toSet());
|
||||
assertEquals(1, currentLeagueRaces.size());
|
||||
assertTrue(currentLeagueRaces.contains(get(league, "F1", "Green"))); // Red is finished, don't show it anymore
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkippingSecondLeagueRace() {
|
||||
// with all races unscheduled we can expect the first race of each regatta's first series to show
|
||||
get(league, "F1", "Red").setStatus(RaceLogRaceStatus.FINISHED);
|
||||
get(league, "F1", "Blue").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> currentLeagueRaces = currentRaces.stream().filter(r->r.getRaceGroup() == league).collect(Collectors.toSet());
|
||||
assertEquals(3, currentLeagueRaces.size());
|
||||
assertTrue(currentLeagueRaces.contains(get(league, "F1", "Green"))); // Red is finished, don't show it anymore; show the next one instead which is Green
|
||||
assertTrue(currentLeagueRaces.contains(get(league, "F1", "Blue"))); // show a scheduled race
|
||||
assertTrue(currentLeagueRaces.contains(get(league, "F2", "Red"))); // This is the next one after the scheduled F1/Blue
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartInSecondSeriesOf49erRaces() {
|
||||
// with all races unscheduled we start with the first race of the second series
|
||||
// we can expect the first race of each regatta's series to show except the first series
|
||||
get(isaf, "F6", "Gold").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> current49erRaces = currentRaces.stream().filter(r->r.getRaceGroup() == isaf).collect(Collectors.toSet());
|
||||
assertEquals(3, current49erRaces.size());
|
||||
assertTrue(current49erRaces.contains(get(isaf, "F6", "Gold"))); // it's scheduled, so it shows
|
||||
assertTrue(current49erRaces.contains(get(isaf, "F6", "Silver"))); // it's unscheduled, first in fleet
|
||||
assertTrue(current49erRaces.contains(get(isaf, "F7", "Gold"))); // predecessor F7/Gold is scheduled, so show this as next in fleet
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulingSilverFleetKnockoutFinalRaceAlsoShowsGoldRace() {
|
||||
// with nothing scheduled in earlier fleets, F1 Gold shall be scheduled when (erroneously or on purpose)
|
||||
// the later race F1 Silver is already scheduled.
|
||||
get(ess, "F1", "Silver").setStatus(RaceLogRaceStatus.SCHEDULED);
|
||||
final Set<SimpleFilterableRace> currentRaces = fixture.getCurrentRaces();
|
||||
final Set<SimpleFilterableRace> current49erRaces = currentRaces.stream().filter(r->r.getRaceGroup() == ess).collect(Collectors.toSet());
|
||||
assertEquals(3, current49erRaces.size());
|
||||
assertTrue(current49erRaces.contains(get(ess, "F1", "Gold"))); // it's unscheduled but the first in an already started series
|
||||
assertTrue(current49erRaces.contains(get(ess, "F1", "Silver"))); // it's scheduled
|
||||
assertTrue(current49erRaces.contains(get(ess, "R11", "Default"))); // preceding series' last column has a scheduled race
|
||||
}
|
||||
|
||||
private SimpleFilterableRace get(RaceGroup raceGroup, String raceColumnName, String fleetName) {
|
||||
for (final SeriesWithRows series : raceGroup.getSeries()) {
|
||||
final Fleet fleet = getFleet(series, fleetName);
|
||||
if (fleet != null) {
|
||||
final RaceRow raceRow = series.getRaceRow(fleet);
|
||||
if (raceRow != null) {
|
||||
for (final RaceCell raceCell : raceRow.getCells()) {
|
||||
if (raceCell.getName().equals(raceColumnName)) {
|
||||
return races.get(new RaceGroupSeriesFleetRaceColumn(raceGroup, series, fleet, raceColumnName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Fleet getFleet(SeriesWithRows series, String fleetName) {
|
||||
for (final Fleet fleet : series.getFleets()) {
|
||||
if (fleet.getName().equals(fleetName)) {
|
||||
return fleet;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RaceRow createRaceRow(final int firstRaceColumnNumber, final int numberOfRaces,
|
||||
final String raceColumnNamePrefix, final String fleetName) {
|
||||
final List<RaceCell> _505RaceCells = new ArrayList<>();
|
||||
for (int i=0; i < numberOfRaces; i++) {
|
||||
_505RaceCells.add(new RaceCellImpl(raceColumnNamePrefix+(i+firstRaceColumnNumber),
|
||||
/* race log */ null, /* factor */ firstRaceColumnNumber, /* explicitFactor */ null,
|
||||
/* zeroBasedIndexInFleet */ i));
|
||||
}
|
||||
final RaceRowImpl _505RaceRow = new RaceRowImpl(new FleetImpl(fleetName), _505RaceCells);
|
||||
return _505RaceRow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.sap.sailing.domain.base.racegroup.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.SeriesBase;
|
||||
import com.sap.sailing.domain.base.racegroup.FilterableRace;
|
||||
import com.sap.sailing.domain.base.racegroup.RaceGroup;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
|
||||
public class SimpleFilterableRace implements FilterableRace {
|
||||
private final RaceGroup raceGroup;
|
||||
private final SeriesBase series;
|
||||
private final Fleet fleet;
|
||||
private RaceLogRaceStatus status;
|
||||
private final int zeroBasedIndexInFleet;
|
||||
private final int zeroBasedSeriesIndex;
|
||||
private final String raceColumnName;
|
||||
|
||||
public SimpleFilterableRace(RaceGroup raceGroup, SeriesBase series, Fleet fleet, int zeroBasedIndexInFleet,
|
||||
int zeroBasedSeriesIndex, String raceColumnName) {
|
||||
super();
|
||||
this.raceGroup = raceGroup;
|
||||
this.series = series;
|
||||
this.fleet = fleet;
|
||||
this.zeroBasedIndexInFleet = zeroBasedIndexInFleet;
|
||||
this.zeroBasedSeriesIndex = zeroBasedSeriesIndex;
|
||||
this.raceColumnName = raceColumnName;
|
||||
this.status = RaceLogRaceStatus.UNSCHEDULED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceGroup getRaceGroup() {
|
||||
return raceGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeriesBase getSeries() {
|
||||
return series;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fleet getFleet() {
|
||||
return fleet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceLogRaceStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(RaceLogRaceStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZeroBasedIndexInFleet() {
|
||||
return zeroBasedIndexInFleet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZeroBasedSeriesIndex() {
|
||||
return zeroBasedSeriesIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRaceColumnName() {
|
||||
return raceColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimpleFilterableRace ["+getRaceGroup().getName() + " - " + getSeries().getName() + " - " +
|
||||
getFleet().getName() + " - " + getRaceColumnName() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class DependentStartTimeFinderTest {
|
||||
expectedDependingOnRaces.add(new SimpleRaceLogIdentifierImpl("A", "", ""));
|
||||
assertNull(result.getStartTime());
|
||||
assertEquals(bAfterA, result.getStartTimeDiff());
|
||||
assertEquals(expectedDependingOnRaces, result.getRacesDependingOn());
|
||||
assertEquals(expectedDependingOnRaces, result.getDependingOnRaces());
|
||||
// assertEquals(5000, result.getStartTimeDiff().asMillis());
|
||||
|
||||
finder = new StartTimeFinder(raceLogResolver, raceLogC);
|
||||
@@ -96,7 +96,7 @@ public class DependentStartTimeFinderTest {
|
||||
result = finder.analyze();
|
||||
assertNull(result.getStartTime());
|
||||
assertEquals(cAfterB, result.getStartTimeDiff());
|
||||
assertEquals(expectedDependingOnRaces, result.getRacesDependingOn());
|
||||
assertEquals(expectedDependingOnRaces, result.getDependingOnRaces());
|
||||
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
raceLogA.add(new RaceLogStartTimeEventImpl(now, now, author, "12", 12, new MillisecondsTimePoint(5000),
|
||||
@@ -175,7 +175,7 @@ public class DependentStartTimeFinderTest {
|
||||
StartTimeFinderResult result = finder.analyze();
|
||||
assertEquals(19000, result.getStartTime().asMillis());
|
||||
assertEquals(8000, result.getStartTimeDiff().asMillis());
|
||||
assertEquals(expectedDependingOnRaces, result.getRacesDependingOn());
|
||||
assertEquals(expectedDependingOnRaces, result.getDependingOnRaces());
|
||||
|
||||
// now C -> B
|
||||
finder = new StartTimeFinder(raceLogResolver, raceLogC);
|
||||
@@ -187,7 +187,7 @@ public class DependentStartTimeFinderTest {
|
||||
result = finder.analyze();
|
||||
assertEquals(11000, result.getStartTime().asMillis());
|
||||
assertEquals(6000, result.getStartTimeDiff().asMillis());
|
||||
assertEquals(expectedDependingOnRaces, result.getRacesDependingOn());
|
||||
assertEquals(expectedDependingOnRaces, result.getDependingOnRaces());
|
||||
|
||||
// now B
|
||||
finder = new StartTimeFinder(raceLogResolver, raceLogB);
|
||||
@@ -198,6 +198,6 @@ public class DependentStartTimeFinderTest {
|
||||
result = finder.analyze();
|
||||
assertEquals(5000, result.getStartTime().asMillis());
|
||||
assertNull(result.getStartTimeDiff());
|
||||
assertEquals(expectedDependingOnRaces, result.getRacesDependingOn());
|
||||
assertEquals(expectedDependingOnRaces, result.getDependingOnRaces());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
|
||||
import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration;
|
||||
import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl;
|
||||
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration;
|
||||
import com.sap.sailing.domain.common.CourseDesignerMode;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
|
||||
@@ -177,7 +178,7 @@ public class RaceStateTest {
|
||||
state.forceNewStartTime(nowMock, new MillisecondsTimePoint(1));
|
||||
Thread.sleep(100);
|
||||
state.setFinishedTime(new MillisecondsTimePoint(10));
|
||||
state.setCourseDesign(nowMock, mock(CourseBase.class));
|
||||
state.setCourseDesign(nowMock, mock(CourseBase.class), CourseDesignerMode.ADMIN_CONSOLE);
|
||||
|
||||
state.setAdvancePass(mock(TimePoint.class));
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class CompetitorDeregistrationTest extends AbstractRegattaLogTrackingTest {
|
||||
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null);
|
||||
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
|
||||
|
||||
@Test
|
||||
public void testCompetitorDeregistration() {
|
||||
|
||||