diff --git a/configuration/downloadNewArchivedTracTracEvents.sh b/configuration/downloadNewArchivedTracTracEvents.sh
new file mode 100755
index 00000000000..16c762b5848
--- /dev/null
+++ b/configuration/downloadNewArchivedTracTracEvents.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+GIT_ROOT=/home/wiki/gitwiki
+# Downloads all TracTrac event data based on ${GIT_ROOT}/configuration/tractrac-json-urls
+# into the target directory (specified as $1) for those event URLs whose specific folder
+# does not yet exist in the target directory.
+TARGET_DIR="${1}"
+JSON_URLS_FILE="${GIT_ROOT}/configuration/tractrac-json-urls"
+for i in `cat "${JSON_URLS_FILE}"`; do
+ EVENT_DB="$( basename $( dirname ${i} ) )"
+ if [ -d "${TARGET_DIR}/${EVENT_DB}" ]; then
+ echo "Directory for event ${EVENT_DB} already found. Not downloading again. Use"
+ echo " ${GIT_ROOT}/configuration/downloadTracTracEvent ${i} ${TARGET_DIR}"
+ echo "to force an update."
+ else
+ echo "Did not find directory for event ${EVENT_DB} yet in ${TARGET_DIR}. Downloading..."
+ ${GIT_ROOT}/configuration/downloadTracTracEvent "${i}" "${TARGET_DIR}"
+ fi
+done
diff --git a/configuration/downloadTracTracEvent b/configuration/downloadTracTracEvent
new file mode 100755
index 00000000000..ca746626ca2
--- /dev/null
+++ b/configuration/downloadTracTracEvent
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Example usage:
+# ./downloadTracTracEvent https://event.tractrac.com/events/event_20150625_KielerWoch/jsonservice.php /tmp/KielerWoche2015
+#
+# To obtain the set of TracTrac JSON URLs currently in use by the archive, on
+# dbserver.internal.sapsailing.com try this:
+# mongo --quiet "mongodb://dbserver.internal.sapsailing.com:10201/winddb?replicaSet=archive" --eval 'db.TRACTRAC_CONFIGURATIONS.find({}, {TT_CONFIG_JSON_URL : 1}).toArray()' | grep -v ObjectId | jq -r '.[].TT_CONFIG_JSON_URL' | sort -u >/tmp/tractrac-json-urls
+# and then:
+# for i in `cat /tmp/tractrac-json-urls`; do ./downloadTracTracEvent $i /tmp/tractrac-tracks; done
+# and you will get a folder per event under /tmp/tractrac-tracks with all .mtb and .txt files as well
+# as the .json file in them.
+EVENT_JSON_URL="${1}"
+EVENT_DB="$( basename $( dirname ${EVENT_JSON_URL} ) )"
+TARGET_DIR="${2}/${EVENT_DB}"
+if [ ! -d "${TARGET_DIR}" ]; then
+ echo "${TARGET_DIR} does not exist; making it..."
+ mkdir -p "${TARGET_DIR}"
+fi
+pushd "${TARGET_DIR}"
+# create a patched version of the .json file that uses only relative params_url values:
+wget -O - "${EVENT_JSON_URL}" | sed -e 's/"params_url":"[^"]*\/\([^"/]*\.txt\)"/"params_url":"\1"/g' >"${EVENT_DB}.json"
+for params_url in `wget -O - "${EVENT_JSON_URL}" | jq -r '.races[].params_url'`; do
+ echo ${params_url}
+ wget "${params_url}"
+ FILE="`basename ${params_url}`"
+ STORED_URI_PART=`grep -i ^stored-uri: "${FILE}" | head -1 | sed -e 's/^stored-uri://'`
+ STORED_URI="`dirname ${EVENT_JSON_URL}`/${STORED_URI_PART}"
+ echo "stored-uri: ${STORED_URI}"
+ # presumably the dirname of the stored URI is something like "datafiles"
+ mkdir -p `dirname ${STORED_URI_PART}`
+ wget -O "${STORED_URI_PART}" "${STORED_URI}"
+done
+popd
diff --git a/configuration/tractrac-json-urls b/configuration/tractrac-json-urls
new file mode 100644
index 00000000000..f7f6d7d43b9
--- /dev/null
+++ b/configuration/tractrac-json-urls
@@ -0,0 +1,496 @@
+http://club.tractrac.com/events/event_20160616_KielerWoch1/jsonservice.php
+http://club.tractrac.com/events/event_20160616_KielerWoch/jsonservice.php
+http://club.tractrac.com/events/event_20160622_KielerWoch/jsonservice.php
+http://club.tractrac.com/events/event_20160721_Travemnder/jsonservice.php
+http://club.tractrac.com/events/event_20160722_Bundesliga/jsonservice.php
+http://club.tractrac.com/events/event_20170616_KielerWoch/jsonservice.php
+http://club.tractrac.com/events/event_20170621_KielerWoch/jsonservice.php
+http://club.tractrac.com/events/event_20170729_Travemnder/jsonservice.php
+http://club.tractrac.com/events/event_20180615_KielerWoch/jsonservice.php
+http://club.tractrac.com/events/event_20180719_Travemnder/jsonservice.php
+http://club.tractrac.com/events/event_20180731_SailingWor/jsonservice.php
+http://event2.tractrac.com/events/event_20161207_ESSAustral/jsonservice.php
+http://event2.tractrac.com/events/event_20170307_ESSMuscat/jsonservice.php
+http://event2.tractrac.com/events/event_20170427_ESSQingdao/jsonservice.php
+http://event2.tractrac.com/events/event_20170628_ESSMadeira/jsonservice.php
+http://event2.tractrac.com/events/event_20170719_ESSEurope/jsonservice.php
+http://event2.tractrac.com/events/event_20170720_Travemnder/jsonservice.php
+http://event2.tractrac.com/events/event_20170809_ESSHamburg/jsonservice.php
+http://event2.tractrac.com/events/event_20170824_ESSCardiff/jsonservice.php
+http://event2.tractrac.com/events/event_20171018_ESSSanDieg/jsonservice.php
+http://event2.tractrac.com/events/event_20180312_ESSMuscat/jsonservice.php
+http://event2.tractrac.com/events/event_20180523_ESSRivadel/jsonservice.php
+http://event2.tractrac.com/events/event_20180613_ESSBarcelo/jsonservice.php
+http://event2.tractrac.com/events/event_20180703_ESSCascais/jsonservice.php
+http://event2.tractrac.com/events/event_20180822_ESSCardiff/jsonservice.php
+http://event.tractrac.com/events/event_20140619_KieleWoche/jsonservice.php
+http://event.tractrac.com/events/event_20150323_Worlds/jsonservice.php
+http://event.tractrac.com/events/event_20150415_SAPOptiCup/jsonservice.php
+http://event.tractrac.com/events/event_20150423_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150426_Segelbunde/jsonservice.php
+http://event.tractrac.com/events/event_20150428_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150514_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150519_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20150523_YES/jsonservice.php
+http://event.tractrac.com/events/event_20150528_Bodenseewo/jsonservice.php
+http://event.tractrac.com/events/event_20150530_RosAtomCup/jsonservice.php
+http://event.tractrac.com/events/event_20150603_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150612_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150616_KielerWoch/jsonservice.php
+http://event.tractrac.com/events/event_20150619_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150625_KielerWoch/jsonservice.php
+http://event.tractrac.com/events/event_20150701_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150703_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150707_erEuropean/jsonservice.php
+http://event.tractrac.com/events/event_20150709_sterreichi/jsonservice.php
+http://event.tractrac.com/events/event_20150716_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150717_Travemnder/jsonservice.php
+http://event.tractrac.com/events/event_20150814_Allsvenska1/jsonservice.php
+http://event.tractrac.com/events/event_20150818_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150818_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150818_SuomenPurj/jsonservice.php
+http://event.tractrac.com/events/event_20150819_sterreichi/jsonservice.php
+http://event.tractrac.com/events/event_20150820_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150824_erYouthWor/jsonservice.php
+http://event.tractrac.com/events/event_20150827_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150828_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20150912_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150917_NorskSeils/jsonservice.php
+http://event.tractrac.com/events/event_20150918_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20150924_AudiBusine1/jsonservice.php
+http://event.tractrac.com/events/event_20150924_NorskSeils/jsonservice.php
+http://event.tractrac.com/events/event_20150925_Bundesliga1/jsonservice.php
+http://event.tractrac.com/events/event_20150925_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20150925_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20150925_WindsurfWo/jsonservice.php
+http://event.tractrac.com/events/event_20150926_SuomenPurj/jsonservice.php
+http://event.tractrac.com/events/event_20150928_CopyofDutc/jsonservice.php
+http://event.tractrac.com/events/event_20150928_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20151004_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20151008_MesternesM/jsonservice.php
+http://event.tractrac.com/events/event_20151009_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20151009_SuomenPurj/jsonservice.php
+http://event.tractrac.com/events/event_20151016_MstarnasMs/jsonservice.php
+http://event.tractrac.com/events/event_20151029_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20151116_erWorldCha/jsonservice.php
+http://event.tractrac.com/events/event_20160128_erWorlds/jsonservice.php
+http://event.tractrac.com/events/event_20160324_ererFXatTr/jsonservice.php
+http://event.tractrac.com/events/event_20160401_Charleston/jsonservice.php
+http://event.tractrac.com/events/event_20160410_erEuropean/jsonservice.php
+http://event.tractrac.com/events/event_20160427_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160501_Bundesliga1/jsonservice.php
+http://event.tractrac.com/events/event_20160511_WMRTStageC/jsonservice.php
+http://event.tractrac.com/events/event_20160513_Sejlsports1/jsonservice.php
+http://event.tractrac.com/events/event_20160519_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20160519_FinnishLea/jsonservice.php
+http://event.tractrac.com/events/event_20160519_NorskSeils/jsonservice.php
+http://event.tractrac.com/events/event_20160519_Sejlsports/jsonservice.php
+http://event.tractrac.com/events/event_20160526_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160526_RosAtomCup/jsonservice.php
+http://event.tractrac.com/events/event_20160527_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160604_GrundigSai/jsonservice.php
+http://event.tractrac.com/events/event_20160604_JuniorenSe/jsonservice.php
+http://event.tractrac.com/events/event_20160609_Regattaste/jsonservice.php
+http://event.tractrac.com/events/event_20160609_SwedishLea/jsonservice.php
+http://event.tractrac.com/events/event_20160610_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160610_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20160616_FrenchSail/jsonservice.php
+http://event.tractrac.com/events/event_20160617_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20160617_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160618_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160623_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160624_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20160626_USOptimist/jsonservice.php
+http://event.tractrac.com/events/event_20160701_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20160701_JuniorenSe_1467364143/jsonservice.php
+http://event.tractrac.com/events/event_20160701_WMRTMarstr/jsonservice.php
+http://event.tractrac.com/events/event_20160723_erWorlds/jsonservice.php
+http://event.tractrac.com/events/event_20160730_Worlds/jsonservice.php
+http://event.tractrac.com/events/event_20160806_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20160806_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20160812_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160812_SwedishLea/jsonservice.php
+http://event.tractrac.com/events/event_20160818_AudiBusine/jsonservice.php
+http://event.tractrac.com/events/event_20160818_Bundesliga1/jsonservice.php
+http://event.tractrac.com/events/event_20160818_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160819_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160820_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160820_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20160825_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20160826_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160826_JuniorenSe/jsonservice.php
+http://event.tractrac.com/events/event_20160830_EasternEco/jsonservice.php
+http://event.tractrac.com/events/event_20160902_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160902_SwedishLea/jsonservice.php
+http://event.tractrac.com/events/event_20160907_VanProSumm/jsonservice.php
+http://event.tractrac.com/events/event_20160909_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20160909_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20160909_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20160910_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160915_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160916_AudiIDMSta/jsonservice.php
+http://event.tractrac.com/events/event_20160916_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20160916_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20160918_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20160922_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20160923_JuniorenSe/jsonservice.php
+http://event.tractrac.com/events/event_20161006_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20161007_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20161009_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20161013_MesternesM/jsonservice.php
+http://event.tractrac.com/events/event_20161014_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20161014_MstarnasMs/jsonservice.php
+http://event.tractrac.com/events/event_20161028_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20161202_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20170122_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20170420_WorldCupSe/jsonservice.php
+http://event.tractrac.com/events/event_20170426_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20170510_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20170511_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20170512_NorwegianL1/jsonservice.php
+http://event.tractrac.com/events/event_20170512_NorwegianL/jsonservice.php
+http://event.tractrac.com/events/event_20170517_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20170518_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170524_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20170525_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170606_FrenchSail/jsonservice.php
+http://event.tractrac.com/events/event_20170608_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20170608_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20170616_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20170616_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170617_CopyofNorw1/jsonservice.php
+http://event.tractrac.com/events/event_20170623_DanishLeag1/jsonservice.php
+http://event.tractrac.com/events/event_20170624_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20170628_SegelBunde/jsonservice.php
+http://event.tractrac.com/events/event_20170629_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20170630_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20170707_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20170720_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20170720_SegelBunde/jsonservice.php
+http://event.tractrac.com/events/event_20170727_NorwegianL1/jsonservice.php
+http://event.tractrac.com/events/event_20170728_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20170729_erEuropean/jsonservice.php
+http://event.tractrac.com/events/event_20170801_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20170801_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20170803_CopyofNorw/jsonservice.php
+http://event.tractrac.com/events/event_20170804_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20170810_CopyofNorw/jsonservice.php
+http://event.tractrac.com/events/event_20170813_MeterWorld/jsonservice.php
+http://event.tractrac.com/events/event_20170817_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20170817_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20170817_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20170817_SegelBunde/jsonservice.php
+http://event.tractrac.com/events/event_20170821_IDMFinn/jsonservice.php
+http://event.tractrac.com/events/event_20170824_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20170825_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170830_Internatio/jsonservice.php
+http://event.tractrac.com/events/event_20170831_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20170831_SAPExpiere/jsonservice.php
+http://event.tractrac.com/events/event_20170901_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170901_DutchSaili1/jsonservice.php
+http://event.tractrac.com/events/event_20170907_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20170908_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20170908_CopyofNorw/jsonservice.php
+http://event.tractrac.com/events/event_20170908_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170908_NorwegianL1/jsonservice.php
+http://event.tractrac.com/events/event_20170908_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20170914_ADHTrophyM/jsonservice.php
+http://event.tractrac.com/events/event_20170915_ADHTrophyU/jsonservice.php
+http://event.tractrac.com/events/event_20170915_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20170915_DanishLeag/jsonservice.php
+http://event.tractrac.com/events/event_20170920_SAPWorldCh/jsonservice.php
+http://event.tractrac.com/events/event_20170921_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20171005_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20171006_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20171012_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20171013_DSLPokalGl/jsonservice.php
+http://event.tractrac.com/events/event_20171014_MstarnasMs/jsonservice.php
+http://event.tractrac.com/events/event_20171019_Allsvenska/jsonservice.php
+http://event.tractrac.com/events/event_20171101_Bundesliga/jsonservice.php
+http://event.tractrac.com/events/event_20171130_ESSLosCabo/jsonservice.php
+http://event.tractrac.com/events/event_20180116_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20180322_FrenchSail/jsonservice.php
+http://event.tractrac.com/events/event_20180412_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180421_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20180426_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180517_SwedishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180525_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180525_NorwegianS/jsonservice.php
+http://event.tractrac.com/events/event_20180530_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20180531_DanishSail1/jsonservice.php
+http://event.tractrac.com/events/event_20180531_NorwegianS/jsonservice.php
+http://event.tractrac.com/events/event_20180601_SwedishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180602_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20180606_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180607_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20180607_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20180614_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180615_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180615_NordStream/jsonservice.php
+http://event.tractrac.com/events/event_20180623_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180628_FrenchSail/jsonservice.php
+http://event.tractrac.com/events/event_20180706_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20180712_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20180713_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180717_Worlds/jsonservice.php
+http://event.tractrac.com/events/event_20180720_Eliteserie1/jsonservice.php
+http://event.tractrac.com/events/event_20180720_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180720_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180720_SAPSailing/jsonservice.php
+http://event.tractrac.com/events/event_20180721_CopyofNorw1/jsonservice.php
+http://event.tractrac.com/events/event_20180721_CopyofNorw2/jsonservice.php
+http://event.tractrac.com/events/event_20180726_YouthChamp/jsonservice.php
+http://event.tractrac.com/events/event_20180727_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180801_FinnishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180803_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20180807_NorwegianS/jsonservice.php
+http://event.tractrac.com/events/event_20180817_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180818_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180823_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20180823_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180823_SwedishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180824_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180829_SailingCha/jsonservice.php
+http://event.tractrac.com/events/event_20180831_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20180901_DanishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180906_SwedishSai/jsonservice.php
+http://event.tractrac.com/events/event_20180907_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20180907_DanishSail1/jsonservice.php
+http://event.tractrac.com/events/event_20180907_Eliteserie/jsonservice.php
+http://event.tractrac.com/events/event_20180907_NorwegianS/jsonservice.php
+http://event.tractrac.com/events/event_20180907_PolishSail/jsonservice.php
+http://event.tractrac.com/events/event_20180912_SailingWor/jsonservice.php
+http://event.tractrac.com/events/event_20180914_GermanSail/jsonservice.php
+http://event.tractrac.com/events/event_20180921_DutchSaili/jsonservice.php
+http://event.tractrac.com/events/event_20181019_AustrianSa/jsonservice.php
+http://event.tractrac.com/events/event_20181019_FrenchSail/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20100725_OWorlds/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20110308_SAPWorldCh/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20110505_SailingTea/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20110609_KielerWoch/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20110815_RCSwedenCu/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20110929_Internatio/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120101_ExtremeSai/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120314_ArenalTrai/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120501_SailingTea/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120525_YES/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120615_KielerWoch1/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120615_KielerWoch/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120621_KielerWoch1/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120621_KielerWoch/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20120714_SAPWorldCh/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20121031_OBMR/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130220_HawaiiWinn/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130311_Palma/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130404_Barbadosen/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130607_DeutscheLi/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130918_eranderFXW/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20130926_DeutscheSe/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20131105_DeutscheSe/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140514_DeutscheSe/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140730_RoyalHongK/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140821_DeutscheSe/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140904_CopyofBund/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140918_VulcainTro/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140919_BartsBash/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140925_Bundesliga1/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20140925_Bundesliga/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20141016_SailingCha/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20141022_Blubber/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20141107_Bundesliga/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20150310_Palmatrain/jsonservice.php
+http://germanmaster.traclive.dk/events/event_20150929_mRIDM/jsonservice.php
+http://kml.skitrac.traclive.dk/events/event_20120730_IDMDrachen/jsonservice.php
+http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php
+http://premium.event.tractrac.com/events/event_20170603_SailingWor/jsonservice.php
+https://club.tractrac.com/events/event_20150625_KielerWoch2/jsonservice.php
+https://club.tractrac.com/events/event_20181017_ESSSanDieg/jsonservice.php
+https://club.tractrac.com/events/event_20181129_ESSLosCabo/jsonservice.php
+https://club.tractrac.com/events/event_20200901_KielerWoch1/jsonservice.php
+https://club.tractrac.com/events/event_20200910_KielerWoch/jsonservice.php
+https://club.tractrac.com/events/event_20200914_ererFXNacr/jsonservice.php
+https://club.tractrac.com/events/event_20210902_KielerWoch/jsonservice.php
+http://secondary.traclive.dk/events/event_20130621_KielerWoch/jsonservice.php
+http://secondary.traclive.dk/events/event_20130626_KielerWoch/jsonservice.php
+http://secondary.traclive.dk/events/event_20130627_KielerWoch/jsonservice.php
+http://secondary.traclive.dk/events/event_20130703_erEuropean/jsonservice.php
+http://secondary.traclive.dk/events/event_20130706_MiniPacifi/jsonservice.php
+http://secondary.traclive.dk/events/event_20130711_Travemuend/jsonservice.php
+http://secondary.traclive.dk/events/event_20130719_DeutscheSe/jsonservice.php
+http://secondary.traclive.dk/events/event_20130724_ESSPorto/jsonservice.php
+http://secondary.traclive.dk/events/event_20130822_ESSCardiff/jsonservice.php
+http://secondary.traclive.dk/events/event_20131002_ESSNice/jsonservice.php
+http://secondary.traclive.dk/events/event_20140218_ESSSingapo/jsonservice.php
+http://secondary.traclive.dk/events/event_20140318_ESSMuscat/jsonservice.php
+http://secondary.traclive.dk/events/event_20140429_ESSQingdao/jsonservice.php
+http://secondary.traclive.dk/events/event_20140528_Sejlsports/jsonservice.php
+http://secondary.traclive.dk/events/event_20140603_YES/jsonservice.php
+http://secondary.traclive.dk/events/event_20140613_Sejlsports/jsonservice.php
+http://secondary.traclive.dk/events/event_20140619_KieleWoche/jsonservice.php
+http://secondary.traclive.dk/events/event_20140625_ESSSaintPe/jsonservice.php
+http://secondary.traclive.dk/events/event_20140625_KielerWoch/jsonservice.php
+http://secondary.traclive.dk/events/event_20140626_KieleWoche/jsonservice.php
+http://secondary.traclive.dk/events/event_20140715_DeutscheSe/jsonservice.php
+http://secondary.traclive.dk/events/event_20140715_Travemunde/jsonservice.php
+http://secondary.traclive.dk/events/event_20140813_Worlds/jsonservice.php
+https://event2.tractrac.com/events/event_20190813_Olympictes/jsonservice.php
+https://event3.tractrac.com/events/event_20220403_TrofeoPrin/jsonservice.php
+https://event3.tractrac.com/events/event_20220428_JOCJuniorO/jsonservice.php
+https://event3.tractrac.com/events/event_20220429_KornatiCup/jsonservice.php
+https://event3.tractrac.com/events/event_20220501_NorwegianS/jsonservice.php
+https://event3.tractrac.com/events/event_20220503_Batterites/jsonservice.php
+https://event3.tractrac.com/events/event_20220512_Allsvenska_event3/jsonservice.php
+https://event3.tractrac.com/events/event_20220512_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220515_UNDSEGELBU/jsonservice.php
+https://event3.tractrac.com/events/event_20220520_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220525_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220527_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220528_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220530_AllianzReg1/jsonservice.php
+https://event3.tractrac.com/events/event_20220604_SailingCha/jsonservice.php
+https://event3.tractrac.com/events/event_20220608_HelgaCup/jsonservice.php
+https://event3.tractrac.com/events/event_20220617_KielerWoch/jsonservice.php
+https://event3.tractrac.com/events/event_20220617_NorwegianS/jsonservice.php
+https://event3.tractrac.com/events/event_20220617_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220617_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220618_NorwegianS/jsonservice.php
+https://event3.tractrac.com/events/event_20220621_CopyofKiel/jsonservice.php
+https://event3.tractrac.com/events/event_20220624_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220707_YouthSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220714_SegelBunde/jsonservice.php
+https://event3.tractrac.com/events/event_20220715_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220728_CopyofSege/jsonservice.php
+https://event3.tractrac.com/events/event_20220811_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220816_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220817_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220818_FinnishSai/jsonservice.php
+https://event3.tractrac.com/events/event_20220826_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220826_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220830_erWorlds/jsonservice.php
+https://event3.tractrac.com/events/event_20220902_Sejlsports/jsonservice.php
+https://event3.tractrac.com/events/event_20220902_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220903_FinnishSai/jsonservice.php
+https://event3.tractrac.com/events/event_20220907_LigueNatio/jsonservice.php
+https://event3.tractrac.com/events/event_20220908_SegelBunde/jsonservice.php
+https://event3.tractrac.com/events/event_20220908_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220910_FinnishSai/jsonservice.php
+https://event3.tractrac.com/events/event_20220915_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220916_SUNDBYWOWS/jsonservice.php
+https://event3.tractrac.com/events/event_20220922_FinnishSai/jsonservice.php
+https://event3.tractrac.com/events/event_20220923_NorwegianS/jsonservice.php
+https://event3.tractrac.com/events/event_20220923_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220923_XYachtsSta/jsonservice.php
+https://event3.tractrac.com/events/event_20220929_SegelBunde/jsonservice.php
+https://event3.tractrac.com/events/event_20220929_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20220930_NorwegianS/jsonservice.php
+https://event3.tractrac.com/events/event_20221006_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20221012_SegelBunde/jsonservice.php
+https://event3.tractrac.com/events/event_20221013_MesternesM/jsonservice.php
+https://event3.tractrac.com/events/event_20221014_SwissSaili/jsonservice.php
+https://event3.tractrac.com/events/event_20221104_DSLPokal/jsonservice.php
+https://event.tractrac.com/events/event_20170727_Travemnder2/jsonservice.php
+https://event.tractrac.com/events/event_20171013_DSLPokalGl/jsonservice.php
+https://event.tractrac.com/events/event_20181012_MstarnasMs/jsonservice.php
+https://event.tractrac.com/events/event_20181018_GermanSail/jsonservice.php
+https://event.tractrac.com/events/event_20181108_RedBullFoi/jsonservice.php
+https://event.tractrac.com/events/event_20181212_WorldsFrem/jsonservice.php
+ https://event.tractrac.com/events/event_20190126_SailingWor/jsonservice.php
+https://event.tractrac.com/events/event_20190412_SailingWor/jsonservice.php
+https://event.tractrac.com/events/event_20190425_KornatiCup/jsonservice.php
+https://event.tractrac.com/events/event_20190520_MedemblikR/jsonservice.php
+https://event.tractrac.com/events/event_20190526_SailingWor/jsonservice.php
+https://event.tractrac.com/events/event_20190613_HelgaCup/jsonservice.php
+https://event.tractrac.com/events/event_20190621_KielerWoch/jsonservice.php
+https://event.tractrac.com/events/event_20190621_NordStream/jsonservice.php
+https://event.tractrac.com/events/event_20190626_KielerWoch/jsonservice.php
+https://event.tractrac.com/events/event_20190825_SailingWor/jsonservice.php
+https://event.tractrac.com/events/event_20190912_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20190912_FrenchSail/jsonservice.php
+https://event.tractrac.com/events/event_20190920_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20191010_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20191011_CroatiaCoa/jsonservice.php
+https://event.tractrac.com/events/event_20191017_FrenchSail/jsonservice.php
+https://event.tractrac.com/events/event_20191024_AlandiaNor1/jsonservice.php
+https://event.tractrac.com/events/event_20191024_Bermuda/jsonservice.php
+https://event.tractrac.com/events/event_20191125_erNacraOce/jsonservice.php
+https://event.tractrac.com/events/event_20191128_erNacraWor/jsonservice.php
+https://event.tractrac.com/events/event_20200119_SailingWor/jsonservice.php
+https://event.tractrac.com/events/event_20200205_ererFXNacr/jsonservice.php
+https://event.tractrac.com/events/event_20200807_DivSejlspo/jsonservice.php
+https://event.tractrac.com/events/event_20200813_SwedishSLA/jsonservice.php
+https://event.tractrac.com/events/event_20200814_DivSejlspo/jsonservice.php
+https://event.tractrac.com/events/event_20200821_Ungdomslig/jsonservice.php
+https://event.tractrac.com/events/event_20200828_DivSejlspo/jsonservice.php
+https://event.tractrac.com/events/event_20200903_SwedishSLA/jsonservice.php
+https://event.tractrac.com/events/event_20200904_DivSejlspo/jsonservice.php
+https://event.tractrac.com/events/event_20200911_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20200918_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20201001_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20201002_SwedishSLQ/jsonservice.php
+https://event.tractrac.com/events/event_20201009_SwedishSLM/jsonservice.php
+https://event.tractrac.com/events/event_20210401_Charleston/jsonservice.php
+https://event.tractrac.com/events/event_20210510_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210512_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210526_MedemblikR/jsonservice.php
+https://event.tractrac.com/events/event_20210602_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210607_LNVoileNan/jsonservice.php
+https://event.tractrac.com/events/event_20210609_Allsvenska/jsonservice.php
+https://event.tractrac.com/events/event_20210616_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210707_NorskSeils/jsonservice.php
+https://event.tractrac.com/events/event_20210719_Tokyosaili/jsonservice.php
+https://event.tractrac.com/events/event_20210811_NorskSeils/jsonservice.php
+https://event.tractrac.com/events/event_20210811_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210815_Allsvenska/jsonservice.php
+https://event.tractrac.com/events/event_20210818_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210819_FinnishSai1/jsonservice.php
+https://event.tractrac.com/events/event_20210825_NASTROROSA/jsonservice.php
+https://event.tractrac.com/events/event_20210825_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210826_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20210831_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20210901_Sejlsports/jsonservice.php
+https://event.tractrac.com/events/event_20210906_LNVoileMar/jsonservice.php
+https://event.tractrac.com/events/event_20210908_NorskSeils/jsonservice.php
+https://event.tractrac.com/events/event_20210913_Allsvenska/jsonservice.php
+https://event.tractrac.com/events/event_20210915_WOWSundby/jsonservice.php
+https://event.tractrac.com/events/event_20210922_QualifierA/jsonservice.php
+https://event.tractrac.com/events/event_20210923_SpecialXYa/jsonservice.php
+https://event.tractrac.com/events/event_20210929_NorskSeils/jsonservice.php
+https://event.tractrac.com/events/event_20210930_SwedishSLM/jsonservice.php
+https://event.tractrac.com/events/event_20211001_FinnishSai/jsonservice.php
+https://event.tractrac.com/events/event_20211014_MesternesM/jsonservice.php
+https://event.tractrac.com/events/event_20211017_KornatiCup/jsonservice.php
+https://event.tractrac.com/events/event_20211115_ererFxNacr/jsonservice.php
+https://event.tractrac.com/events/event_20211210_YouthSaili/jsonservice.php
+https://event.tractrac.com/events/event_20220626_KielerWoch/jsonservice.php
+https://event.tractrac.com/events/event_20230531_ERERFXNACR/jsonservice.php
+http://skitrac.traclive.dk/events/event_20140821_ESSCardiff/jsonservice.php
+http://skitrac.traclive.dk/events/event_20140909_ESSIstanbu/jsonservice.php
+http://skitrac.traclive.dk/events/event_20141001_ESSNice/jsonservice.php
+http://skitrac.traclive.dk/events/event_20141210_ESSSydney/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150204_ESSSingapo/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150310_ESSMuscat/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150428_ESSQingdao/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150617_ESSCardiff/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150722_ESSHamburg/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150819_ESSSaintPe/jsonservice.php
+http://skitrac.traclive.dk/events/event_20150928_ESSIstanbu/jsonservice.php
+http://skitrac.traclive.dk/events/event_20151207_ESSSydney/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160222_ESSSTPeter/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160315_ESSMuscat/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160428_ESSQingdao/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160622_ESSCardiff/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160727_ESSHamburg/jsonservice.php
+http://skitrac.traclive.dk/events/event_20160921_ESSInstanb/jsonservice.php
+http://skitrac.traclive.dk/events/event_20161005_ESSLisbon/jsonservice.php
+http://traclive.dk/events/event_20120905_erEuropean/jsonservice.php
+http://traclive.dk/events/event_20130302_ESSMuscat/jsonservice.php
+http://traclive.dk/events/event_20130401_STGTrainin/jsonservice.php
+http://traclive.dk/events/event_20130405_ESSSingapo/jsonservice.php
+http://traclive.dk/events/event_20130424_IDMStarboo/jsonservice.php
+http://traclive.dk/events/event_20130429_ESSQingdao/jsonservice.php
+http://traclive.dk/events/event_20130917_IDMO/jsonservice.php
+http://traclive.dk/events/event_20131112_ESSFlorian/jsonservice.php
+http://traclive.dk/events/event_20140820_Sejlsports/jsonservice.php
+http://traclive.dk/events/event_20140904_Sejlsports/jsonservice.php
+http://traclive.dk/events/event_20140912_CopyofSejl/jsonservice.php
+http://traclive.dk/events/event_20141025_Sejlsports/jsonservice.php
diff --git a/configuration/update-tractrac-urls-to-archive.sh b/configuration/update-tractrac-urls-to-archive.sh
new file mode 100755
index 00000000000..10b43683d92
--- /dev/null
+++ b/configuration/update-tractrac-urls-to-archive.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+GIT_ROOT=/home/wiki/gitwiki
+mongo --quiet "mongodb://dbserver.internal.sapsailing.com:10201/winddb?replicaSet=archive" --eval 'db.TRACTRAC_CONFIGURATIONS.find({}, {TT_CONFIG_JSON_URL : 1}).toArray()' | grep -v ObjectId | jq -r '.[].TT_CONFIG_JSON_URL' | sort -u >"${GIT_ROOT}/configuration/tractrac-json-urls"
+cd "${GIT_ROOT}"
+git commit -m "Updated tractrac-json-urls" -a
+git push
diff --git a/docker/Dockerfile_windestimation b/docker/Dockerfile_windestimation
index b08e1ae3a6b..0804be1771a 100755
--- a/docker/Dockerfile_windestimation
+++ b/docker/Dockerfile_windestimation
@@ -13,4 +13,4 @@ RUN wget -O /tmp/rds.pem https://s3.amazonaws.com/rds-downloads/rds-combined-ca-
&& /opt/sapjvm_8/bin/keytool -importcert -alias AWSRDS -file /tmp/rds.pem -keystore /opt/sapjvm_8/jre/lib/security/cacerts -noprompt -storepass changeit \
&& rm /tmp/rds.pem
RUN wget -O /home/sailing/WindEstimationModelsTraining.jar https://static.sapsailing.com/WindEstimationModelsTraining.jar
-CMD exec java "${MEMORY}" -Dmongo.uri="${MONGODB_URI}" -jar WindEstimationModelsTraining.jar "${BEARER_TOKEN}" ${TRAINING_DATA_PERCENT}
+CMD exec java "${MEMORY}" -Dmongo.uri="${MONGODB_URI}" -XX:UseParallelGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=dump/ -Xlog:gc*=info,gc+region*=info,gc+ergo*=info,gc+humongous*=info,gc+liveness=trace:file=logs/gc.log:time,level,tags:filecount=10,filesize=100000000 -jar WindEstimationModelsTraining.jar "${BEARER_TOKEN}" ${TRAINING_DATA_PERCENT}
diff --git a/docker/Dockerfile_windestimation-on-sapmachine17 b/docker/Dockerfile_windestimation-on-sapmachine17
index 926c002c7f8..db340998fa6 100755
--- a/docker/Dockerfile_windestimation-on-sapmachine17
+++ b/docker/Dockerfile_windestimation-on-sapmachine17
@@ -2,7 +2,7 @@ FROM sapmachine:17.0.5
LABEL maintainer=axel.uhl@sap.com
# Download and extract the release
WORKDIR /home/sailing
-RUN chmod 777 /home/sailing; mkdir logs
+RUN chmod 777 /home/sailing; mkdir logs; mkdir dump
RUN apt-get -y update; apt-get -y upgrade; apt-get -y install apt-utils wget curl
RUN curl -fsSL https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add -
RUN echo "deb [arch=amd64,arm64] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" >/etc/apt/sources.list.d/mongodb-org-4.4.list
@@ -13,4 +13,4 @@ RUN wget -O /tmp/rds.pem https://s3.amazonaws.com/rds-downloads/rds-combined-ca-
&& ${JAVA_HOME}/bin/keytool -importcert -alias AWSRDS -file /tmp/rds.pem -keystore ${JAVA_HOME}/lib/security/cacerts -noprompt -storepass changeit \
&& rm /tmp/rds.pem
RUN wget -O /home/sailing/WindEstimationModelsTraining.jar https://static.sapsailing.com/WindEstimationModelsTraining.jar
-CMD exec java "${MEMORY}" -Dmongo.uri="${MONGODB_URI}" -Xlog:gc+ergo*=trace:file=logs/gc_ergo.log:time:filecount=10,filesize=100000000 -Xlog:gc*:file=logs/gc.log:time:filecount=10,filesize=100000000 -jar WindEstimationModelsTraining.jar "${BEARER_TOKEN}" ${TRAINING_DATA_PERCENT}
+CMD exec java "${MEMORY}" -Dmongo.uri="${MONGODB_URI}" -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=dump/ -Xlog:gc*=info,gc+region*=info,gc+ergo*=info,gc+humongous*=info,gc+liveness=trace:file=logs/gc.log:time,level,tags:filecount=10,filesize=100000000 -jar WindEstimationModelsTraining.jar "${BEARER_TOKEN}" ${TRAINING_DATA_PERCENT}
diff --git a/home.md b/home.md
index 5f141841ac8..b30e7b64ffc 100644
--- a/home.md
+++ b/home.md
@@ -122,6 +122,7 @@ SAP is at the center of today’s technology revolution, developing innovations
* [[Working with GWT Super Dev Mode|wiki/howto/development/super-dev-mode]]
* [[Training of internal Wind Estimation models|wiki/howto/windestimation]]
* [[Whitelabelling|wiki/howto/whitelabelling]]
+* [[Downloading and Archiving TracTrac Events|wiki/howto/downloading-and-archiving-tractrac-events]]
### For Event Managers
diff --git a/java/com.sap.sailing.domain.test/SailingDomainTest (No Proxy).launch b/java/com.sap.sailing.domain.test/SailingDomainTest (No Proxy).launch
index cb8f2927cb8..294036b6bd3 100644
--- a/java/com.sap.sailing.domain.test/SailingDomainTest (No Proxy).launch
+++ b/java/com.sap.sailing.domain.test/SailingDomainTest (No Proxy).launch
@@ -1,31 +1,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java
index b15a7a8cdad..71dad317dcd 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/NonCompetingCompetitorTest.java
@@ -32,7 +32,7 @@ public class NonCompetingCompetitorTest extends AbstractManeuverDetectionTestCas
public void setUp() throws Exception {
super.setUp();
super.setUp(
- new URL("http://skitrac.traclive.dk/events/event_20160222_ESSSTPeter/5a265e70-519a-0134-dd23-10b11c4ed8fd.txt"),
+ new URL("http://event2.tractrac.com/events/event_20160222_ESSSTPeter/5a265e70-519a-0134-dd23-10b11c4ed8fd.txt"),
/* liveUri */null, /* storedUri */null, new ReceiverType[] { ReceiverType.MARKPASSINGS,
ReceiverType.MARKPOSITIONS, ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS });
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java
index 73935338e97..3288d089366 100644
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RaceLogAttachOnTrackedRaceTest.java
@@ -2,8 +2,11 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.io.Serializable;
+import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
@@ -11,6 +14,7 @@ import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
+import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
@@ -41,6 +45,13 @@ public class RaceLogAttachOnTrackedRaceTest {
public RaceLog getRaceLog(Serializable identifier) {
return raceLog;
}
+
+ @Override
+ public RaceDefinition getRace() {
+ final RaceDefinition result = mock(RaceDefinition.class);
+ when(result.getCompetitors()).thenReturn(Collections.emptySet());
+ return result;
+ }
}
private FlexibleLeaderboard leaderboard;
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RegattaLogAttachOnTrackedRaceTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RegattaLogAttachOnTrackedRaceTest.java
index 93778a8a448..9e6b95fbb18 100644
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RegattaLogAttachOnTrackedRaceTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RegattaLogAttachOnTrackedRaceTest.java
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashMap;
@@ -15,6 +17,7 @@ import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
+import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
@@ -63,6 +66,13 @@ public class RegattaLogAttachOnTrackedRaceTest {
public Iterable getAttachedRegattaLogs() {
return Collections.singletonList(regattaLog);
}
+
+ @Override
+ public RaceDefinition getRace() {
+ final RaceDefinition result = mock(RaceDefinition.class);
+ when(result.getCompetitors()).thenReturn(Collections.emptySet());
+ return result;
+ }
}
private FlexibleLeaderboard leaderboard;
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java
index 755de191580..53e75f67283 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/tractrac/JorgesTracTracParallelLoadingTest.java
@@ -231,7 +231,7 @@ public class JorgesTracTracParallelLoadingTest {
@Test
public void logParallelLoading() throws CreateModelException, URISyntaxException, InterruptedException, IOException {
outputs = new ConcurrentHashMap<>();
- final String jsonUrl = "http://skitrac.traclive.dk/events/event_20160622_ESSCardiff/jsonservice.php";
+ final String jsonUrl = "http://event2.tractrac.com/events/event_20160622_ESSCardiff/jsonservice.php";
start(jsonUrl);
lock.await(60, TimeUnit.SECONDS);
Map firstRunsOutput = outputs;
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/RaceRecord.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/RaceRecord.java
index 7477bb0d74e..2bf27803280 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/RaceRecord.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/RaceRecord.java
@@ -101,7 +101,7 @@ public class RaceRecord {
paramURL = new URL(baseJsonURL + "/clientparams.php?event="
+ technicalEventName + "&race=" + ID);
} else {
- paramURL = new URL(paramURLAsString);
+ paramURL = new URL(jsonURL, paramURLAsString); // handle relative to JSON URL if not absolute
}
} catch (Exception e) {
logger.info("Couldn't parse TracTrac paramURL " + paramURLAsString + " for race record " + getName());
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java
index 5314fdb4876..73e7caf972f 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java
@@ -43,4 +43,7 @@ public interface RaceDefinition extends NamedWithID {
*/
byte[] getCompetitorMD5();
+ default boolean hasCompetitor(Competitor competitor) {
+ return getBoatOfCompetitor(competitor) != null;
+ }
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
index cb8e4e9379e..de22e2e634d 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
@@ -139,8 +139,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public synchronized void releaseTrackedRace(Fleet fleet) {
- TrackedRace previouslyLinkedRace = this.trackedRaces.get(fleet);
- this.trackedRaces.remove(fleet);
+ final TrackedRace previouslyLinkedRace = this.trackedRaces.remove(fleet);
if (previouslyLinkedRace != null && regattaLikeParent != null) {
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
previouslyLinkedRace.detachRaceLog(identifier.getIdentifier());
@@ -182,12 +181,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public TrackedRace getTrackedRace(Competitor competitor) {
- for (TrackedRace trackedRace : trackedRaces.values()) {
- if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
- return trackedRace;
- }
- }
- return null;
+ return trackedRaces.get(competitor);
}
@Override
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
index 38bdef5cb6d..8962d4c0366 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/CourseImpl.java
@@ -43,6 +43,8 @@ public class CourseImpl extends RenamableImpl implements Course {
private final List waypoints;
private final Map waypointIndexes;
+ private Waypoint firstWaypoint;
+ private Waypoint lastWaypoint;
private final List legs;
private UUID originatingCourseTemplateId;
private final Map associatedRoles;
@@ -68,13 +70,14 @@ public class CourseImpl extends RenamableImpl implements Course {
lock = new NamedReentrantReadWriteLock("lock for CourseImpl "+name,
/* fair */ true); // if non-fair, course update may need to wait forever for many concurrent readers
listeners = new HashSet();
- this.waypoints = new ArrayList();
- waypointIndexes = new HashMap();
+ this.waypoints = new ArrayList<>();
+ waypointIndexes = new HashMap<>();
legs = new ArrayList();
Iterator waypointIter = waypoints.iterator();
int i=0;
if (waypointIter.hasNext()) {
Waypoint previous = waypointIter.next();
+ firstWaypoint = previous;
this.waypoints.add(previous);
waypointIndexes.put(previous, i++);
while (waypointIter.hasNext()) {
@@ -86,6 +89,7 @@ public class CourseImpl extends RenamableImpl implements Course {
legs.add(leg);
previous = current;
}
+ lastWaypoint = previous;
}
assert this.waypoints.size() == waypointIndexes.size();
}
@@ -153,6 +157,12 @@ public class CourseImpl extends RenamableImpl implements Course {
if (waypoints.size() > 1) {
legs.add(new LegImpl(this, waypoints.size()-2));
}
+ if (zeroBasedPosition == 0) {
+ firstWaypoint = waypointToAdd;
+ }
+ if (zeroBasedPosition == waypoints.size()-1) {
+ lastWaypoint = waypointToAdd;
+ }
logger.info("Waypoint " + waypointToAdd + " added to course '" + getName() + "', before notifying listeners");
notifyListenersWaypointAdded(zeroBasedPosition, waypointToAdd);
logger.info("Waypoint " + waypointToAdd + " added to course '" + getName() + "', after notifying listeners");
@@ -184,6 +194,17 @@ public class CourseImpl extends RenamableImpl implements Course {
// last waypoint was removed; remove last leg
legs.remove(legs.size() - 1);
}
+ if (waypoints.isEmpty()) {
+ firstWaypoint = null;
+ lastWaypoint = null;
+ } else {
+ if (zeroBasedPosition == 0) {
+ firstWaypoint = waypoints.get(0);
+ }
+ if (zeroBasedPosition == waypoints.size()) {
+ lastWaypoint = waypoints.get(waypoints.size()-1);
+ }
+ }
logger.info("Waypoint " + removedWaypoint + " removed from course '" + getName() + "', before notifying listeners");
notifyListenersWaypointRemoved(zeroBasedPosition, removedWaypoint);
logger.info("Waypoint " + removedWaypoint + " removed from course '" + getName() + "', after notifying listeners");
@@ -305,22 +326,12 @@ public class CourseImpl extends RenamableImpl implements Course {
@Override
public Waypoint getFirstWaypoint() {
- lockForRead();
- try {
- return waypoints.isEmpty() ? null : waypoints.get(0);
- } finally {
- unlockAfterRead();
- }
+ return firstWaypoint;
}
@Override
public Waypoint getLastWaypoint() {
- lockForRead();
- try {
- return waypoints.isEmpty() ? null : waypoints.get(waypoints.size() - 1);
- } finally {
- unlockAfterRead();
- }
+ return lastWaypoint;
}
@Override
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java
index 85e7486320f..5aaf2d321ff 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java
@@ -964,11 +964,14 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
@Override
public Iterable extends RaceColumn> getRaceColumns() {
- final List result = new ArrayList<>();
- for (final Series series : getSeries()) {
- for (final RaceColumnInSeries rc : series.getRaceColumns()) {
- result.add(rc);
- }
+ // special handling of no series and single series case to avoid somewhat expensive mapping iterables
+ final Iterable extends RaceColumn> result;
+ if (series.isEmpty()) {
+ result = Collections.emptySet();
+ } else if (series.size() == 1) {
+ result = series.get(0).getRaceColumns();
+ } else {
+ result = Util.concat(Util.map(getSeries(), series->Util.map(series.getRaceColumns(), rc->(RaceColumn) rc)));
}
return result;
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/TrackedRaces.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/TrackedRaces.java
index 6dfbc055d7a..bd61dfe0bc0 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/TrackedRaces.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/TrackedRaces.java
@@ -10,15 +10,15 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.tracking.TrackedRace;
/**
- * Wraps the trackedRaces map in the {@link AbstractRaceColumn} allowing to serialize an empty map when a master data
- * import is running by using the {@link ThreadLocal} flag {@link #ongoingMasterDataExport}. If the flag is
+ * Wraps the {@link #trackedRaces} map in the {@link AbstractRaceColumn} allowing to serialize an empty map when a
+ * master data import is running by using the {@link ThreadLocal} flag {@link #ongoingMasterDataExport}. If the flag is
* false the map is serialized as is.
*
- *
* @author Frederik Petersen (D054528)
*
*/
@@ -33,26 +33,62 @@ public class TrackedRaces implements Serializable {
private transient ThreadLocal ongoingMasterDataExport;
private Map trackedRaces;
+
+ /**
+ * Keys the {@link TrackedRace}s that appear as values in {@link #trackedRaces} by their {@link Competitor}s for
+ * quick associative access.
+ */
+ private Map racesByCompetitor;
public TrackedRaces(Map trackedRaces) {
this.trackedRaces = trackedRaces;
+ this.racesByCompetitor = new HashMap<>();
+ for (final TrackedRace trackedRace : trackedRaces.values()) {
+ updateRaceByCompetitor(trackedRace);
+ }
this.ongoingMasterDataExport = createOngoingMasterDataExportThreadLocal();
}
+ private void updateRaceByCompetitor(final TrackedRace trackedRace) {
+ for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
+ racesByCompetitor.put(competitor, trackedRace);
+ }
+ }
+
public TrackedRaces() {
this(new HashMap());
}
+ public TrackedRace get(Competitor competitor) {
+ return racesByCompetitor.get(competitor);
+ }
+
public TrackedRace get(Fleet fleet) {
return trackedRaces.get(fleet);
}
public void put(Fleet fleet, TrackedRace trackedRace) {
- trackedRaces.put(fleet, trackedRace);
+ final TrackedRace previousTrackedRace = trackedRaces.put(fleet, trackedRace);
+ if (previousTrackedRace != null) {
+ removeRaceByCompetitor(previousTrackedRace);
+ }
+ if (trackedRace != null) {
+ updateRaceByCompetitor(trackedRace);
+ }
}
- public void remove(Fleet fleet) {
- trackedRaces.remove(fleet);
+ private void removeRaceByCompetitor(final TrackedRace previousTrackedRace) {
+ for (final Competitor previousCompetitor : previousTrackedRace.getRace().getCompetitors()) {
+ racesByCompetitor.remove(previousCompetitor);
+ }
+ }
+
+ public TrackedRace remove(Fleet fleet) {
+ final TrackedRace trackedRace = trackedRaces.remove(fleet);
+ if (trackedRace != null) {
+ removeRaceByCompetitor(trackedRace);
+ }
+ return trackedRace;
}
public Set> entrySet() {
@@ -83,6 +119,7 @@ public class TrackedRaces implements Serializable {
final boolean masterDataImportOngoing = ois.readBoolean();
if (masterDataImportOngoing) {
trackedRaces = new HashMap<>();
+ racesByCompetitor = new HashMap<>();
} else {
ois.defaultReadObject();
}
@@ -96,5 +133,4 @@ public class TrackedRaces implements Serializable {
oos.defaultWriteObject();
}
}
-
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java
index 202e086c509..0aea1986067 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java
@@ -217,7 +217,15 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns {
* {@link ResultDiscardingRule#getDiscardedRaceColumns(Competitor, Leaderboard, Iterable, TimePoint, ScoringScheme)
* getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint)}.
*/
- Entry getEntry(Competitor competitor, RaceColumn race, TimePoint timePoint, Set discardedRaceColumns) throws NoWindException;
+ default Entry getEntry(Competitor competitor, RaceColumn race, TimePoint timePoint, Set discardedRaceColumns) {
+ return getEntry(competitor, race, timePoint, discardedRaceColumns, new LeaderboardDTOCalculationReuseCache(timePoint));
+ }
+
+ /**
+ * Like {@link #getEntry(Competitor, RaceColumn, TimePoint, Set)}, but with the option to specify a re-usable cache
+ */
+ Entry getEntry(Competitor competitor, RaceColumn race, TimePoint timePoint, Set discardedRaceColumns,
+ WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache);
/**
* Computes the competitor's ranks as they were or would have been after each race column (from left to right)
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
index c862fefef85..89f5b462993 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
@@ -527,7 +527,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard {
final TrackedRace trackedRace = raceColumnAndCompetitor.getA().getTrackedRace(raceColumnAndCompetitor.getB());
return trackedRace==null?null:trackedRace.getRankingMetric().getRankingInfo(timePoint, cache);
}) : null;
- Entry entry = AbstractLeaderboardWithCache.this.getEntry(competitor, raceColumn, timePoint, discardedRaceColumns);
+ Entry entry = AbstractLeaderboardWithCache.this.getEntry(competitor, raceColumn, timePoint, discardedRaceColumns, cache);
return getLeaderboardEntryDTO(entry, raceColumn, competitor, timePoint, computeLegDetails,
rankingInfo, waitForLatestAnalyses, legRanksCache, baseDomainFactory,
fillTotalPointsUncorrected, cache);
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java
index d5e6b5fc05c..a1acd63510b 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java
@@ -667,10 +667,10 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW
@Override
public Entry getEntry(final Competitor competitor, final RaceColumn race, final TimePoint timePoint,
- Set discardedRaceColumns) throws NoWindException {
- Callable trackedRankProvider = () -> getTrackedRank(competitor, race, timePoint);
+ Set discardedRaceColumns, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
+ Callable trackedRankProvider = () -> getTrackedRank(competitor, race, timePoint, cache);
final Result correctedResults = getScoreCorrection().getCorrectedScore(trackedRankProvider, competitor, race,
- this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme());
+ this, timePoint, new NumberOfCompetitorsFetcherImpl(), getScoringScheme(), cache);
boolean discarded = isDiscarded(competitor, race, timePoint, discardedRaceColumns);
final Double correctedScore = correctedResults.getCorrectedScore();
final Double correctedScoreScaledByColumnFactor = correctedScore == null ? null
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java
index 50727e0498e..ca15cf6d323 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java
@@ -269,8 +269,8 @@ public class DelegatingRegattaLeaderboardWithCompetitorElimination extends Abstr
@Override
public Entry getEntry(Competitor competitor, RaceColumn race, TimePoint timePoint,
- Set discardedRaceColumns) throws NoWindException {
- return getDelegateLeaderboard().getEntry(competitor, race, timePoint, discardedRaceColumns);
+ Set discardedRaceColumns, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
+ return getDelegateLeaderboard().getEntry(competitor, race, timePoint, discardedRaceColumns, cache);
}
@Override
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java
index 87608a97479..cf62387dbbc 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java
@@ -1,8 +1,5 @@
package com.sap.sailing.domain.leaderboard.impl;
-import java.util.ArrayList;
-import java.util.List;
-
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
@@ -59,13 +56,9 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
@Override
public Iterable getRaceColumns() {
- final List result = new ArrayList();
- for (Series series : getRegatta().getSeries()) {
- for (RaceColumn raceColumn : series.getRaceColumns()) {
- result.add(raceColumn);
- }
- }
- return result;
+ @SuppressWarnings("unchecked") // the iterable is read-only, so no problem to case extends RaceColumn> to RaceColumn
+ Iterable raceColumns = (Iterable) getRegatta().getRaceColumns();
+ return raceColumns;
}
@Override
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java
index ad173bde5db..9d40ff9980e 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java
@@ -12,6 +12,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -19,6 +20,7 @@ import com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetche
import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
+import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
@@ -256,6 +258,16 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
* earlier races.
*/
private boolean isCertainlyBeforeRaceFinish(TimePoint timePoint, RaceColumn raceColumn, Competitor competitor) {
+ return isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor, new LeaderboardDTOCalculationReuseCache(timePoint));
+ }
+
+ /**
+ * Same as {@link #isCertainlyBeforeRaceFinish(TimePoint, RaceColumn, Competitor)}, but with the possibility to
+ * specify a re-use cache, introduced particularly for speeding up the {@link Course#getLastWaypoint()} lookup which
+ * is expected to yield the same result for the entire leaderboard calculation round-trip, however upon each
+ * invocation requires locking.
+ */
+ private boolean isCertainlyBeforeRaceFinish(TimePoint timePoint, RaceColumn raceColumn, Competitor competitor, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
final boolean result;
TrackedRace trackedRace = raceColumn.getTrackedRace(competitor);
final TimePoint endOfRace = trackedRace == null ? null : trackedRace.getFinishedTime() == null ? trackedRace.getEndOfRace() : trackedRace.getFinishedTime();
@@ -467,7 +479,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection {
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
Double correctedNonMaxedScore = correctedScores.get(raceColumn.getKey(competitor));
Double result;
- if (correctedNonMaxedScore == null || isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor)) {
+ if (correctedNonMaxedScore == null || isCertainlyBeforeRaceFinish(timePoint, raceColumn, competitor, cache)) {
result = getUncorrectedScore(competitor, raceColumn, trackedRankProvider, scoringScheme,
numberOfCompetitorsInLeaderboardFetcher, timePoint, cache);
} else {
diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TracTracConnectivityParamsLoadAndStoreTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TracTracConnectivityParamsLoadAndStoreTest.java
index e77d0dc458e..45269d7dd65 100644
--- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TracTracConnectivityParamsLoadAndStoreTest.java
+++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TracTracConnectivityParamsLoadAndStoreTest.java
@@ -34,7 +34,7 @@ public class TracTracConnectivityParamsLoadAndStoreTest extends AbstractConnecti
final boolean correctWindDirectionByMagneticDeclination = true;
final URL paramURL = new URL("http://event.tractrac.com/events/event_20160604_JuniorenSe/clientparams.php?event=event_20160604_JuniorenSe&race=4b9f0190-0b0d-0134-5b24-60a44ce903c3");
final URI storedURI = new URI("http://event.tractrac.com/events/event_20160604_JuniorenSe/datafiles/4b9f0190-0b0d-0134-5b24-60a44ce903c3.mtb");
- final URI courseDesignUpdateURI = new URI("https://skitrac.dk/reverse/update");
+ final URI courseDesignUpdateURI = new URI("https://event2.tractrac.com/reverse/update");
final TimePoint startOfTracking = MillisecondsTimePoint.now();
final TimePoint endOfTracking = startOfTracking.plus(1000);
final long delayToLiveInMillis = 3000;
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRaceFilterForTracTracEvents.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRaceFilterForTracTracEvents.java
index daaf4c6a0dd..84e5db072ab 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRaceFilterForTracTracEvents.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRaceFilterForTracTracEvents.java
@@ -19,7 +19,7 @@ import com.sap.sailing.selenium.test.AbstractSeleniumTest;
*/
public class TestRaceFilterForTracTracEvents extends AbstractSeleniumTest {
private static final String BMW_CUP_JSON_URL =
- "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
@Override
@Before
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
index 41a1ccf7233..f86777576b0 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
@@ -23,7 +23,7 @@ import com.sap.sailing.selenium.test.AbstractSeleniumTest;
* D049941
*/
public class TestStartAndStopTrackingForTracTracEvents extends AbstractSeleniumTest {
- private static final String BMW_CUP_JSON_URL = "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ private static final String BMW_CUP_JSON_URL = "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
private static final String BMW_CUP_EVENT = "BMW Cup";
private static final String IDM_2013_EVENT = "IDM 5O5 2013";
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
index b961d72b4d0..86c9521defc 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
@@ -35,7 +35,7 @@ import com.sap.sailing.selenium.pages.leaderboard.LeaderboardTablePO;
import com.sap.sailing.selenium.test.AbstractSeleniumTest;
public class TestAutoPlay extends AbstractSeleniumTest {
- private static final String BMW_CUP_JSON_URL = "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ private static final String BMW_CUP_JSON_URL = "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
private static final String BMW_CUP_EVENT = "BMW Cup";
private static final String BMW_CUP_BOAT_CLASS = "J80";
private static final String BMW_CUP_REGATTA = "BMW Cup (J80)"; //$NON-NLS-1$
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
index 29b1cc7a346..7eb75a209af 100755
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
@@ -34,7 +34,7 @@ import com.sap.sailing.selenium.test.AbstractSeleniumTest;
public class TestSwitchingOffStartOfRaceInference extends AbstractSeleniumTest {
private static final String BMW_CUP_JSON_URL =
- "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
private static final String REGATTA = "The BMW Cup"; //$NON-NLS-1$
private static final String LEADERBOARD = "The BMW Cup (J80)"; //$NON-NLS-1$
private static final String EVENT = "BMW Cup"; //$NON-NLS-1$
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboardedit/TestLeaderboardEditing.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboardedit/TestLeaderboardEditing.java
index 80de43e4ac3..49ceaa5c64e 100755
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboardedit/TestLeaderboardEditing.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboardedit/TestLeaderboardEditing.java
@@ -24,7 +24,7 @@ import com.sap.sse.common.Util;
public class TestLeaderboardEditing extends AbstractSeleniumTest {
private static final String LEADERBOARD = "BMW Cup - J80";
- private static final String BMW_CUP_JSON_URL = "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ private static final String BMW_CUP_JSON_URL = "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
private static final String BMW_CUP_RACE_8 = "BMW Cup Race 8";
private static final String BMW_CUP_REGATTA = "BMW Cup";
private static final String BMW_CUP_BOAT_CLASS = "J/80";
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
index cb282026a85..4cfc17c55db 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
@@ -42,7 +42,7 @@ import com.sap.sailing.selenium.pages.timeslider.TimeSliderPO;
import com.sap.sailing.selenium.test.AbstractSeleniumTest;
public class SettingsTest extends AbstractSeleniumTest {
- private static final String BMW_CUP_JSON_URL = "http://kml.skitrac.traclive.dk/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
+ private static final String BMW_CUP_JSON_URL = "http://event2.tractrac.com/events/event_20120803_BMWCup/jsonservice.php"; //$NON-NLS-1$
private static final String BMW_CUP_EVENT = "BMW Cup";
private static final String AUDI_CUP_EVENT = "Audi Business Cup";
private static final String BMW_CUP_BOAT_CLASS = "J80";
diff --git a/java/com.sap.sse.common.test/src/com/sap/sse/common/test/IterableConcatTest.java b/java/com.sap.sse.common.test/src/com/sap/sse/common/test/IterableConcatTest.java
new file mode 100644
index 00000000000..41747085040
--- /dev/null
+++ b/java/com.sap.sse.common.test/src/com/sap/sse/common/test/IterableConcatTest.java
@@ -0,0 +1,91 @@
+package com.sap.sse.common.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.sap.sse.common.Util;
+
+public class IterableConcatTest {
+ @Test
+ public void emptyTest() {
+ assertTrue(Util.isEmpty(Util.concat(Collections.emptySet())));
+ }
+
+ @Test
+ public void testWithSingleNullIterable() {
+ assertTrue(Util.isEmpty(Util.concat(Collections.singleton(null))));
+ }
+
+ @Test
+ public void testWithTwoNullIterables() {
+ assertTrue(Util.isEmpty(Util.concat(Arrays.asList(null, null))));
+ }
+
+ @Test
+ public void testWithSingleIterable() {
+ final Iterable list = Arrays.asList(1, 2, 3, 4);
+ assertTrue(Util.equals(list, Util.concat(Collections.singleton(list))));
+ }
+
+ @Test
+ public void testWithSingleIterableSurroundedByTwoNullIterables() {
+ final Iterable list = Arrays.asList(1, 2, 3, 4);
+ assertTrue(Util.equals(list, Util.concat(Arrays.asList(null, list, null))));
+ }
+
+ @Test
+ public void testWithTwoIterables() {
+ final Iterable list1 = Arrays.asList(1, 2, 3, 4);
+ final Iterable list2 = Arrays.asList(9, 8, 7, 6);
+ final List expectedResult = new ArrayList<>();
+ Util.addAll(list1, expectedResult);
+ Util.addAll(list2, expectedResult);
+ assertTrue(Util.equals(expectedResult, Util.concat(Arrays.asList(list1, list2))));
+ }
+
+ @Test
+ public void testWithTwoIterablesWithNullBetween() {
+ final Iterable list1 = Arrays.asList(1, 2, 3, 4);
+ final Iterable list2 = Arrays.asList(9, 8, 7, 6);
+ final List expectedResult = new ArrayList<>();
+ Util.addAll(list1, expectedResult);
+ Util.addAll(list2, expectedResult);
+ assertTrue(Util.equals(expectedResult, Util.concat(Arrays.asList(list1, null, list2))));
+ }
+
+ @Test
+ public void testWithTwoIterablesWithEmptyIterableBetween() {
+ final Iterable list1 = Arrays.asList(1, 2, 3, 4);
+ final Iterable list2 = Arrays.asList(9, 8, 7, 6);
+ final List expectedResult = new ArrayList<>();
+ Util.addAll(list1, expectedResult);
+ Util.addAll(list2, expectedResult);
+ assertTrue(Util.equals(expectedResult, Util.concat(Arrays.asList(list1, new ArrayList<>(), list2))));
+ }
+
+ @Test
+ public void testWithTwiceSameIterable() {
+ final Iterable list1 = Arrays.asList(1, 2, 3, 4);
+ final List expectedResult = new ArrayList<>();
+ Util.addAll(list1, expectedResult);
+ Util.addAll(list1, expectedResult);
+ assertTrue(Util.equals(expectedResult, Util.concat(Arrays.asList(list1, list1))));
+ }
+
+ @Test
+ public void testIteratingTwice() {
+ final Iterable list1 = Arrays.asList(1, 2, 3, 4);
+ final List expectedResult = new ArrayList<>();
+ Util.addAll(list1, expectedResult);
+ Util.addAll(list1, expectedResult);
+ final Iterable concat = Util.concat(Arrays.asList(list1, list1));
+ assertTrue(Util.equals(expectedResult, concat));
+ assertTrue(Util.equals(expectedResult, concat));
+ }
+}
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
index 5c17619ecce..ba4bcea272c 100755
--- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java
@@ -370,17 +370,11 @@ public class Util {
return result;
}
- public static interface Mapper { T map(S s); }
- public static Iterable map(final Iterable iterable, final Mapper mapper) {
- return new MappingIterable<>(iterable, new MappingIterator.MapFunction() {
- @Override
- public T map(S s) {
- return mapper.map(s);
- }
- });
+ public static Iterable map(final Iterable iterable, final MappingIterator.MapFunction mapper) {
+ return new MappingIterable<>(iterable, mapper);
}
- public static ArrayList mapToArrayList(final Iterable iterable, final Mapper mapper) {
+ public static ArrayList mapToArrayList(final Iterable iterable, final MappingIterator.MapFunction mapper) {
final ArrayList result = new ArrayList<>();
addAll(map(iterable, mapper), result);
return result;
@@ -390,6 +384,53 @@ public class Util {
return ()->StreamSupport.stream(iterable.spliterator(), /* parallel */ false).filter(predicate).iterator();
}
+ /**
+ * Concatenates the iterables and returns a single iterable that enumerates the elements in the
+ * iterables in the sequence of the iterables. {@code null} iterables are ignored; {@code null}
+ * values enumerated by one of the iterables are propagated into the resulting iterable.
+ */
+ public static Iterable concat(final Iterable> iterables) {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ final Iterator> iterableIter = iterables.iterator();
+ Iterable iterable = null;
+ Iterator iter; // loops over the "iterable"; when iterable is not null, iter is not null
+ boolean nextValid;
+ T next;
+
+ @Override
+ public boolean hasNext() {
+ return nextValid;
+ }
+
+ @Override
+ public T next() {
+ final T result = next;
+ advance();
+ return result;
+ }
+
+ private Iterator advance() {
+ // first ensure we have a valid iterable with a next element if possible:
+ while ((iterable == null || !iter.hasNext()) && iterableIter.hasNext()) {
+ iterable = iterableIter.next();
+ if (iterable != null) {
+ iter = iterable.iterator();
+ }
+ }
+ nextValid = iter != null && iter.hasNext();
+ if (nextValid) {
+ next = iter.next();
+ }
+ return this;
+ }
+ }.advance();
+ }
+ };
+ }
+
/**
* A null-safe check whether t is contained in ts. For ts==null the method
* immediately returns false.
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/util/MappingIterator.java b/java/com.sap.sse.common/src/com/sap/sse/common/util/MappingIterator.java
index 38bacb75e11..8b5efff0f5b 100755
--- a/java/com.sap.sse.common/src/com/sap/sse/common/util/MappingIterator.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/util/MappingIterator.java
@@ -6,6 +6,7 @@ public class MappingIterator implements Iterator {
private final Iterator iterator;
private final MapFunction mapper;
+ @FunctionalInterface
public static interface MapFunction {
T map(S s);
}
diff --git a/wiki/bug2822-review.md b/wiki/bug2822-review.md
index 1e11304746d..491987bf8a6 100644
--- a/wiki/bug2822-review.md
+++ b/wiki/bug2822-review.md
@@ -84,7 +84,7 @@ Check:
Checkpoints are the same as in 1.1.
ESS 2016 – Hamburg
-http://skitrac.traclive.dk/events/event_20160727_ESSHamburg/jsonservice.php
+http://event2.tractrac.com/events/event_20160727_ESSHamburg/jsonservice.php
### 3.3. Tracking of existing sailing event without changing boats
diff --git a/wiki/howto/downloading-and-archiving-tractrac-events.md b/wiki/howto/downloading-and-archiving-tractrac-events.md
new file mode 100644
index 00000000000..d51079625a4
--- /dev/null
+++ b/wiki/howto/downloading-and-archiving-tractrac-events.md
@@ -0,0 +1,77 @@
+# Downloading and Archiving TracTrac Events
+
+Usually we obtain the TracTrac data straight from the TracTrac site using their API ("TracAPI"). The API is initialized using a URL that points to a specific event, such as `https://event.tractrac.com/events/event_20210826_FinnishSai/jsonservice.php` which points to an event of the Finnish sailing league of 2021.
+
+Each time our archive server re-starts it fetches the content from these sites. This has two disadvantages:
+
+- The TracTrac site keeps seeing massive traffic each time we launch an archive server
+- We depend on TracTrac's availability when starting / loading our archive
+
+The benefit in loading straight from the TracTrac side is certainly that any improvements in quality, such as filtering outliers or updating mark passings, will reach us upon the next archive server re-start. Likewise, should TracTrac ever change anything about the format of the `params_url` files or the binary `.mtb` archives holding a race worth of data and publish a corresponding new TracAPI release, working off an archived copy of the data may break.
+
+Yet, we would like to keep a backup copy of the data around and hence need some process for how to create such a backup copy. See also [bug 5801](https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=5801).
+
+## Creating a Backup Copy of a Single Event
+
+TracTrac events are usually identified by the event's DB name, such as `event_20220626_KielerWoch` for the 2022 Kieler Woche event. Together with the TracTrac server hosting the event, this makes for the URL pointing to the entry point for the event: `https://event.tractrac.com/events/event_20220626_KielerWoch/jsonservice.php`.
+
+In our Git repository's `configuration/` folder we have a script `downloadTracTracEvent` that can be called like this, assuming the shell is located in the Git workspace's root folder:
+
+```
+ configuration/downloadTracTracEvent {TracTracURL} {TargetDirectory}
+```
+
+For example:
+
+```
+ configuration/downloadTracTracEvent https://event.tractrac.com/events/event_20220626_KielerWoch/jsonservice.php /home/trac/static/TracTracTracks
+```
+
+This will produce a folder `/home/trac/static/TracTracTracks/event_20220626_KielerWoch` that holds a file `event_20220626_KielerWoch.json`, the URL to which then serves as an entry point for loading the races of that event.
+
+The `sapsailing.com:/home/trac/static` folder (a link to `sapsailing.com:/var/www/static`) is exposed as `https://static.sapsailing.com`. Hence, the example above leads to a JSON URL that can be used with the SAP Sailing Analytics as follows: `https://static.sapsailing.com/TracTracTracks/event_20220626_KielerWoch/event_20220626_KielerWoch.json`.
+
+## Archiving Several Events at Once
+
+Assume you have a file with one TracTrac event JSON URL per line, called `tractrac-json-urls`. You can then download a copy of the data of all these events as follows:
+
+```
+ for i in `cat tractrac-json-urls`; do
+ configuration/downloadTracTracEvent $i /home/trac/static/TracTracTracks
+ done
+```
+
+This will obtain copies of all events listed in the `tractrac-json-urls` file. Such a file is provided in Git at `configuration/tractrac-json-urls` and may be updated with new events every once in a while.
+
+To obtain a list of such JSON URLs from a SAP Sailing Analytics server's MongoDB, the following command can be used:
+
+```
+ mongo --quiet "{mongodb-url}" --eval 'db.TRACTRAC_CONFIGURATIONS.find({}, {TT_CONFIG_JSON_URL : 1}).toArray()' | grep -v ObjectId | jq -r '.[].TT_CONFIG_JSON_URL' | sort -u
+```
+
+For example, within the production landscape of sapsailing.com, you could try this to obtain all TracTrac URLs of all events contained in the ARCHIVE server:
+
+```
+ mongo --quiet "mongodb://dbserver.internal.sapsailing.com:10201/winddb?replicaSet=archive" --eval 'db.TRACTRAC_CONFIGURATIONS.find({}, {TT_CONFIG_JSON_URL : 1}).toArray()' | grep -v ObjectId | jq -r '.[].TT_CONFIG_JSON_URL' | sort -u
+```
+
+## Automation
+
+For `wiki@sapsailing.com` the process of updating the `configuration/tractrac-json-urls` file from the ARCHIVE server is automated by means of two cron jobs as specified in `wiki@sapsailing.com:crontab`:
+
+```
+10 12 * * * /home/wiki/gitwiki/configuration/update-tractrac-urls-to-archive.sh >/home/wiki/update-tractrac-urls-to-archive.out 2>/home/wiki/update-tractrac-urls-to-archive.err
+15 12 * * * /home/wiki/gitwiki/configuration/downloadNewArchivedTracTracEvents.sh /home/trac/static/TracTracTracks >/home/wiki/downloadNewArchivedTracTracEvents.out 2>/home/wiki/downloadNewArchivedTracTracEvents.err
+```
+
+Every day the first job calls the `configuration/update-tractrac-urls-to-archive.sh` script which fetches those URLs from the `mongodb://dbserver.internal.sapsailing.com:10201/winddb?replicaSet=archive` database and if changed commits it to the Git repository. The second job calls `configuration/downloadNewArchivedTracTracEvents.sh` which fetches only those events that do not have a representation yet in `/home/trac/static/TracTracTracks`.
+
+With this, `/home/trac/static/TracTracTracks` will always have a representation of all archived events as a backup copy from which we may be able to load the data if the TracTrac content becomes unavailable for whatever reason.
+
+## Background, Details
+
+The `downloadTracTracEvent` script creates the sub-folder in the target folder specified, based on the event's database name, such as `event_20220626_KielerWoch` in the example above, and within that the sub-folder listed by the `stored-uri` property in the `params_url` properties, typically `datafiles/`. Based on the contents of the JSON file to which URL provided as the first argument to the `downloadTracTracEvent` script points, the `params_url` file (usually in `.txt` format) as well as the file referenced by the `stored-uri` property inside the `params_url` file are downloaded.
+
+The JSON file is stored in the event-specific sub-folder of the target folder, named after the event database, e.g., `event_20220626_KielerWoch.json`. It is patched such that the `params_url` properties all use relative "URLs" (just as the base filename of the `.txt` file) which resolve to the race's `.txt` file when interpreted in the context of the URL pointing to the event's JSON file.
+
+With this, the JSON file can be used to load the races from the backup copies.
\ No newline at end of file